AX: ARIA "region" role which lacks an accessible name should not be treated as a...
[WebKit-https.git] / Source / WebCore / accessibility / mac / WebAccessibilityObjectWrapperMac.mm
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  */
28
29 #import "config.h"
30 #import "WebAccessibilityObjectWrapperMac.h"
31
32 #if HAVE(ACCESSIBILITY)
33
34 #import "AXObjectCache.h"
35 #import "AccessibilityARIAGridRow.h"
36 #import "AccessibilityLabel.h"
37 #import "AccessibilityList.h"
38 #import "AccessibilityListBox.h"
39 #import "AccessibilityProgressIndicator.h"
40 #import "AccessibilityRenderObject.h"
41 #import "AccessibilityScrollView.h"
42 #import "AccessibilitySpinButton.h"
43 #import "AccessibilityTable.h"
44 #import "AccessibilityTableCell.h"
45 #import "AccessibilityTableColumn.h"
46 #import "AccessibilityTableRow.h"
47 #import "Chrome.h"
48 #import "ChromeClient.h"
49 #import "ColorMac.h"
50 #import "ContextMenuController.h"
51 #import "Editing.h"
52 #import "Editor.h"
53 #import "Font.h"
54 #import "FontCascade.h"
55 #import "FrameLoaderClient.h"
56 #import "FrameSelection.h"
57 #import "HTMLAnchorElement.h"
58 #import "HTMLAreaElement.h"
59 #import "HTMLFrameOwnerElement.h"
60 #import "HTMLImageElement.h"
61 #import "HTMLInputElement.h"
62 #import "HTMLNames.h"
63 #import "LocalizedStrings.h"
64 #import "MainFrame.h"
65 #import "Page.h"
66 #import "PluginDocument.h"
67 #import "PluginViewBase.h"
68 #import "RenderTextControl.h"
69 #import "RenderView.h"
70 #import "RenderWidget.h"
71 #import "ScrollView.h"
72 #import "TextCheckerClient.h"
73 #import "TextCheckingHelper.h"
74 #import "TextDecorationPainter.h"
75 #import "TextIterator.h"
76 #import "VisibleUnits.h"
77 #import "WebCoreFrameView.h"
78 #import "WebCoreObjCExtras.h"
79 #import "WebCoreSystemInterface.h"
80 #import <wtf/ObjcRuntimeExtras.h>
81 #if ENABLE(TREE_DEBUGGING) || ENABLE(METER_ELEMENT)
82 #import <wtf/text/StringBuilder.h>
83 #endif
84
85 using namespace WebCore;
86 using namespace HTMLNames;
87
88 // Cell Tables
89 #ifndef NSAccessibilitySelectedCellsAttribute
90 #define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
91 #endif
92
93 #ifndef NSAccessibilityVisibleCellsAttribute
94 #define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
95 #endif
96
97 #ifndef NSAccessibilityRowIndexRangeAttribute
98 #define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
99 #endif
100
101 #ifndef NSAccessibilityColumnIndexRangeAttribute
102 #define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
103 #endif
104
105 #ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
106 #define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
107 #endif
108
109 #ifndef NSAccessibilityCellRole
110 #define NSAccessibilityCellRole @"AXCell"
111 #endif
112
113 // Lists
114 #ifndef NSAccessibilityContentListSubrole
115 #define NSAccessibilityContentListSubrole @"AXContentList"
116 #endif
117
118 #ifndef NSAccessibilityDefinitionListSubrole
119 #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
120 #endif
121
122 #ifndef NSAccessibilityDescriptionListSubrole
123 #define NSAccessibilityDescriptionListSubrole @"AXDescriptionList"
124 #endif
125
126 #ifndef NSAccessibilityContentSeparatorSubrole
127 #define NSAccessibilityContentSeparatorSubrole @"AXContentSeparator"
128 #endif
129
130 #ifndef NSAccessibilityRubyBaseSubRole
131 #define NSAccessibilityRubyBaseSubrole @"AXRubyBase"
132 #endif
133
134 #ifndef NSAccessibilityRubyBlockSubrole
135 #define NSAccessibilityRubyBlockSubrole @"AXRubyBlock"
136 #endif
137
138 #ifndef NSAccessibilityRubyInlineSubrole
139 #define NSAccessibilityRubyInlineSubrole @"AXRubyInline"
140 #endif
141
142 #ifndef NSAccessibilityRubyRunSubrole
143 #define NSAccessibilityRubyRunSubrole @"AXRubyRun"
144 #endif
145
146 #ifndef NSAccessibilityRubyTextSubrole
147 #define NSAccessibilityRubyTextSubrole @"AXRubyText"
148 #endif
149
150 // Miscellaneous
151 #ifndef NSAccessibilityBlockQuoteLevelAttribute
152 #define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
153 #endif
154
155 #ifndef NSAccessibilityAccessKeyAttribute
156 #define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
157 #endif
158
159 #ifndef NSAccessibilityValueAutofilledAttribute
160 #define NSAccessibilityValueAutofilledAttribute @"AXValueAutofilled"
161 #endif
162
163 #ifndef NSAccessibilityValueAutofillAvailableAttribute
164 #define NSAccessibilityValueAutofillAvailableAttribute @"AXValueAutofillAvailable"
165 #endif
166
167 #ifndef NSAccessibilityValueAutofillTypeAttribute
168 #define NSAccessibilityValueAutofillTypeAttribute @"AXValueAutofillType"
169 #endif
170
171 #ifndef NSAccessibilityLanguageAttribute
172 #define NSAccessibilityLanguageAttribute @"AXLanguage"
173 #endif
174
175 #ifndef NSAccessibilityRequiredAttribute
176 #define NSAccessibilityRequiredAttribute @"AXRequired"
177 #endif
178
179 #ifndef NSAccessibilityInvalidAttribute
180 #define NSAccessibilityInvalidAttribute @"AXInvalid"
181 #endif
182
183 #ifndef NSAccessibilityOwnsAttribute
184 #define NSAccessibilityOwnsAttribute @"AXOwns"
185 #endif
186
187 #ifndef NSAccessibilityGrabbedAttribute
188 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
189 #endif
190
191 #ifndef NSAccessibilityDropEffectsAttribute
192 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
193 #endif
194
195 #ifndef NSAccessibilityARIALiveAttribute
196 #define NSAccessibilityARIALiveAttribute @"AXARIALive"
197 #endif
198
199 #ifndef NSAccessibilityARIAAtomicAttribute
200 #define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
201 #endif
202
203 #ifndef NSAccessibilityARIARelevantAttribute
204 #define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
205 #endif
206
207 #ifndef NSAccessibilityElementBusyAttribute
208 #define NSAccessibilityElementBusyAttribute @"AXElementBusy"
209 #endif
210
211 #ifndef NSAccessibilityARIAPosInSetAttribute
212 #define NSAccessibilityARIAPosInSetAttribute @"AXARIAPosInSet"
213 #endif
214
215 #ifndef NSAccessibilityARIASetSizeAttribute
216 #define NSAccessibilityARIASetSizeAttribute @"AXARIASetSize"
217 #endif
218
219 #ifndef NSAccessibilityLoadingProgressAttribute
220 #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
221 #endif
222
223 #ifndef NSAccessibilityHasPopupAttribute
224 #define NSAccessibilityHasPopupAttribute @"AXHasPopup"
225 #endif
226
227 #ifndef NSAccessibilityPlaceholderValueAttribute
228 #define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
229 #endif
230
231 #define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid"
232 #define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
233 #define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
234
235 #ifndef NSAccessibilityScrollToVisibleAction
236 #define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
237 #endif
238
239 #ifndef NSAccessibilityPathAttribute
240 #define NSAccessibilityPathAttribute @"AXPath"
241 #endif
242
243 #ifndef NSAccessibilityExpandedTextValueAttribute
244 #define NSAccessibilityExpandedTextValueAttribute @"AXExpandedTextValue"
245 #endif
246
247 #ifndef NSAccessibilityIsMultiSelectableAttribute
248 #define NSAccessibilityIsMultiSelectableAttribute @"AXIsMultiSelectable"
249 #endif
250
251 #ifndef NSAccessibilityDocumentURIAttribute
252 #define NSAccessibilityDocumentURIAttribute @"AXDocumentURI"
253 #endif
254
255 #ifndef NSAccessibilityDocumentEncodingAttribute
256 #define NSAccessibilityDocumentEncodingAttribute @"AXDocumentEncoding"
257 #endif
258
259 #ifndef NSAccessibilityAriaControlsAttribute
260 #define NSAccessibilityAriaControlsAttribute @"AXARIAControls"
261 #endif
262
263 #define NSAccessibilityDOMIdentifierAttribute @"AXDOMIdentifier"
264 #define NSAccessibilityDOMClassListAttribute @"AXDOMClassList"
265
266 #ifndef NSAccessibilityARIACurrentAttribute
267 #define NSAccessibilityARIACurrentAttribute @"AXARIACurrent"
268 #endif
269
270 // Table/grid attributes
271 #ifndef NSAccessibilityARIAColumnIndexAttribute
272 #define NSAccessibilityARIAColumnIndexAttribute @"AXARIAColumnIndex"
273 #endif
274
275 #ifndef NSAccessibilityARIARowIndexAttribute
276 #define NSAccessibilityARIARowIndexAttribute @"AXARIARowIndex"
277 #endif
278
279 #ifndef NSAccessibilityARIAColumnCountAttribute
280 #define NSAccessibilityARIAColumnCountAttribute @"AXARIAColumnCount"
281 #endif
282
283 #ifndef NSAccessibilityARIARowCountAttribute
284 #define NSAccessibilityARIARowCountAttribute @"AXARIARowCount"
285 #endif
286
287
288 #ifndef NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
289 #define NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute @"AXUIElementCountForSearchPredicate"
290 #endif
291
292 #ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute
293 #define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate"
294 #endif
295
296 // Text markers
297 #ifndef NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute
298 #define NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute @"AXEndTextMarkerForBounds"
299 #endif
300
301 #ifndef NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute
302 #define NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute @"AXStartTextMarkerForBounds"
303 #endif
304
305 #ifndef NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute
306 #define NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute @"AXLineTextMarkerRangeForTextMarker"
307 #endif
308
309 // Text selection
310 #ifndef NSAccessibilitySelectTextActivity
311 #define NSAccessibilitySelectTextActivity @"AXSelectTextActivity"
312 #endif
313
314 #ifndef NSAccessibilitySelectTextActivityFindAndReplace
315 #define NSAccessibilitySelectTextActivityFindAndReplace @"AXSelectTextActivityFindAndReplace"
316 #endif
317
318 #ifndef NSAccessibilitySelectTextActivityFindAndSelect
319 #define NSAccessibilitySelectTextActivityFindAndSelect @"AXSelectTextActivityFindAndSelect"
320 #endif
321
322 #ifndef kAXSelectTextActivityFindAndCapitalize
323 #define kAXSelectTextActivityFindAndCapitalize @"AXSelectTextActivityFindAndCapitalize"
324 #endif
325
326 #ifndef kAXSelectTextActivityFindAndLowercase
327 #define kAXSelectTextActivityFindAndLowercase @"AXSelectTextActivityFindAndLowercase"
328 #endif
329
330 #ifndef kAXSelectTextActivityFindAndUppercase
331 #define kAXSelectTextActivityFindAndUppercase @"AXSelectTextActivityFindAndUppercase"
332 #endif
333
334 #ifndef NSAccessibilitySelectTextAmbiguityResolution
335 #define NSAccessibilitySelectTextAmbiguityResolution @"AXSelectTextAmbiguityResolution"
336 #endif
337
338 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection
339 #define NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection @"AXSelectTextAmbiguityResolutionClosestAfterSelection"
340 #endif
341
342 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection
343 #define NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection @"AXSelectTextAmbiguityResolutionClosestBeforeSelection"
344 #endif
345
346 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection
347 #define NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection @"AXSelectTextAmbiguityResolutionClosestToSelection"
348 #endif
349
350 #ifndef NSAccessibilitySelectTextReplacementString
351 #define NSAccessibilitySelectTextReplacementString @"AXSelectTextReplacementString"
352 #endif
353
354 #ifndef NSAccessibilitySelectTextSearchStrings
355 #define NSAccessibilitySelectTextSearchStrings @"AXSelectTextSearchStrings"
356 #endif
357
358 #ifndef NSAccessibilitySelectTextWithCriteriaParameterizedAttribute
359 #define NSAccessibilitySelectTextWithCriteriaParameterizedAttribute @"AXSelectTextWithCriteria"
360 #endif
361
362 // Math attributes
363 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
364 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
365 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
366 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
367 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
368 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
369 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
370 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
371 #define NSAccessibilityMathOverAttribute @"AXMathOver"
372 #define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
373 #define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
374 #define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
375 #define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
376 #define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
377
378 #ifndef NSAccessibilityPreventKeyboardDOMEventDispatchAttribute
379 #define NSAccessibilityPreventKeyboardDOMEventDispatchAttribute @"AXPreventKeyboardDOMEventDispatch"
380 #endif
381
382 #ifndef NSAccessibilityCaretBrowsingEnabledAttribute
383 #define NSAccessibilityCaretBrowsingEnabledAttribute @"AXCaretBrowsingEnabled"
384 #endif
385
386 #ifndef NSAccessibilitFocusableAncestorAttribute
387 #define NSAccessibilityFocusableAncestorAttribute @"AXFocusableAncestor"
388 #endif
389
390 #ifndef NSAccessibilityEditableAncestorAttribute
391 #define NSAccessibilityEditableAncestorAttribute @"AXEditableAncestor"
392 #endif
393
394 #ifndef NSAccessibilityHighestEditableAncestorAttribute
395 #define NSAccessibilityHighestEditableAncestorAttribute @"AXHighestEditableAncestor"
396 #endif
397
398 @implementation WebAccessibilityObjectWrapper
399
400 - (void)unregisterUniqueIdForUIElement
401 {
402     wkUnregisterUniqueIdForElement(self);
403 }
404
405 - (void)detach
406 {
407     // Send unregisterUniqueIdForUIElement unconditionally because if it is
408     // ever accidentally not done (via other bugs in our AX implementation) you
409     // end up with a crash like <rdar://problem/4273149>.  It is safe and not
410     // expensive to send even if the object is not registered.
411     [self unregisterUniqueIdForUIElement];
412     [super detach];
413 }
414
415 - (id)attachmentView
416 {
417     ASSERT(m_object->isAttachment());
418     Widget* widget = m_object->widgetForAttachmentView();
419     if (!widget)
420         return nil;
421     return NSAccessibilityUnignoredDescendant(widget->platformWidget());
422 }
423
424 #pragma mark SystemInterface wrappers
425
426 static inline BOOL AXObjectIsTextMarker(id obj)
427 {
428     return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerTypeID();
429 }
430
431 static inline BOOL AXObjectIsTextMarkerRange(id obj)
432 {
433     return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerRangeTypeID();
434 }
435
436 static id AXTextMarkerRange(id startMarker, id endMarker)
437 {
438     ASSERT(startMarker != nil);
439     ASSERT(endMarker != nil);
440     ASSERT(CFGetTypeID(startMarker) == wkGetAXTextMarkerTypeID());
441     ASSERT(CFGetTypeID(endMarker) == wkGetAXTextMarkerTypeID());
442     return CFBridgingRelease(wkCreateAXTextMarkerRange((CFTypeRef)startMarker, (CFTypeRef)endMarker));
443 }
444
445 static id AXTextMarkerRangeStart(id range)
446 {
447     ASSERT(range != nil);
448     ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
449     return CFBridgingRelease(wkCopyAXTextMarkerRangeStart(range));
450 }
451
452 static id AXTextMarkerRangeEnd(id range)
453 {
454     ASSERT(range != nil);
455     ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
456     return CFBridgingRelease(wkCopyAXTextMarkerRangeEnd(range));
457 }
458
459 #pragma mark Other helpers
460
461 - (IntRect)screenToContents:(const IntRect&)rect
462 {
463     Document* document = m_object->document();
464     if (!document)
465         return IntRect();
466     
467     FrameView* frameView = document->view();
468     if (!frameView)
469         return IntRect();
470     
471     IntPoint startPoint = frameView->screenToContents(rect.minXMaxYCorner());
472     IntPoint endPoint = frameView->screenToContents(rect.maxXMinYCorner());
473     return IntRect(startPoint.x(), startPoint.y(), endPoint.x() - startPoint.x(), endPoint.y() - startPoint.y());
474 }
475
476 #pragma mark Select text helpers
477
478 static AccessibilitySelectTextCriteria accessibilitySelectTextCriteriaForCriteriaParameterizedAttribute(const NSDictionary *parameterizedAttribute)
479 {
480     NSString *activityParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextActivity];
481     NSString *ambiguityResolutionParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextAmbiguityResolution];
482     NSString *replacementStringParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextReplacementString];
483     NSArray *searchStringsParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextSearchStrings];
484     
485     AccessibilitySelectTextActivity activity = FindAndSelectActivity;
486     if ([activityParameter isKindOfClass:[NSString class]]) {
487         if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndReplace])
488             activity = FindAndReplaceActivity;
489         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndCapitalize])
490             activity = FindAndCapitalize;
491         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndLowercase])
492             activity = FindAndLowercase;
493         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndUppercase])
494             activity = FindAndUppercase;
495     }
496     
497     AccessibilitySelectTextAmbiguityResolution ambiguityResolution = ClosestToSelectionAmbiguityResolution;
498     if ([ambiguityResolutionParameter isKindOfClass:[NSString class]]) {
499         if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection])
500             ambiguityResolution = ClosestAfterSelectionAmbiguityResolution;
501         else if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection])
502             ambiguityResolution = ClosestBeforeSelectionAmbiguityResolution;
503     }
504     
505     String replacementString;
506     if ([replacementStringParameter isKindOfClass:[NSString class]])
507         replacementString = replacementStringParameter;
508     
509     AccessibilitySelectTextCriteria criteria(activity, ambiguityResolution, replacementString);
510     
511     if ([searchStringsParameter isKindOfClass:[NSArray class]]) {
512         size_t searchStringsCount = static_cast<size_t>([searchStringsParameter count]);
513         criteria.searchStrings.reserveInitialCapacity(searchStringsCount);
514         for (NSString *searchString in searchStringsParameter) {
515             if ([searchString isKindOfClass:[NSString class]])
516                 criteria.searchStrings.uncheckedAppend(searchString);
517         }
518     }
519     
520     return criteria;
521 }
522
523 #pragma mark Text Marker helpers
524
525 static bool isTextMarkerIgnored(id textMarker)
526 {
527     if (!textMarker)
528         return false;
529     
530     TextMarkerData textMarkerData;
531     if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
532         return false;
533     
534     return textMarkerData.ignored;
535 }
536
537 - (AccessibilityObject*)accessibilityObjectForTextMarker:(id)textMarker
538 {
539     return accessibilityObjectForTextMarker(m_object->axObjectCache(), textMarker);
540 }
541
542 static AccessibilityObject* accessibilityObjectForTextMarker(AXObjectCache* cache, id textMarker)
543 {
544     if (!textMarker || !cache || isTextMarkerIgnored(textMarker))
545         return nullptr;
546     
547     TextMarkerData textMarkerData;
548     if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
549         return nullptr;
550     return cache->accessibilityObjectForTextMarkerData(textMarkerData);
551 }
552
553 - (id)textMarkerRangeFromRange:(const RefPtr<Range>)range
554 {
555     return textMarkerRangeFromRange(m_object->axObjectCache(), range);
556 }
557
558 static id textMarkerRangeFromRange(AXObjectCache* cache, const RefPtr<Range> range)
559 {
560     id startTextMarker = startOrEndTextmarkerForRange(cache, range, true);
561     id endTextMarker = startOrEndTextmarkerForRange(cache, range, false);
562     return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
563 }
564
565 - (id)startOrEndTextMarkerForRange:(const RefPtr<Range>)range isStart:(BOOL)isStart
566 {
567     return startOrEndTextmarkerForRange(m_object->axObjectCache(), range, isStart);
568 }
569
570 static id startOrEndTextmarkerForRange(AXObjectCache* cache, RefPtr<Range> range, bool isStart)
571 {
572     if (!cache)
573         return nil;
574     
575     TextMarkerData textMarkerData;
576     cache->startOrEndTextMarkerDataForRange(textMarkerData, range, isStart);
577     if (!textMarkerData.axID)
578         return nil;
579     
580     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
581 }
582
583 static id nextTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
584 {
585     if (!cache)
586         return nil;
587     
588     TextMarkerData textMarkerData;
589     cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
590     if (!textMarkerData.axID)
591         return nil;
592     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
593 }
594
595 static id previousTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
596 {
597     if (!cache)
598         return nil;
599     
600     TextMarkerData textMarkerData;
601     cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
602     if (!textMarkerData.axID)
603         return nil;
604     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
605 }
606
607 - (id)nextTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
608 {
609     return nextTextMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
610 }
611
612 - (id)previousTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
613 {
614     return previousTextMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
615 }
616
617 - (id)textMarkerForCharacterOffset:(CharacterOffset&)characterOffset
618 {
619     return textMarkerForCharacterOffset(m_object->axObjectCache(), characterOffset);
620 }
621
622 static id textMarkerForCharacterOffset(AXObjectCache* cache, const CharacterOffset& characterOffset)
623 {
624     if (!cache)
625         return nil;
626     
627     TextMarkerData textMarkerData;
628     cache->textMarkerDataForCharacterOffset(textMarkerData, characterOffset);
629     if (!textMarkerData.axID && !textMarkerData.ignored)
630         return nil;
631     
632     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
633 }
634
635 - (RefPtr<Range>)rangeForTextMarkerRange:(id)textMarkerRange
636 {
637     if (!textMarkerRange)
638         return nullptr;
639     
640     id startTextMarker = AXTextMarkerRangeStart(textMarkerRange);
641     id endTextMarker = AXTextMarkerRangeEnd(textMarkerRange);
642     
643     if (!startTextMarker || !endTextMarker)
644         return nullptr;
645     
646     AXObjectCache* cache = m_object->axObjectCache();
647     if (!cache)
648         return nullptr;
649     
650     CharacterOffset startCharacterOffset = [self characterOffsetForTextMarker:startTextMarker];
651     CharacterOffset endCharacterOffset = [self characterOffsetForTextMarker:endTextMarker];
652     return cache->rangeForUnorderedCharacterOffsets(startCharacterOffset, endCharacterOffset);
653 }
654
655 static CharacterOffset characterOffsetForTextMarker(AXObjectCache* cache, CFTypeRef textMarker)
656 {
657     if (!cache || !textMarker)
658         return CharacterOffset();
659     
660     TextMarkerData textMarkerData;
661     if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
662         return CharacterOffset();
663     
664     return cache->characterOffsetForTextMarkerData(textMarkerData);
665 }
666
667 - (CharacterOffset)characterOffsetForTextMarker:(id)textMarker
668 {
669     return characterOffsetForTextMarker(m_object->axObjectCache(), textMarker);
670 }
671
672 static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
673 {
674     ASSERT(cache);
675     
676     TextMarkerData textMarkerData;
677     cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
678     if (!textMarkerData.axID)
679         return nil;
680     
681     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
682 }
683
684 - (id)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos
685 {
686     return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos);
687 }
688
689 static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, CFTypeRef textMarker)
690 {
691     ASSERT(cache);
692     
693     if (!textMarker)
694         return VisiblePosition();
695     TextMarkerData textMarkerData;
696     if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
697         return VisiblePosition();
698     
699     return cache->visiblePositionForTextMarkerData(textMarkerData);
700 }
701
702 - (VisiblePosition)visiblePositionForTextMarker:(id)textMarker
703 {
704     return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker);
705 }
706
707 static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache* cache, id textMarkerRange)
708 {
709     return visiblePositionForTextMarker(cache, AXTextMarkerRangeStart(textMarkerRange));
710 }
711
712 static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache* cache, id textMarkerRange)
713 {
714     return visiblePositionForTextMarker(cache, AXTextMarkerRangeEnd(textMarkerRange));
715 }
716
717 static id textMarkerRangeFromMarkers(id textMarker1, id textMarker2)
718 {
719     if (!textMarker1 || !textMarker2)
720         return nil;
721     
722     return AXTextMarkerRange(textMarker1, textMarker2);
723 }
724
725 // When modifying attributed strings, the range can come from a source which may provide faulty information (e.g. the spell checker).
726 // To protect against such cases the range should be validated before adding or removing attributes.
727 static BOOL AXAttributedStringRangeIsValid(NSAttributedString *attrString, NSRange range)
728 {
729     return (range.location < [attrString length] && NSMaxRange(range) <= [attrString length]);
730 }
731
732 static void AXAttributeStringSetFont(NSMutableAttributedString *attrString, NSString *attribute, CTFontRef font, NSRange range)
733 {
734     if (!AXAttributedStringRangeIsValid(attrString, range))
735         return;
736
737     if (font) {
738         NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
739             static_cast<NSString *>(adoptCF(CTFontCopyPostScriptName(font)).get()), NSAccessibilityFontNameKey,
740             static_cast<NSString *>(adoptCF(CTFontCopyFamilyName(font)).get()), NSAccessibilityFontFamilyKey,
741             static_cast<NSString *>(adoptCF(CTFontCopyDisplayName(font)).get()), NSAccessibilityVisibleNameKey,
742             [NSNumber numberWithFloat:CTFontGetSize(font)], NSAccessibilityFontSizeKey,
743             nil];
744         
745         [attrString addAttribute:attribute value:dict range:range];
746     } else
747         [attrString removeAttribute:attribute range:range];
748     
749 }
750
751 static CGColorRef CreateCGColorIfDifferent(NSColor *nsColor, CGColorRef existingColor)
752 {
753     // get color information assuming NSDeviceRGBColorSpace
754     NSColor *rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
755     if (rgbColor == nil)
756         rgbColor = [NSColor blackColor];
757     CGFloat components[4];
758     [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
759     
760     // create a new CGColorRef to return
761     CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
762     CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
763     CGColorSpaceRelease(cgColorSpace);
764     
765     // check for match with existing color
766     if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
767         CGColorRelease(cgColor);
768         cgColor = nullptr;
769     }
770     
771     return cgColor;
772 }
773
774 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
775 {
776     if (!AXAttributedStringRangeIsValid(attrString, range))
777         return;
778     
779     if (color) {
780         CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
781         CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
782         if (cgColor) {
783             [attrString addAttribute:attribute value:(id)cgColor range:range];
784             CGColorRelease(cgColor);
785         }
786     } else
787         [attrString removeAttribute:attribute range:range];
788 }
789
790 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
791 {
792     if (!AXAttributedStringRangeIsValid(attrString, range))
793         return;
794     
795     if (number)
796         [attrString addAttribute:attribute value:number range:range];
797     else
798         [attrString removeAttribute:attribute range:range];
799 }
800
801 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
802 {
803     const RenderStyle& style = renderer->style();
804     
805     // set basic font info
806     AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style.fontCascade().primaryFont().getCTFont(), range);
807     
808     // set basic colors
809     AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style.visitedDependentColor(CSSPropertyColor)), range);
810     AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style.visitedDependentColor(CSSPropertyBackgroundColor)), range);
811     
812     // set super/sub scripting
813     EVerticalAlign alignment = style.verticalAlign();
814     if (alignment == SUB)
815         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
816     else if (alignment == SUPER)
817         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
818     else
819         [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
820     
821     // set shadow
822     if (style.textShadow())
823         AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
824     else
825         [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
826     
827     // set underline and strikethrough
828     int decor = style.textDecorationsInEffect();
829     if ((decor & TextDecorationUnderline) == 0) {
830         [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
831         [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
832     }
833     
834     if ((decor & TextDecorationLineThrough) == 0) {
835         [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
836         [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
837     }
838     
839     if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
840         // FIXME: Should the underline style be reported here?
841         auto decorationStyles = TextDecorationPainter::stylesForRenderer(*renderer, decor);
842
843         if ((decor & TextDecorationUnderline) != 0) {
844             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
845             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(decorationStyles.underlineColor), range);
846         }
847         
848         if ((decor & TextDecorationLineThrough) != 0) {
849             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
850             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(decorationStyles.linethroughColor), range);
851         }
852     }
853     
854     // Indicate background highlighting.
855     for (Node* node = renderer->node(); node; node = node->parentNode()) {
856         if (node->hasTagName(markTag))
857             AXAttributeStringSetNumber(attrString, @"AXHighlight", [NSNumber numberWithBool:YES], range);
858     }
859 }
860
861 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
862 {
863     if (!AXAttributedStringRangeIsValid(attrString, range))
864         return;
865     
866     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
867     int quoteLevel = obj->blockquoteLevel();
868     
869     if (quoteLevel)
870         [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
871     else
872         [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
873 }
874
875 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, StringView text, NSRange range)
876 {
877     if (unifiedTextCheckerEnabled(node->document().frame())) {
878         // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
879         TextCheckerClient* checker = node->document().frame()->editor().textChecker();
880         
881         // checkTextOfParagraph is the only spelling/grammar checker implemented in WK1 and WK2
882         Vector<TextCheckingResult> results;
883         checkTextOfParagraph(*checker, text, TextCheckingTypeSpelling, results, node->document().frame()->selection().selection());
884         
885         size_t size = results.size();
886         NSNumber* trueValue = [NSNumber numberWithBool:YES];
887         for (unsigned i = 0; i < size; i++) {
888             const TextCheckingResult& result = results[i];
889             AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
890 #if PLATFORM(MAC)
891             AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
892 #endif
893         }
894         return;
895     }
896
897     for (unsigned currentPosition = 0; currentPosition < text.length(); ) {
898         int misspellingLocation = -1;
899         int misspellingLength = 0;
900         node->document().frame()->editor().textChecker()->checkSpellingOfString(text.substring(currentPosition), &misspellingLocation, &misspellingLength);
901         if (misspellingLocation == -1 || !misspellingLength)
902             break;
903         
904         NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
905         AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
906 #if PLATFORM(MAC)
907         AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
908 #endif
909
910         currentPosition += misspellingLocation + misspellingLength;
911     }
912 }
913
914 static void AXAttributeStringSetExpandedTextValue(NSMutableAttributedString *attrString, RenderObject* renderer, NSRange range)
915 {
916     if (!renderer || !AXAttributedStringRangeIsValid(attrString, range))
917         return;
918     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
919     if (axObject->supportsExpandedTextValue())
920         [attrString addAttribute:NSAccessibilityExpandedTextValueAttribute value:axObject->expandedTextValue() range:range];
921     else
922         [attrString removeAttribute:NSAccessibilityExpandedTextValueAttribute range:range];
923 }
924
925 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
926 {
927     if (!renderer)
928         return;
929     
930     if (!AXAttributedStringRangeIsValid(attrString, range))
931         return;
932     
933     // Sometimes there are objects between the text and the heading.
934     // In those cases the parent hierarchy should be queried to see if there is a heading level.
935     int parentHeadingLevel = 0;
936     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
937     for (; parentObject; parentObject = parentObject->parentObject()) {
938         parentHeadingLevel = parentObject->headingLevel();
939         if (parentHeadingLevel)
940             break;
941     }
942     
943     if (parentHeadingLevel)
944         [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
945     else
946         [attrString removeAttribute:@"AXHeadingLevel" range:range];
947 }
948
949 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
950 {
951     if (!AXAttributedStringRangeIsValid(attrString, range))
952         return;
953     
954     if (is<AccessibilityRenderObject>(object)) {
955         // make a serializable AX object
956         
957         RenderObject* renderer = downcast<AccessibilityRenderObject>(*object).renderer();
958         if (!renderer)
959             return;
960         
961         AXObjectCache* cache = renderer->document().axObjectCache();
962         if (!cache)
963             return;
964         
965         AXUIElementRef axElement = wkCreateAXUIElementRef(object->wrapper());
966         if (axElement) {
967             [attrString addAttribute:attribute value:(id)axElement range:range];
968             CFRelease(axElement);
969         }
970     } else
971         [attrString removeAttribute:attribute range:range];
972 }
973
974 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, StringView text)
975 {
976     // skip invisible text
977     RenderObject* renderer = node->renderer();
978     if (!renderer)
979         return;
980     
981     // easier to calculate the range before appending the string
982     NSRange attrStringRange = NSMakeRange([attrString length], text.length());
983     
984     // append the string from this node
985     [[attrString mutableString] appendString:text.createNSStringWithoutCopying().get()];
986     
987     // add new attributes and remove irrelevant inherited ones
988     // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
989     // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
990     // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
991     
992     // remove inherited attachment from prior AXAttributedStringAppendReplaced
993     [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
994 #if PLATFORM(MAC)
995     [attrString removeAttribute:NSAccessibilityMarkedMisspelledTextAttribute range:attrStringRange];
996 #endif
997     [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
998     
999     // set new attributes
1000     AXAttributeStringSetStyle(attrString, renderer, attrStringRange);
1001     AXAttributeStringSetHeadingLevel(attrString, renderer, attrStringRange);
1002     AXAttributeStringSetBlockquoteLevel(attrString, renderer, attrStringRange);
1003     AXAttributeStringSetExpandedTextValue(attrString, renderer, attrStringRange);
1004     AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
1005     
1006     // do spelling last because it tends to break up the range
1007     AXAttributeStringSetSpelling(attrString, node, text, attrStringRange);
1008 }
1009
1010 static NSString* nsStringForReplacedNode(Node* replacedNode)
1011 {
1012     // we should always be given a rendered node and a replaced node, but be safe
1013     // replaced nodes are either attachments (widgets) or images
1014     if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode()) {
1015         ASSERT_NOT_REACHED();
1016         return nil;
1017     }
1018     
1019     // create an AX object, but skip it if it is not supposed to be seen
1020     RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
1021     if (obj->accessibilityIsIgnored())
1022         return nil;
1023     
1024     // use the attachmentCharacter to represent the replaced node
1025     const UniChar attachmentChar = NSAttachmentCharacter;
1026     return [NSString stringWithCharacters:&attachmentChar length:1];
1027 }
1028
1029 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(id)textMarkerRange
1030 {
1031     if (!m_object)
1032         return nil;
1033     
1034     RefPtr<Range> range = [self rangeForTextMarkerRange:textMarkerRange];
1035     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
1036     TextIterator it(range.get());
1037     while (!it.atEnd()) {
1038         // locate the node and starting offset for this range
1039         Node& node = it.range()->startContainer();
1040         ASSERT(&node == &it.range()->endContainer());
1041         int offset = it.range()->startOffset();
1042         
1043         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1044         if (it.text().length()) {
1045             // Add the text of the list marker item if necessary.
1046             String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
1047             if (!listMarkerText.isEmpty())
1048                 AXAttributedStringAppendText(attrString, &node, listMarkerText);
1049             AXAttributedStringAppendText(attrString, &node, it.text());
1050         } else {
1051             Node* replacedNode = node.traverseToChildAt(offset);
1052             NSString *attachmentString = nsStringForReplacedNode(replacedNode);
1053             if (attachmentString) {
1054                 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
1055                 
1056                 // append the placeholder string
1057                 [[attrString mutableString] appendString:attachmentString];
1058                 
1059                 // remove all inherited attributes
1060                 [attrString setAttributes:nil range:attrStringRange];
1061                 
1062                 // add the attachment attribute
1063                 AccessibilityObject* obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
1064                 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
1065             }
1066         }
1067         it.advance();
1068     }
1069     
1070     return [attrString autorelease];
1071 }
1072
1073 static id textMarkerRangeFromVisiblePositions(AXObjectCache* cache, const VisiblePosition& startPosition, const VisiblePosition& endPosition)
1074 {
1075     id startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
1076     id endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
1077     return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
1078 }
1079
1080 - (id)textMarkerRangeFromVisiblePositions:(const VisiblePosition&)startPosition endPosition:(const VisiblePosition&)endPosition
1081 {
1082     return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition);
1083 }
1084
1085 - (NSArray*)accessibilityActionNames
1086 {
1087     if (![self updateObjectBackingStore])
1088         return nil;
1089     
1090     // All elements should get ShowMenu and ScrollToVisible.
1091     // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list.
1092     static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
1093
1094     // Action elements allow Press.
1095     // 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.
1096     static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
1097
1098     // Menu elements allow Press and Cancel.
1099     static NSArray *menuElementActions = [[actionElementActions arrayByAddingObject:NSAccessibilityCancelAction] retain];
1100
1101     // Slider elements allow Increment/Decrement.
1102     static NSArray *sliderActions = [[defaultElementActions arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]] retain];
1103     
1104     NSArray *actions;
1105     if (m_object->supportsPressAction())
1106         actions = actionElementActions;
1107     else if (m_object->isMenuRelated())
1108         actions = menuElementActions;
1109     else if (m_object->isSlider())
1110         actions = sliderActions;
1111     else if (m_object->isAttachment())
1112         actions = [[self attachmentView] accessibilityActionNames];
1113     else
1114         actions = defaultElementActions;
1115     
1116     return actions;
1117 }
1118
1119 - (NSArray*)additionalAccessibilityAttributeNames
1120 {
1121     if (!m_object)
1122         return nil;
1123     
1124     NSMutableArray *additional = [NSMutableArray array];
1125     if (m_object->supportsARIAOwns())
1126         [additional addObject:NSAccessibilityOwnsAttribute];
1127     
1128     if (m_object->isToggleButton())
1129         [additional addObject:NSAccessibilityValueAttribute];
1130     
1131     if (m_object->supportsExpanded() || m_object->isSummary())
1132         [additional addObject:NSAccessibilityExpandedAttribute];
1133     
1134     if (m_object->isScrollbar()
1135         || m_object->isRadioGroup()
1136         || m_object->isSplitter()
1137         || m_object->isToolbar())
1138         [additional addObject:NSAccessibilityOrientationAttribute];
1139     
1140     if (m_object->supportsARIADragging())
1141         [additional addObject:NSAccessibilityGrabbedAttribute];
1142     
1143     if (m_object->supportsARIADropping())
1144         [additional addObject:NSAccessibilityDropEffectsAttribute];
1145     
1146     if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility() && downcast<AccessibilityTable>(*m_object).supportsSelectedRows())
1147         [additional addObject:NSAccessibilitySelectedRowsAttribute];
1148     
1149     if (m_object->supportsARIALiveRegion()) {
1150         [additional addObject:NSAccessibilityARIALiveAttribute];
1151         [additional addObject:NSAccessibilityARIARelevantAttribute];
1152     }
1153     
1154     if (m_object->supportsARIASetSize())
1155         [additional addObject:NSAccessibilityARIASetSizeAttribute];
1156     if (m_object->supportsARIAPosInSet())
1157         [additional addObject:NSAccessibilityARIAPosInSetAttribute];
1158     
1159     if (m_object->sortDirection() != SortDirectionNone)
1160         [additional addObject:NSAccessibilitySortDirectionAttribute];
1161     
1162     // If an object is a child of a live region, then add these
1163     if (m_object->isInsideARIALiveRegion())
1164         [additional addObject:NSAccessibilityARIAAtomicAttribute];
1165     // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
1166     [additional addObject:NSAccessibilityElementBusyAttribute];
1167     
1168     // Popup buttons on the Mac expose the value attribute.
1169     if (m_object->isPopUpButton()) {
1170         [additional addObject:NSAccessibilityValueAttribute];
1171     }
1172
1173     if (m_object->supportsRequiredAttribute()) {
1174         [additional addObject:NSAccessibilityRequiredAttribute];
1175     }
1176     
1177     if (m_object->ariaHasPopup())
1178         [additional addObject:NSAccessibilityHasPopupAttribute];
1179     
1180     if (m_object->isMathRoot()) {
1181         // The index of a square root is always known, so there's no object associated with it.
1182         if (!m_object->isMathSquareRoot())
1183             [additional addObject:NSAccessibilityMathRootIndexAttribute];
1184         [additional addObject:NSAccessibilityMathRootRadicandAttribute];
1185     } else if (m_object->isMathFraction()) {
1186         [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
1187         [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
1188         [additional addObject:NSAccessibilityMathLineThicknessAttribute];
1189     } else if (m_object->isMathSubscriptSuperscript()) {
1190         [additional addObject:NSAccessibilityMathBaseAttribute];
1191         [additional addObject:NSAccessibilityMathSubscriptAttribute];
1192         [additional addObject:NSAccessibilityMathSuperscriptAttribute];
1193     } else if (m_object->isMathUnderOver()) {
1194         [additional addObject:NSAccessibilityMathBaseAttribute];
1195         [additional addObject:NSAccessibilityMathUnderAttribute];
1196         [additional addObject:NSAccessibilityMathOverAttribute];
1197     } else if (m_object->isMathFenced()) {
1198         [additional addObject:NSAccessibilityMathFencedOpenAttribute];
1199         [additional addObject:NSAccessibilityMathFencedCloseAttribute];
1200     } else if (m_object->isMathMultiscript()) {
1201         [additional addObject:NSAccessibilityMathBaseAttribute];
1202         [additional addObject:NSAccessibilityMathPrescriptsAttribute];
1203         [additional addObject:NSAccessibilityMathPostscriptsAttribute];
1204     }
1205     
1206     if (m_object->supportsPath())
1207         [additional addObject:NSAccessibilityPathAttribute];
1208     
1209     if (m_object->supportsExpandedTextValue())
1210         [additional addObject:NSAccessibilityExpandedTextValueAttribute];
1211     
1212     return additional;
1213 }
1214
1215 - (NSArray*)accessibilityAttributeNames
1216 {
1217     if (![self updateObjectBackingStore])
1218         return nil;
1219     
1220     if (m_object->isAttachment())
1221         return [[self attachmentView] accessibilityAttributeNames];
1222     
1223     static NSArray* attributes = nil;
1224     static NSArray* anchorAttrs = nil;
1225     static NSArray* webAreaAttrs = nil;
1226     static NSArray* textAttrs = nil;
1227     static NSArray* listAttrs = nil;
1228     static NSArray* listBoxAttrs = nil;
1229     static NSArray* rangeAttrs = nil;
1230     static NSArray* commonMenuAttrs = nil;
1231     static NSArray* menuAttrs = nil;
1232     static NSArray* menuBarAttrs = nil;
1233     static NSArray* menuItemAttrs = nil;
1234     static NSArray* menuButtonAttrs = nil;
1235     static NSArray* controlAttrs = nil;
1236     static NSArray* tableAttrs = nil;
1237     static NSArray* tableRowAttrs = nil;
1238     static NSArray* tableColAttrs = nil;
1239     static NSArray* tableCellAttrs = nil;
1240     static NSArray* groupAttrs = nil;
1241     static NSArray* inputImageAttrs = nil;
1242     static NSArray* passwordFieldAttrs = nil;
1243     static NSArray* tabListAttrs = nil;
1244     static NSArray* comboBoxAttrs = nil;
1245     static NSArray* outlineAttrs = nil;
1246     static NSArray* outlineRowAttrs = nil;
1247     static NSArray* buttonAttrs = nil;
1248     static NSArray* scrollViewAttrs = nil;
1249     static NSArray* incrementorAttrs = nil;
1250     NSMutableArray* tempArray;
1251     if (attributes == nil) {
1252         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1253             NSAccessibilitySubroleAttribute,
1254             NSAccessibilityRoleDescriptionAttribute,
1255             NSAccessibilityChildrenAttribute,
1256             NSAccessibilityHelpAttribute,
1257             NSAccessibilityParentAttribute,
1258             NSAccessibilityPositionAttribute,
1259             NSAccessibilitySizeAttribute,
1260             NSAccessibilityTitleAttribute,
1261             NSAccessibilityDescriptionAttribute,
1262             NSAccessibilityValueAttribute,
1263             NSAccessibilityFocusedAttribute,
1264             NSAccessibilityEnabledAttribute,
1265             NSAccessibilityWindowAttribute,
1266             @"AXSelectedTextMarkerRange",
1267             @"AXStartTextMarker",
1268             @"AXEndTextMarker",
1269             @"AXVisited",
1270             NSAccessibilityLinkedUIElementsAttribute,
1271             NSAccessibilitySelectedAttribute,
1272             NSAccessibilityBlockQuoteLevelAttribute,
1273             NSAccessibilityTopLevelUIElementAttribute,
1274             NSAccessibilityLanguageAttribute,
1275             NSAccessibilityDOMIdentifierAttribute,
1276             NSAccessibilityDOMClassListAttribute,
1277             NSAccessibilityFocusableAncestorAttribute,
1278             NSAccessibilityEditableAncestorAttribute,
1279             NSAccessibilityHighestEditableAncestorAttribute,
1280             nil];
1281     }
1282     if (commonMenuAttrs == nil) {
1283         commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1284                            NSAccessibilityRoleDescriptionAttribute,
1285                            NSAccessibilityChildrenAttribute,
1286                            NSAccessibilityParentAttribute,
1287                            NSAccessibilityEnabledAttribute,
1288                            NSAccessibilityPositionAttribute,
1289                            NSAccessibilitySizeAttribute,
1290                            nil];
1291     }
1292     if (anchorAttrs == nil) {
1293         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1294         [tempArray addObject:NSAccessibilityURLAttribute];
1295         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1296         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
1297         [tempArray release];
1298     }
1299     if (webAreaAttrs == nil) {
1300         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1301         // WebAreas should not expose AXSubrole.
1302         [tempArray removeObject:NSAccessibilitySubroleAttribute];
1303         // WebAreas should not expose ancestor attributes
1304         [tempArray removeObject:NSAccessibilityFocusableAncestorAttribute];
1305         [tempArray removeObject:NSAccessibilityEditableAncestorAttribute];
1306         [tempArray removeObject:NSAccessibilityHighestEditableAncestorAttribute];
1307         [tempArray addObject:@"AXLinkUIElements"];
1308         [tempArray addObject:@"AXLoaded"];
1309         [tempArray addObject:@"AXLayoutCount"];
1310         [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
1311         [tempArray addObject:NSAccessibilityURLAttribute];
1312         [tempArray addObject:NSAccessibilityCaretBrowsingEnabledAttribute];
1313         [tempArray addObject:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute];
1314         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
1315         [tempArray release];
1316     }
1317     if (textAttrs == nil) {
1318         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1319         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
1320         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
1321         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
1322         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
1323         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
1324         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1325         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1326         [tempArray addObject:NSAccessibilityRequiredAttribute];
1327         [tempArray addObject:NSAccessibilityInvalidAttribute];
1328         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1329         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1330         textAttrs = [[NSArray alloc] initWithArray:tempArray];
1331         [tempArray release];
1332     }
1333     if (listAttrs == nil) {
1334         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1335         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1336         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1337         [tempArray addObject:NSAccessibilityOrientationAttribute];
1338         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1339         listAttrs = [[NSArray alloc] initWithArray:tempArray];
1340         [tempArray release];
1341     }
1342     if (listBoxAttrs == nil) {
1343         tempArray = [[NSMutableArray alloc] initWithArray:listAttrs];
1344         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1345         [tempArray addObject:NSAccessibilityRequiredAttribute];
1346         [tempArray addObject:NSAccessibilityInvalidAttribute];
1347         [tempArray addObject:NSAccessibilityOrientationAttribute];
1348         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1349         [tempArray release];
1350     }
1351     if (rangeAttrs == nil) {
1352         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1353         [tempArray addObject:NSAccessibilityMinValueAttribute];
1354         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1355         [tempArray addObject:NSAccessibilityOrientationAttribute];
1356         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1357         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1358         rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
1359         [tempArray release];
1360     }
1361     if (menuBarAttrs == nil) {
1362         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1363         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1364         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1365         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1366         [tempArray addObject:NSAccessibilityOrientationAttribute];
1367         menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
1368         [tempArray release];
1369     }
1370     if (menuAttrs == nil) {
1371         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1372         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1373         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1374         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1375         [tempArray addObject:NSAccessibilityOrientationAttribute];
1376         menuAttrs = [[NSArray alloc] initWithArray:tempArray];
1377         [tempArray release];
1378     }
1379     if (menuItemAttrs == nil) {
1380         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1381         [tempArray addObject:NSAccessibilityTitleAttribute];
1382         [tempArray addObject:NSAccessibilityDescriptionAttribute];
1383         [tempArray addObject:NSAccessibilityHelpAttribute];
1384         [tempArray addObject:NSAccessibilitySelectedAttribute];
1385         [tempArray addObject:NSAccessibilityValueAttribute];
1386         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
1387         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
1388         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
1389         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
1390         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
1391         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
1392         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
1393         [tempArray addObject:NSAccessibilityFocusedAttribute];
1394         menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
1395         [tempArray release];
1396     }
1397     if (menuButtonAttrs == nil) {
1398         menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
1399                            NSAccessibilityRoleDescriptionAttribute,
1400                            NSAccessibilityParentAttribute,
1401                            NSAccessibilityPositionAttribute,
1402                            NSAccessibilitySizeAttribute,
1403                            NSAccessibilityWindowAttribute,
1404                            NSAccessibilityEnabledAttribute,
1405                            NSAccessibilityFocusedAttribute,
1406                            NSAccessibilityTitleAttribute,
1407                            NSAccessibilityChildrenAttribute, nil];
1408     }
1409     if (controlAttrs == nil) {
1410         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1411         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1412         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1413         [tempArray addObject:NSAccessibilityRequiredAttribute];
1414         [tempArray addObject:NSAccessibilityInvalidAttribute];
1415         controlAttrs = [[NSArray alloc] initWithArray:tempArray];
1416         [tempArray release];
1417     }
1418     if (incrementorAttrs == nil) {
1419         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1420         [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
1421         [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
1422         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1423         [tempArray addObject:NSAccessibilityMinValueAttribute];
1424         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1425         incrementorAttrs = [[NSArray alloc] initWithArray:tempArray];
1426         [tempArray release];
1427     }
1428     if (buttonAttrs == nil) {
1429         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1430         // Buttons should not expose AXValue.
1431         [tempArray removeObject:NSAccessibilityValueAttribute];
1432         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1433         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1434         buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
1435         [tempArray release];
1436     }
1437     if (comboBoxAttrs == nil) {
1438         tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
1439         [tempArray addObject:NSAccessibilityExpandedAttribute];
1440         [tempArray addObject:NSAccessibilityOrientationAttribute];
1441         comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1442         [tempArray release];
1443     }
1444     if (tableAttrs == nil) {
1445         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1446         [tempArray addObject:NSAccessibilityRowsAttribute];
1447         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1448         [tempArray addObject:NSAccessibilityColumnsAttribute];
1449         [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
1450         [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
1451         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1452         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1453         [tempArray addObject:NSAccessibilityHeaderAttribute];
1454         [tempArray addObject:NSAccessibilityColumnCountAttribute];
1455         [tempArray addObject:NSAccessibilityRowCountAttribute];
1456         [tempArray addObject:NSAccessibilityARIAColumnCountAttribute];
1457         [tempArray addObject:NSAccessibilityARIARowCountAttribute];
1458         tableAttrs = [[NSArray alloc] initWithArray:tempArray];
1459         [tempArray release];
1460     }
1461     if (tableRowAttrs == nil) {
1462         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1463         [tempArray addObject:NSAccessibilityIndexAttribute];
1464         tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1465         [tempArray release];
1466     }
1467     if (tableColAttrs == nil) {
1468         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1469         [tempArray addObject:NSAccessibilityIndexAttribute];
1470         [tempArray addObject:NSAccessibilityHeaderAttribute];
1471         [tempArray addObject:NSAccessibilityRowsAttribute];
1472         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1473         tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
1474         [tempArray release];
1475     }
1476     if (tableCellAttrs == nil) {
1477         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1478         [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
1479         [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
1480         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1481         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1482         [tempArray addObject:NSAccessibilityARIAColumnIndexAttribute];
1483         [tempArray addObject:NSAccessibilityARIARowIndexAttribute];
1484         tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
1485         [tempArray release];
1486     }
1487     if (groupAttrs == nil) {
1488         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1489         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1490         groupAttrs = [[NSArray alloc] initWithArray:tempArray];
1491         [tempArray release];
1492     }
1493     if (inputImageAttrs == nil) {
1494         tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
1495         [tempArray addObject:NSAccessibilityURLAttribute];
1496         inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
1497         [tempArray release];
1498     }
1499     if (passwordFieldAttrs == nil) {
1500         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1501         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1502         [tempArray addObject:NSAccessibilityRequiredAttribute];
1503         [tempArray addObject:NSAccessibilityInvalidAttribute];
1504         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1505         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1506         passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
1507         [tempArray release];
1508     }
1509     if (tabListAttrs == nil) {
1510         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1511         [tempArray addObject:NSAccessibilityTabsAttribute];
1512         [tempArray addObject:NSAccessibilityContentsAttribute];
1513         [tempArray addObject:NSAccessibilityOrientationAttribute];
1514         tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
1515         [tempArray release];
1516     }
1517     if (outlineAttrs == nil) {
1518         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1519         [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
1520         [tempArray addObject:NSAccessibilityRowsAttribute];
1521         [tempArray addObject:NSAccessibilityColumnsAttribute];
1522         [tempArray addObject:NSAccessibilityOrientationAttribute];
1523         outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
1524         [tempArray release];
1525     }
1526     if (outlineRowAttrs == nil) {
1527         tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
1528         [tempArray addObject:NSAccessibilityDisclosingAttribute];
1529         [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
1530         [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
1531         [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1532         outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1533         [tempArray release];
1534     }
1535     if (scrollViewAttrs == nil) {
1536         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1537         [tempArray addObject:NSAccessibilityContentsAttribute];
1538         [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1539         [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1540         scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray];
1541         [tempArray release];
1542     }
1543     
1544     NSArray *objectAttributes = attributes;
1545     
1546     if (m_object->isPasswordField())
1547         objectAttributes = passwordFieldAttrs;
1548     
1549     else if (m_object->isWebArea())
1550         objectAttributes = webAreaAttrs;
1551     
1552     else if (m_object->isTextControl())
1553         objectAttributes = textAttrs;
1554     
1555     else if (m_object->isLink() || m_object->isImage())
1556         objectAttributes = anchorAttrs;
1557     
1558     else if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility())
1559         objectAttributes = tableAttrs;
1560     else if (m_object->isTableColumn())
1561         objectAttributes = tableColAttrs;
1562     else if (m_object->isTableCell())
1563         objectAttributes = tableCellAttrs;
1564     else if (m_object->isTableRow()) {
1565         // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1566         if (m_object->isARIATreeGridRow())
1567             objectAttributes = outlineRowAttrs;
1568         else
1569             objectAttributes = tableRowAttrs;
1570     }
1571     
1572     else if (m_object->isTree())
1573         objectAttributes = outlineAttrs;
1574     else if (m_object->isTreeItem())
1575         objectAttributes = outlineRowAttrs;
1576     
1577     else if (m_object->isListBox())
1578         objectAttributes = listBoxAttrs;
1579     else if (m_object->isList())
1580         objectAttributes = listAttrs;
1581     
1582     else if (m_object->isComboBox())
1583         objectAttributes = comboBoxAttrs;
1584     
1585     else if (m_object->isProgressIndicator() || m_object->isSlider())
1586         objectAttributes = rangeAttrs;
1587     
1588     // These are processed in order because an input image is a button, and a button is a control.
1589     else if (m_object->isInputImage())
1590         objectAttributes = inputImageAttrs;
1591     else if (m_object->isButton())
1592         objectAttributes = buttonAttrs;
1593     else if (m_object->isControl())
1594         objectAttributes = controlAttrs;
1595     
1596     else if (m_object->isGroup() || m_object->isListItem())
1597         objectAttributes = groupAttrs;
1598     else if (m_object->isTabList())
1599         objectAttributes = tabListAttrs;
1600     else if (m_object->isScrollView())
1601         objectAttributes = scrollViewAttrs;
1602     else if (m_object->isSpinButton())
1603         objectAttributes = incrementorAttrs;
1604     
1605     else if (m_object->isMenu())
1606         objectAttributes = menuAttrs;
1607     else if (m_object->isMenuBar())
1608         objectAttributes = menuBarAttrs;
1609     else if (m_object->isMenuButton())
1610         objectAttributes = menuButtonAttrs;
1611     else if (m_object->isMenuItem())
1612         objectAttributes = menuItemAttrs;
1613     
1614     NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1615     if ([additionalAttributes count])
1616         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1617     
1618     // Only expose AXARIACurrent attribute when the element is set to be current item.
1619     if (m_object->ariaCurrentState() != ARIACurrentFalse)
1620         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:@[ NSAccessibilityARIACurrentAttribute ]];
1621     
1622     return objectAttributes;
1623 }
1624
1625 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange
1626 {
1627     if (!textMarkerRange)
1628         return VisiblePositionRange();
1629     AXObjectCache* cache = m_object->axObjectCache();
1630     return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1631 }
1632
1633 - (NSArray*)renderWidgetChildren
1634 {
1635     Widget* widget = m_object->widget();
1636     if (!widget)
1637         return nil;
1638 #pragma clang diagnostic push
1639 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1640     return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1641 #pragma clang diagnostic pop
1642 }
1643
1644 - (id)remoteAccessibilityParentObject
1645 {
1646     if (!m_object)
1647         return nil;
1648     
1649     Document* document = m_object->document();
1650     if (!document)
1651         return nil;
1652     
1653     Frame* frame = document->frame();
1654     if (!frame)
1655         return nil;
1656     
1657     return frame->loader().client().accessibilityRemoteObject();
1658 }
1659
1660 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1661 {
1662     unsigned length = [array count];
1663     vector.reserveInitialCapacity(length);
1664     for (unsigned i = 0; i < length; ++i) {
1665         AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1666         if (obj)
1667             vector.append(obj);
1668     }
1669 }
1670
1671 static NSMutableArray *convertStringsToNSArray(const Vector<String>& vector)
1672 {
1673     NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
1674     for (const auto& string : vector)
1675         [array addObject:string];
1676     return array;
1677 }
1678
1679 - (id)textMarkerRangeForSelection
1680 {
1681     VisibleSelection selection = m_object->selection();
1682     if (selection.isNone())
1683         return nil;
1684     return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1685 }
1686
1687 - (id)associatedPluginParent
1688 {
1689     if (!m_object || !m_object->hasAttribute(x_apple_pdf_annotationAttr))
1690         return nil;
1691     
1692     if (!m_object->document()->isPluginDocument())
1693         return nil;
1694         
1695     Widget* pluginWidget = static_cast<PluginDocument*>(m_object->document())->pluginWidget();
1696     if (!pluginWidget || !pluginWidget->isPluginViewBase())
1697         return nil;
1698
1699     return static_cast<PluginViewBase*>(pluginWidget)->accessibilityAssociatedPluginParentForElement(m_object->element());
1700 }
1701
1702 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1703 {
1704     FrameView* frameView = m_object->documentFrameView();
1705     
1706     // WebKit1 code path... platformWidget() exists.
1707     if (frameView && frameView->platformWidget()) {
1708         NSPoint nsPoint = (NSPoint)point;
1709         NSView* view = frameView->documentView();
1710 #pragma clang diagnostic push
1711 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1712         nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]];
1713 #pragma clang diagnostic pop
1714         return CGPointMake(nsPoint.x, nsPoint.y);
1715     } else {
1716         
1717         // Find the appropriate scroll view to use to convert the contents to the window.
1718         ScrollView* scrollView = nullptr;
1719         AccessibilityObject* parent = nullptr;
1720         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1721             if (is<AccessibilityScrollView>(*parent)) {
1722                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1723                 break;
1724             }
1725         }
1726         
1727         IntPoint intPoint = flooredIntPoint(point);
1728         if (scrollView)
1729             intPoint = scrollView->contentsToRootView(intPoint);
1730         
1731         Page* page = m_object->page();
1732         
1733         // If we have an empty chrome client (like SVG) then we should use the page
1734         // of the scroll view parent to help us get to the screen rect.
1735         if (parent && page && page->chrome().client().isEmptyChromeClient())
1736             page = parent->page();
1737         
1738         if (page) {
1739             IntRect rect = IntRect(intPoint, IntSize(0, 0));            
1740             intPoint = page->chrome().rootViewToScreen(rect).location();
1741         }
1742         
1743         return intPoint;
1744     }
1745 }
1746
1747 static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element)
1748 {
1749     NSBezierPath *bezierPath = (NSBezierPath *)info;
1750     switch (element->type) {
1751     case kCGPathElementMoveToPoint:
1752         [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])];
1753         break;
1754     case kCGPathElementAddLineToPoint:
1755         [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])];
1756         break;
1757     case kCGPathElementAddCurveToPoint:
1758         [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])];
1759         break;
1760     case kCGPathElementCloseSubpath:
1761         [bezierPath closePath];
1762         break;
1763     default:
1764         break;
1765     }
1766 }
1767
1768 - (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1769 {
1770     NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1771     CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath);
1772     return bezierPath;
1773 }
1774
1775 - (NSBezierPath *)path
1776 {
1777     Path path = m_object->elementPath();
1778     if (path.isEmpty())
1779         return NULL;
1780     
1781     CGPathRef transformedPath = [self convertPathToScreenSpace:path];
1782     return [self bezierPathFromPath:transformedPath];
1783 }
1784
1785 - (NSValue *)position
1786 {
1787     IntRect rect = snappedIntRect(m_object->elementRect());
1788     
1789     // The Cocoa accessibility API wants the lower-left corner.
1790     FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY());
1791
1792     CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint];
1793     
1794     return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)];
1795 }
1796
1797 typedef HashMap<int, NSString*> AccessibilityRoleMap;
1798
1799 static const AccessibilityRoleMap& createAccessibilityRoleMap()
1800 {
1801     struct RoleEntry {
1802         AccessibilityRole value;
1803         NSString* string;
1804     };
1805     
1806     static const RoleEntry roles[] = {
1807         { UnknownRole, NSAccessibilityUnknownRole },
1808         { ButtonRole, NSAccessibilityButtonRole },
1809         { RadioButtonRole, NSAccessibilityRadioButtonRole },
1810         { CheckBoxRole, NSAccessibilityCheckBoxRole },
1811         { SliderRole, NSAccessibilitySliderRole },
1812         { TabGroupRole, NSAccessibilityTabGroupRole },
1813         { TextFieldRole, NSAccessibilityTextFieldRole },
1814         { StaticTextRole, NSAccessibilityStaticTextRole },
1815         { TextAreaRole, NSAccessibilityTextAreaRole },
1816         { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1817         { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1818         { MenuButtonRole, NSAccessibilityMenuButtonRole },
1819         { TableRole, NSAccessibilityTableRole },
1820         { ApplicationRole, NSAccessibilityApplicationRole },
1821         { GroupRole, NSAccessibilityGroupRole },
1822         { TextGroupRole, NSAccessibilityGroupRole },
1823         { RadioGroupRole, NSAccessibilityRadioGroupRole },
1824         { ListRole, NSAccessibilityListRole },
1825         { DirectoryRole, NSAccessibilityListRole },
1826         { ScrollBarRole, NSAccessibilityScrollBarRole },
1827         { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1828         { ImageRole, NSAccessibilityImageRole },
1829         { MenuBarRole, NSAccessibilityMenuBarRole },
1830         { MenuRole, NSAccessibilityMenuRole },
1831         { MenuItemRole, NSAccessibilityMenuItemRole },
1832         { MenuItemCheckboxRole, NSAccessibilityMenuItemRole },
1833         { MenuItemRadioRole, NSAccessibilityMenuItemRole },
1834         { ColumnRole, NSAccessibilityColumnRole },
1835         { RowRole, NSAccessibilityRowRole },
1836         { ToolbarRole, NSAccessibilityToolbarRole },
1837         { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1838         { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1839         { WindowRole, NSAccessibilityWindowRole },
1840         { DrawerRole, NSAccessibilityDrawerRole },
1841         { SystemWideRole, NSAccessibilitySystemWideRole },
1842         { OutlineRole, NSAccessibilityOutlineRole },
1843         { IncrementorRole, NSAccessibilityIncrementorRole },
1844         { BrowserRole, NSAccessibilityBrowserRole },
1845         { ComboBoxRole, NSAccessibilityComboBoxRole },
1846         { SplitGroupRole, NSAccessibilitySplitGroupRole },
1847         { SplitterRole, NSAccessibilitySplitterRole },
1848         { ColorWellRole, NSAccessibilityColorWellRole },
1849         { GrowAreaRole, NSAccessibilityGrowAreaRole },
1850         { SheetRole, NSAccessibilitySheetRole },
1851         { HelpTagRole, NSAccessibilityHelpTagRole },
1852         { MatteRole, NSAccessibilityMatteRole },
1853         { RulerRole, NSAccessibilityRulerRole },
1854         { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1855         { LinkRole, NSAccessibilityLinkRole },
1856         { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1857         { GridRole, NSAccessibilityTableRole },
1858         { WebCoreLinkRole, NSAccessibilityLinkRole },
1859         { ImageMapLinkRole, NSAccessibilityLinkRole },
1860         { ImageMapRole, @"AXImageMap" },
1861         { ListMarkerRole, @"AXListMarker" },
1862         { WebAreaRole, @"AXWebArea" },
1863         { HeadingRole, @"AXHeading" },
1864         { ListBoxRole, NSAccessibilityListRole },
1865         { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1866         { CellRole, NSAccessibilityCellRole },
1867         { GridCellRole, NSAccessibilityCellRole },
1868         { TableHeaderContainerRole, NSAccessibilityGroupRole },
1869         { ColumnHeaderRole, NSAccessibilityCellRole },
1870         { RowHeaderRole, NSAccessibilityCellRole },
1871         { DefinitionRole, NSAccessibilityGroupRole },
1872         { DescriptionListDetailRole, NSAccessibilityGroupRole },
1873         { DescriptionListTermRole, NSAccessibilityGroupRole },
1874         { DescriptionListRole, NSAccessibilityListRole },
1875         { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1876         { WebApplicationRole, NSAccessibilityGroupRole },
1877         { LandmarkBannerRole, NSAccessibilityGroupRole },
1878         { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1879         { LandmarkDocRegionRole, NSAccessibilityGroupRole },
1880         { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1881         { LandmarkMainRole, NSAccessibilityGroupRole },
1882         { LandmarkNavigationRole, NSAccessibilityGroupRole },
1883         { LandmarkRegionRole, NSAccessibilityGroupRole },
1884         { LandmarkSearchRole, NSAccessibilityGroupRole },
1885         { ApplicationAlertRole, NSAccessibilityGroupRole },
1886         { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1887         { ApplicationDialogRole, NSAccessibilityGroupRole },
1888         { ApplicationGroupRole, NSAccessibilityGroupRole },
1889         { ApplicationTextGroupRole, NSAccessibilityGroupRole },
1890         { ApplicationLogRole, NSAccessibilityGroupRole },
1891         { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1892         { ApplicationStatusRole, NSAccessibilityGroupRole },
1893         { ApplicationTimerRole, NSAccessibilityGroupRole },
1894         { DocumentRole, NSAccessibilityGroupRole },
1895         { DocumentArticleRole, NSAccessibilityGroupRole },
1896         { DocumentMathRole, NSAccessibilityGroupRole },
1897         { DocumentNoteRole, NSAccessibilityGroupRole },
1898         { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1899         { TabRole, NSAccessibilityRadioButtonRole },
1900         { TabListRole, NSAccessibilityTabGroupRole },
1901         { TabPanelRole, NSAccessibilityGroupRole },
1902         { TreeRole, NSAccessibilityOutlineRole },
1903         { TreeItemRole, NSAccessibilityRowRole },
1904         { ListItemRole, NSAccessibilityGroupRole },
1905         { ParagraphRole, NSAccessibilityGroupRole },
1906         { LabelRole, NSAccessibilityGroupRole },
1907         { DivRole, NSAccessibilityGroupRole },
1908         { FormRole, NSAccessibilityGroupRole },
1909         { SpinButtonRole, NSAccessibilityIncrementorRole },
1910         { FooterRole, NSAccessibilityGroupRole },
1911         { ToggleButtonRole, NSAccessibilityCheckBoxRole },
1912         { CanvasRole, NSAccessibilityImageRole },
1913         { SVGRootRole, NSAccessibilityGroupRole },
1914         { LegendRole, NSAccessibilityGroupRole },
1915         { MathElementRole, NSAccessibilityGroupRole },
1916         { AudioRole, NSAccessibilityGroupRole },
1917         { VideoRole, NSAccessibilityGroupRole },
1918         { HorizontalRuleRole, NSAccessibilitySplitterRole },
1919         { BlockquoteRole, NSAccessibilityGroupRole },
1920         { SwitchRole, NSAccessibilityCheckBoxRole },
1921         { SearchFieldRole, NSAccessibilityTextFieldRole },
1922         { PreRole, NSAccessibilityGroupRole },
1923         { RubyBaseRole, NSAccessibilityGroupRole },
1924         { RubyBlockRole, NSAccessibilityGroupRole },
1925         { RubyInlineRole, NSAccessibilityGroupRole },
1926         { RubyRunRole, NSAccessibilityGroupRole },
1927         { RubyTextRole, NSAccessibilityGroupRole },
1928         { DetailsRole, NSAccessibilityGroupRole },
1929         { SummaryRole, NSAccessibilityButtonRole },
1930         { SVGTextPathRole, NSAccessibilityGroupRole },
1931         { SVGTextRole, NSAccessibilityGroupRole },
1932         { SVGTSpanRole, NSAccessibilityGroupRole },
1933         { InlineRole, NSAccessibilityGroupRole },
1934         { MarkRole, NSAccessibilityGroupRole },
1935     };
1936     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1937     
1938     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1939     for (unsigned i = 0; i < numRoles; ++i)
1940         roleMap.set(roles[i].value, roles[i].string);
1941     return roleMap;
1942 }
1943
1944 static NSString* roleValueToNSString(AccessibilityRole value)
1945 {
1946     ASSERT(value);
1947     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1948     return roleMap.get(value);
1949 }
1950
1951 - (NSString*)role
1952 {
1953 #pragma clang diagnostic push
1954 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1955     if (m_object->isAttachment())
1956         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1957 #pragma clang diagnostic pop
1958     AccessibilityRole role = m_object->roleValue();
1959
1960     if (role == LabelRole && is<AccessibilityLabel>(*m_object) && downcast<AccessibilityLabel>(*m_object).containsOnlyStaticText())
1961         role = StaticTextRole;
1962
1963     // The mfenced element creates anonymous RenderMathMLOperators with no RenderText
1964     // descendants. Because these anonymous renderers are the only accessible objects
1965     // containing the operator, assign StaticTextRole.
1966     if (m_object->isAnonymousMathOperator())
1967         role = StaticTextRole;
1968
1969     if (role == CanvasRole && m_object->canvasHasFallbackContent())
1970         role = GroupRole;
1971     NSString* string = roleValueToNSString(role);
1972     if (string != nil)
1973         return string;
1974     return NSAccessibilityUnknownRole;
1975 }
1976
1977 #pragma clang diagnostic push
1978 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1979 - (NSString*)subrole
1980 {
1981     if (m_object->isPasswordField())
1982         return NSAccessibilitySecureTextFieldSubrole;
1983     if (m_object->isSearchField())
1984         return NSAccessibilitySearchFieldSubrole;
1985     
1986     if (m_object->isAttachment()) {
1987         NSView* attachView = [self attachmentView];
1988         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute])
1989             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1990     }
1991     
1992     AccessibilityRole role = m_object->roleValue();
1993     if (role == HorizontalRuleRole)
1994         return NSAccessibilityContentSeparatorSubrole;
1995     if (role == ToggleButtonRole)
1996         return NSAccessibilityToggleSubrole;
1997     
1998     if (is<AccessibilitySpinButtonPart>(*m_object)) {
1999         if (downcast<AccessibilitySpinButtonPart>(*m_object).isIncrementor())
2000             return NSAccessibilityIncrementArrowSubrole;
2001         
2002         return NSAccessibilityDecrementArrowSubrole;
2003     }
2004     
2005     if (m_object->isFileUploadButton())
2006         return @"AXFileUploadButton";
2007     
2008     if (m_object->isTreeItem())
2009         return NSAccessibilityOutlineRowSubrole;
2010     
2011     if (m_object->isFieldset())
2012         return @"AXFieldset";
2013     
2014     if (is<AccessibilityList>(*m_object)) {
2015         auto& listObject = downcast<AccessibilityList>(*m_object);
2016         if (listObject.isUnorderedList() || listObject.isOrderedList())
2017             return NSAccessibilityContentListSubrole;
2018         if (listObject.isDescriptionList()) {
2019             return NSAccessibilityDescriptionListSubrole;
2020         }
2021     }
2022     
2023     // ARIA content subroles.
2024     switch (role) {
2025         case LandmarkBannerRole:
2026             return @"AXLandmarkBanner";
2027         case LandmarkComplementaryRole:
2028             return @"AXLandmarkComplementary";
2029             // Footer roles should appear as content info types.
2030         case FooterRole:
2031         case LandmarkContentInfoRole:
2032             return @"AXLandmarkContentInfo";
2033         case LandmarkMainRole:
2034             return @"AXLandmarkMain";
2035         case LandmarkNavigationRole:
2036             return @"AXLandmarkNavigation";
2037         case LandmarkDocRegionRole:
2038         case LandmarkRegionRole:
2039             return @"AXLandmarkRegion";
2040         case LandmarkSearchRole:
2041             return @"AXLandmarkSearch";
2042         case ApplicationAlertRole:
2043             return @"AXApplicationAlert";
2044         case ApplicationAlertDialogRole:
2045             return @"AXApplicationAlertDialog";
2046         case ApplicationDialogRole:
2047             return @"AXApplicationDialog";
2048         case ApplicationGroupRole:
2049         case ApplicationTextGroupRole:
2050             return @"AXApplicationGroup";
2051         case ApplicationLogRole:
2052             return @"AXApplicationLog";
2053         case ApplicationMarqueeRole:
2054             return @"AXApplicationMarquee";
2055         case ApplicationStatusRole:
2056             return @"AXApplicationStatus";
2057         case ApplicationTimerRole:
2058             return @"AXApplicationTimer";
2059         case DocumentRole:
2060             return @"AXDocument";
2061         case DocumentArticleRole:
2062             return @"AXDocumentArticle";
2063         case DocumentMathRole:
2064             return @"AXDocumentMath";
2065         case DocumentNoteRole:
2066             return @"AXDocumentNote";
2067         case UserInterfaceTooltipRole:
2068             return @"AXUserInterfaceTooltip";
2069         case TabPanelRole:
2070             return @"AXTabPanel";
2071         case DefinitionRole:
2072             return @"AXDefinition";
2073         case DescriptionListTermRole:
2074             return @"AXTerm";
2075         case DescriptionListDetailRole:
2076             return @"AXDescription";
2077         case WebApplicationRole:
2078             return @"AXWebApplication";
2079             // Default doesn't return anything, so roles defined below can be chosen.
2080         default:
2081             break;
2082     }
2083     
2084     if (role == MathElementRole) {
2085         if (m_object->isMathFraction())
2086             return @"AXMathFraction";
2087         if (m_object->isMathFenced())
2088             return @"AXMathFenced";
2089         if (m_object->isMathSubscriptSuperscript())
2090             return @"AXMathSubscriptSuperscript";
2091         if (m_object->isMathRow())
2092             return @"AXMathRow";
2093         if (m_object->isMathUnderOver())
2094             return @"AXMathUnderOver";
2095         if (m_object->isMathSquareRoot())
2096             return @"AXMathSquareRoot";
2097         if (m_object->isMathRoot())
2098             return @"AXMathRoot";
2099         if (m_object->isMathText())
2100             return @"AXMathText";
2101         if (m_object->isMathNumber())
2102             return @"AXMathNumber";
2103         if (m_object->isMathIdentifier())
2104             return @"AXMathIdentifier";
2105         if (m_object->isMathTable())
2106             return @"AXMathTable";
2107         if (m_object->isMathTableRow())
2108             return @"AXMathTableRow";
2109         if (m_object->isMathTableCell())
2110             return @"AXMathTableCell";
2111         if (m_object->isMathFenceOperator())
2112             return @"AXMathFenceOperator";
2113         if (m_object->isMathSeparatorOperator())
2114             return @"AXMathSeparatorOperator";
2115         if (m_object->isMathOperator())
2116             return @"AXMathOperator";
2117         if (m_object->isMathMultiscript())
2118             return @"AXMathMultiscript";
2119     }
2120     
2121     if (role == VideoRole)
2122         return @"AXVideo";
2123     if (role == AudioRole)
2124         return @"AXAudio";
2125     if (role == DetailsRole)
2126         return @"AXDetails";
2127     if (role == SummaryRole)
2128         return @"AXSummary";
2129     
2130     if (m_object->isMediaTimeline())
2131         return NSAccessibilityTimelineSubrole;
2132
2133     if (m_object->isSwitch())
2134         return NSAccessibilitySwitchSubrole;
2135
2136     if (m_object->isStyleFormatGroup()) {
2137         if (Node* node = m_object->node()) {
2138             if (node->hasTagName(kbdTag))
2139                 return @"AXKeyboardInputStyleGroup";
2140             if (node->hasTagName(codeTag))
2141                 return @"AXCodeStyleGroup";
2142             if (node->hasTagName(preTag))
2143                 return @"AXPreformattedStyleGroup";
2144             if (node->hasTagName(sampTag))
2145                 return @"AXSampleStyleGroup";
2146             if (node->hasTagName(varTag))
2147                 return @"AXVariableStyleGroup";
2148             if (node->hasTagName(citeTag))
2149                 return @"AXCiteStyleGroup";
2150             if (node->hasTagName(insTag))
2151                 return @"AXInsertStyleGroup";
2152             if (node->hasTagName(delTag))
2153                 return @"AXDeleteStyleGroup";
2154             if (node->hasTagName(supTag))
2155                 return @"AXSuperscriptStyleGroup";
2156             if (node->hasTagName(subTag))
2157                 return @"AXSubscriptStyleGroup";
2158         }
2159     }
2160     
2161     // Ruby subroles
2162     switch (role) {
2163     case RubyBaseRole:
2164         return NSAccessibilityRubyBaseSubrole;
2165     case RubyBlockRole:
2166         return NSAccessibilityRubyBlockSubrole;
2167     case RubyInlineRole:
2168         return NSAccessibilityRubyInlineSubrole;
2169     case RubyRunRole:
2170         return NSAccessibilityRubyRunSubrole;
2171     case RubyTextRole:
2172         return NSAccessibilityRubyTextSubrole;
2173     default:
2174         break;
2175     }
2176     
2177     return nil;
2178 }
2179 #pragma clang diagnostic pop
2180
2181 - (NSString*)roleDescription
2182 {
2183     if (!m_object)
2184         return nil;
2185
2186 #pragma clang diagnostic push
2187 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2188     // attachments have the AXImage role, but a different subrole
2189     if (m_object->isAttachment())
2190         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
2191 #pragma clang diagnostic pop
2192
2193     const AtomicString& overrideRoleDescription = m_object->roleDescription();
2194     if (!overrideRoleDescription.isNull())
2195         return overrideRoleDescription;
2196     
2197     NSString* axRole = [self role];
2198     
2199     if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
2200         
2201         if (m_object->isOutput())
2202             return AXOutputText();
2203         
2204         NSString *ariaLandmarkRoleDescription = [self ariaLandmarkRoleDescription];
2205         if (ariaLandmarkRoleDescription)
2206             return ariaLandmarkRoleDescription;
2207         
2208         if (m_object->isFigure())
2209             return AXFigureText();
2210         
2211         switch (m_object->roleValue()) {
2212         case AudioRole:
2213             return localizedMediaControlElementString("AudioElement");
2214         case DefinitionRole:
2215             return AXDefinitionText();
2216         case DescriptionListTermRole:
2217             return AXDescriptionListTermText();
2218         case DescriptionListDetailRole:
2219             return AXDescriptionListDetailText();
2220         case DetailsRole:
2221             return AXDetailsText();
2222         case FooterRole:
2223             return AXFooterRoleDescriptionText();
2224         case MarkRole:
2225             return AXMarkText();
2226         case VideoRole:
2227             return localizedMediaControlElementString("VideoElement");
2228         default:
2229             return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
2230         }
2231     }
2232     
2233     if ([axRole isEqualToString:@"AXWebArea"])
2234         return AXWebAreaText();
2235     
2236     if ([axRole isEqualToString:@"AXLink"])
2237         return AXLinkText();
2238     
2239     if ([axRole isEqualToString:@"AXListMarker"])
2240         return AXListMarkerText();
2241     
2242     if ([axRole isEqualToString:@"AXImageMap"])
2243         return AXImageMapText();
2244     
2245     if ([axRole isEqualToString:@"AXHeading"])
2246         return AXHeadingText();
2247     
2248     if ([axRole isEqualToString:NSAccessibilityTextFieldRole]) {
2249         auto* node = m_object->node();
2250         if (is<HTMLInputElement>(node)) {
2251             auto& input = downcast<HTMLInputElement>(*node);
2252             if (input.isEmailField())
2253                 return AXEmailFieldText();
2254             if (input.isTelephoneField())
2255                 return AXTelephoneFieldText();
2256             if (input.isURLField())
2257                 return AXURLFieldText();
2258             if (input.isNumberField())
2259                 return AXNumberFieldText();
2260             
2261             // These input types are not enabled on mac yet, we check the type attribute for now.
2262             auto& type = input.attributeWithoutSynchronization(typeAttr);
2263             if (equalLettersIgnoringASCIICase(type, "date"))
2264                 return AXDateFieldText();
2265             if (equalLettersIgnoringASCIICase(type, "time"))
2266                 return AXTimeFieldText();
2267             if (equalLettersIgnoringASCIICase(type, "week"))
2268                 return AXWeekFieldText();
2269             if (equalLettersIgnoringASCIICase(type, "month"))
2270                 return AXMonthFieldText();
2271             if (equalLettersIgnoringASCIICase(type, "datetime-local"))
2272                 return AXDateTimeFieldText();
2273         }
2274     }
2275     
2276     if (m_object->isFileUploadButton())
2277         return AXFileUploadButtonText();
2278     
2279     // Only returning for DL (not UL or OL) because description changed with HTML5 from 'definition list' to
2280     // superset 'description list' and does not return the same values in AX API on some OS versions. 
2281     if (is<AccessibilityList>(*m_object)) {
2282         if (downcast<AccessibilityList>(*m_object).isDescriptionList())
2283             return AXDescriptionListText();
2284     }
2285     
2286     if (m_object->roleValue() == HorizontalRuleRole)
2287         return AXHorizontalRuleDescriptionText();
2288     
2289     // AppKit also returns AXTab for the role description for a tab item.
2290     if (m_object->isTabItem())
2291         return NSAccessibilityRoleDescription(@"AXTab", nil);
2292     
2293     if (m_object->isSummary())
2294         return AXSummaryText();
2295     
2296     // We should try the system default role description for all other roles.
2297     // If we get the same string back, then as a last resort, return unknown.
2298     NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
2299     
2300     // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description
2301     // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions
2302     // we should fallback on a role description ignoring the subrole in these cases.
2303     if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, [self subrole]]])
2304         defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil);
2305     
2306     if (![defaultRoleDescription isEqualToString:axRole])
2307         return defaultRoleDescription;
2308     
2309     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
2310 }
2311
2312 - (NSString *)computedRoleString
2313 {
2314     if (!m_object)
2315         return nil;
2316     return m_object->computedRoleString();
2317 }
2318
2319 - (id)scrollViewParent
2320 {
2321     if (!is<AccessibilityScrollView>(m_object))
2322         return nil;
2323     
2324     // If this scroll view provides it's parent object (because it's a sub-frame), then
2325     // we should not find the remoteAccessibilityParent.
2326     if (m_object->parentObject())
2327         return nil;
2328     
2329     ScrollView* scroll = downcast<AccessibilityScrollView>(*m_object).scrollView();
2330     if (!scroll)
2331         return nil;
2332     
2333     if (scroll->platformWidget())
2334         return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
2335     
2336     return [self remoteAccessibilityParentObject];
2337 }
2338
2339 - (NSString *)valueDescriptionForMeter
2340 {
2341     if (!m_object)
2342         return nil;
2343     
2344     String valueDescription = m_object->valueDescription();
2345 #if ENABLE(METER_ELEMENT)
2346     if (!is<AccessibilityProgressIndicator>(m_object))
2347         return valueDescription;
2348     auto &meter = downcast<AccessibilityProgressIndicator>(*m_object);
2349     String gaugeRegionValue = meter.gaugeRegionValueDescription();
2350     if (!gaugeRegionValue.isEmpty()) {
2351         StringBuilder builder;
2352         builder.append(valueDescription);
2353         if (builder.length())
2354             builder.appendLiteral(", ");
2355         builder.append(gaugeRegionValue);
2356         return builder.toString();
2357     }
2358 #endif
2359     return valueDescription;
2360 }
2361
2362 // FIXME: split up this function in a better way.
2363 // suggestions: Use a hash table that maps attribute names to function calls,
2364 // or maybe pointers to member functions
2365 - (id)accessibilityAttributeValue:(NSString*)attributeName
2366 {
2367     if (![self updateObjectBackingStore])
2368         return nil;
2369     
2370     if (m_object->isDetachedFromParent())
2371         return nil;
2372     
2373     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
2374         return [self role];
2375     
2376     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
2377         return [self subrole];
2378     
2379     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
2380         return [self roleDescription];
2381
2382     // AXARIARole is only used by DumpRenderTree (so far).
2383     if ([attributeName isEqualToString:@"AXARIARole"])
2384         return [self computedRoleString];
2385     
2386     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
2387         
2388         // This will return the parent of the AXWebArea, if this is a web area.
2389         id scrollViewParent = [self scrollViewParent];
2390         if (scrollViewParent)
2391             return scrollViewParent;
2392         
2393         // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
2394         if (m_object->isTreeItem()) {
2395             AccessibilityObject* parent = m_object->parentObjectUnignored();
2396             while (parent) {
2397                 if (parent->isTree())
2398                     return parent->wrapper();
2399                 parent = parent->parentObjectUnignored();
2400             }
2401         }
2402         
2403         AccessibilityObject* parent = m_object->parentObjectUnignored();
2404         if (!parent)
2405             return nil;
2406         
2407         // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
2408         // should be reported directly as such.
2409         if (m_object->isWebArea() && parent->isAttachment())
2410             return [parent->wrapper() attachmentView];
2411         
2412         return parent->wrapper();
2413     }
2414     
2415     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
2416         if (m_object->children().isEmpty()) {
2417             NSArray* children = [self renderWidgetChildren];
2418             if (children != nil)
2419                 return children;
2420         }
2421         
2422         // The tree's (AXOutline) children are supposed to be its rows and columns.
2423         // The ARIA spec doesn't have columns, so we just need rows.
2424         if (m_object->isTree())
2425             return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
2426         
2427         // A tree item should only expose its content as its children (not its rows)
2428         if (m_object->isTreeItem()) {
2429             AccessibilityObject::AccessibilityChildrenVector contentCopy;
2430             m_object->ariaTreeItemContent(contentCopy);
2431             return convertToNSArray(contentCopy);
2432         }
2433         
2434         return convertToNSArray(m_object->children());
2435     }
2436     
2437     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2438         if (m_object->canHaveSelectedChildren()) {
2439             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2440             m_object->selectedChildren(selectedChildrenCopy);
2441             return convertToNSArray(selectedChildrenCopy);
2442         }
2443         return nil;
2444     }
2445     
2446     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
2447         if (m_object->isListBox()) {
2448             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
2449             m_object->visibleChildren(visibleChildrenCopy);
2450             return convertToNSArray(visibleChildrenCopy);
2451         }
2452         else if (m_object->isList())
2453             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
2454         
2455         return nil;
2456     }
2457     
2458     
2459     if (m_object->isWebArea()) {
2460         if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
2461             AccessibilityObject::AccessibilityChildrenVector links;
2462             downcast<AccessibilityRenderObject>(*m_object).getDocumentLinks(links);
2463             return convertToNSArray(links);
2464         }
2465         if ([attributeName isEqualToString:@"AXLoaded"])
2466             return [NSNumber numberWithBool:m_object->isLoaded()];
2467         if ([attributeName isEqualToString:@"AXLayoutCount"])
2468             return [NSNumber numberWithInt:m_object->layoutCount()];
2469         if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
2470             return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
2471     }
2472     
2473     if (m_object->isTextControl()) {
2474         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
2475             int length = m_object->textLength();
2476             if (length < 0)
2477                 return nil;
2478             return [NSNumber numberWithUnsignedInt:length];
2479         }
2480         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2481             String selectedText = m_object->selectedText();
2482             if (selectedText.isNull())
2483                 return nil;
2484             return (NSString*)selectedText;
2485         }
2486         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2487             PlainTextRange textRange = m_object->selectedTextRange();
2488             if (textRange.isNull())
2489                 return [NSValue valueWithRange:NSMakeRange(0, 0)];
2490             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
2491         }
2492         // TODO: Get actual visible range. <rdar://problem/4712101>
2493         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2494             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
2495         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
2496             // if selectionEnd > 0, then there is selected text and this question should not be answered
2497             if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
2498                 return nil;
2499             
2500             AccessibilityObject* focusedObject = m_object->focusedUIElement();
2501             if (focusedObject != m_object)
2502                 return nil;
2503             
2504             VisiblePosition focusedPosition = focusedObject->visiblePositionForIndex(focusedObject->selectionStart(), true);
2505             int lineNumber = m_object->lineForPosition(focusedPosition);
2506             if (lineNumber < 0)
2507                 return nil;
2508             
2509             return [NSNumber numberWithInt:lineNumber];
2510         }
2511     }
2512     
2513     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
2514         URL url = m_object->url();
2515         if (url.isNull())
2516             return nil;
2517         return (NSURL*)url;
2518     }
2519
2520     // Only native spin buttons have increment and decrement buttons.
2521     if (is<AccessibilitySpinButton>(*m_object)) {
2522         if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute])
2523             return downcast<AccessibilitySpinButton>(*m_object).incrementButton()->wrapper();
2524         if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute])
2525             return downcast<AccessibilitySpinButton>(*m_object).decrementButton()->wrapper();
2526     }
2527     
2528     if ([attributeName isEqualToString: @"AXVisited"])
2529         return [NSNumber numberWithBool: m_object->isVisited()];
2530     
2531     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
2532         if (m_object->isAttachment()) {
2533             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
2534                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
2535         }
2536         
2537         // Meter elements should communicate their content via AXValueDescription.
2538         if (m_object->isMeter())
2539             return [NSString string];
2540         
2541         // Summary element should use its text node as AXTitle.
2542         if (m_object->isSummary())
2543             return m_object->textUnderElement();
2544         
2545         return [self baseAccessibilityTitle];
2546     }
2547     
2548     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
2549         if (m_object->isAttachment()) {
2550             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
2551                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
2552         }
2553         return [self baseAccessibilityDescription];
2554     }
2555     
2556     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2557         if (m_object->isAttachment()) {
2558             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
2559                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
2560         }
2561         if (m_object->supportsRangeValue())
2562             return [NSNumber numberWithFloat:m_object->valueForRange()];
2563         if (m_object->roleValue() == SliderThumbRole)
2564             return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
2565         if (m_object->isHeading())
2566             return [NSNumber numberWithInt:m_object->headingLevel()];
2567         
2568         if (m_object->isCheckboxOrRadio() || m_object->isMenuItem() || m_object->isSwitch() || m_object->isToggleButton()) {
2569             switch (m_object->checkboxOrRadioValue()) {
2570                 case ButtonStateOff:
2571                     return [NSNumber numberWithInt:0];
2572                 case ButtonStateOn:
2573                     return [NSNumber numberWithInt:1];
2574                 case ButtonStateMixed:
2575                     return [NSNumber numberWithInt:2];
2576             }
2577         }
2578         
2579         // radio groups return the selected radio button as the AXValue
2580         if (m_object->isRadioGroup()) {
2581             AccessibilityObject* radioButton = m_object->selectedRadioButton();
2582             if (!radioButton)
2583                 return nil;
2584             return radioButton->wrapper();
2585         }
2586         
2587         if (m_object->isTabList()) {
2588             AccessibilityObject* tabItem = m_object->selectedTabItem();
2589             if (!tabItem)
2590                 return nil;
2591             return tabItem->wrapper();
2592         }
2593         
2594         if (m_object->isTabItem())
2595             return [NSNumber numberWithInt:m_object->isSelected()];
2596         
2597         if (m_object->isColorWell()) {
2598             int r, g, b;
2599             m_object->colorValue(r, g, b);
2600             return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.];
2601         }
2602         
2603         return m_object->stringValue();
2604     }
2605
2606     if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) {
2607         const unichar ch = 0x2713; // ✓ used on Mac for selected menu items.
2608         return (m_object->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil;
2609     }
2610     
2611     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) {
2612         // Indeterminate progress indicator should return 0.
2613         if (m_object->ariaRoleAttribute() == ProgressIndicatorRole && !m_object->hasAttribute(aria_valuenowAttr))
2614             return @0;
2615         return [NSNumber numberWithFloat:m_object->minValueForRange()];
2616     }
2617     
2618     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) {
2619         // Indeterminate progress indicator should return 0.
2620         if (m_object->ariaRoleAttribute() == ProgressIndicatorRole && !m_object->hasAttribute(aria_valuenowAttr))
2621             return @0;
2622         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
2623     }
2624     
2625     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
2626         return [self baseAccessibilityHelpText];
2627     
2628     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2629         return [NSNumber numberWithBool: m_object->isFocused()];
2630     
2631     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
2632         return [NSNumber numberWithBool: m_object->isEnabled()];
2633     
2634     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
2635         IntSize s = snappedIntRect(m_object->elementRect()).size();
2636         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
2637     }
2638     
2639     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
2640         return [self position];
2641     if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
2642         return [self path];
2643     
2644     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
2645         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
2646         
2647         id remoteParent = [self remoteAccessibilityParentObject];
2648         if (remoteParent)
2649             return [remoteParent accessibilityAttributeValue:attributeName];
2650         
2651         FrameView* fv = m_object->documentFrameView();
2652         if (fv)
2653             return [fv->platformWidget() window];
2654         return nil;
2655     }
2656     
2657     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
2658         AtomicString accessKey = m_object->accessKey();
2659         if (accessKey.isNull())
2660             return nil;
2661         return accessKey;
2662     }
2663     
2664     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
2665         if (m_object->isTabList()) {
2666             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2667             m_object->tabChildren(tabsChildren);
2668             return convertToNSArray(tabsChildren);
2669         }
2670     }
2671     
2672     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
2673         // The contents of a tab list are all the children except the tabs.
2674         if (m_object->isTabList()) {
2675             const auto& children = m_object->children();
2676             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2677             m_object->tabChildren(tabsChildren);
2678             
2679             AccessibilityObject::AccessibilityChildrenVector contents;
2680             unsigned childrenSize = children.size();
2681             for (unsigned k = 0; k < childrenSize; ++k) {
2682                 if (tabsChildren.find(children[k]) == WTF::notFound)
2683                     contents.append(children[k]);
2684             }
2685             return convertToNSArray(contents);
2686         } else if (m_object->isScrollView()) {
2687             // A scrollView's contents are everything except the scroll bars.
2688             AccessibilityObject::AccessibilityChildrenVector contents;
2689             for (const auto& child : m_object->children()) {
2690                 if (!child->isScrollbar())
2691                     contents.append(child);
2692             }
2693             return convertToNSArray(contents);
2694         }
2695     }
2696     
2697     if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility()) {
2698         auto& table = downcast<AccessibilityTable>(*m_object);
2699         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
2700             return convertToNSArray(table.rows());
2701         
2702         if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2703             AccessibilityObject::AccessibilityChildrenVector visibleRows;
2704             table.visibleRows(visibleRows);
2705             return convertToNSArray(visibleRows);
2706         }
2707         
2708         // TODO: distinguish between visible and non-visible columns
2709         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
2710             [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
2711             return convertToNSArray(table.columns());
2712         }
2713         
2714         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2715             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2716             m_object->selectedChildren(selectedChildrenCopy);
2717             return convertToNSArray(selectedChildrenCopy);
2718         }
2719         
2720         // HTML tables don't support these
2721         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
2722             [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
2723             return nil;
2724         
2725         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
2726             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2727             table.columnHeaders(columnHeaders);
2728             return convertToNSArray(columnHeaders);
2729         }
2730         
2731         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2732             AccessibilityObject* headerContainer = table.headerContainer();
2733             if (headerContainer)
2734                 return headerContainer->wrapper();
2735             return nil;
2736         }
2737         
2738         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2739             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2740             table.rowHeaders(rowHeaders);
2741             return convertToNSArray(rowHeaders);
2742         }
2743         
2744         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
2745             AccessibilityObject::AccessibilityChildrenVector cells;
2746             table.cells(cells);
2747             return convertToNSArray(cells);
2748         }
2749         
2750         if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
2751             return @(table.columnCount());
2752         
2753         if ([attributeName isEqualToString:NSAccessibilityRowCountAttribute])
2754             return @(table.rowCount());
2755         
2756         if ([attributeName isEqualToString:NSAccessibilityARIAColumnCountAttribute])
2757             return @(table.ariaColumnCount());
2758         
2759         if ([attributeName isEqualToString:NSAccessibilityARIARowCountAttribute])
2760             return @(table.ariaRowCount());
2761     }
2762     
2763     if (is<AccessibilityTableColumn>(*m_object)) {
2764         auto& column = downcast<AccessibilityTableColumn>(*m_object);
2765         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2766             return [NSNumber numberWithInt:column.columnIndex()];
2767         
2768         // rows attribute for a column is the list of all the elements in that column at each row
2769         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2770             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2771             return convertToNSArray(column.children());
2772         }
2773         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2774             AccessibilityObject* header = column.headerObject();
2775             if (!header)
2776                 return nil;
2777             return header->wrapper();
2778         }
2779     }
2780     
2781     if (is<AccessibilityTableCell>(*m_object)) {
2782         auto& cell = downcast<AccessibilityTableCell>(*m_object);
2783         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
2784             std::pair<unsigned, unsigned> rowRange;
2785             cell.rowIndexRange(rowRange);
2786             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
2787         }
2788         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
2789             std::pair<unsigned, unsigned> columnRange;
2790             cell.columnIndexRange(columnRange);
2791             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
2792         }
2793         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
2794             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2795             cell.columnHeaders(columnHeaders);
2796             return convertToNSArray(columnHeaders);
2797         }
2798         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2799             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2800             cell.rowHeaders(rowHeaders);
2801             return convertToNSArray(rowHeaders);
2802         }
2803         if ([attributeName isEqualToString:NSAccessibilityARIAColumnIndexAttribute])
2804             return @(cell.ariaColumnIndex());
2805         
2806         if ([attributeName isEqualToString:NSAccessibilityARIARowIndexAttribute])
2807             return @(cell.ariaRowIndex());
2808     }
2809     
2810     if (m_object->isTree()) {
2811         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2812             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2813             m_object->selectedChildren(selectedChildrenCopy);
2814             return convertToNSArray(selectedChildrenCopy);
2815         }
2816         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
2817             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2818             m_object->ariaTreeRows(rowsCopy);
2819             return convertToNSArray(rowsCopy);
2820         }
2821         
2822         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
2823         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
2824             return [NSArray array];
2825     }
2826     
2827     if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
2828         if (m_object->isTreeItem()) {
2829             AccessibilityObject* parent = m_object->parentObject();
2830             for (; parent && !parent->isTree(); parent = parent->parentObject())
2831             { }
2832             
2833             if (!parent)
2834                 return nil;
2835             
2836             // Find the index of this item by iterating the parents.
2837             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2838             parent->ariaTreeRows(rowsCopy);
2839             size_t count = rowsCopy.size();
2840             for (size_t k = 0; k < count; ++k)
2841                 if (rowsCopy[k]->wrapper() == self)
2842                     return [NSNumber numberWithUnsignedInt:k];
2843             
2844             return nil;
2845         }
2846         if (is<AccessibilityTableRow>(*m_object)) {
2847             if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2848                 return [NSNumber numberWithInt:downcast<AccessibilityTableRow>(*m_object).rowIndex()];
2849         }
2850     }
2851     
2852     // The rows that are considered inside this row.
2853     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
2854         if (m_object->isTreeItem()) {
2855             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2856             m_object->ariaTreeItemDisclosedRows(rowsCopy);
2857             return convertToNSArray(rowsCopy);
2858         } else if (is<AccessibilityARIAGridRow>(*m_object)) {
2859             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2860             downcast<AccessibilityARIAGridRow>(*m_object).disclosedRows(rowsCopy);
2861             return convertToNSArray(rowsCopy);
2862         }
2863     }
2864     
2865     // The row that contains this row. It should be the same as the first parent that is a treeitem.
2866     if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
2867         if (m_object->isTreeItem()) {
2868             AccessibilityObject* parent = m_object->parentObject();
2869             while (parent) {
2870                 if (parent->isTreeItem())
2871                     return parent->wrapper();
2872                 // If the parent is the tree itself, then this value == nil.
2873                 if (parent->isTree())
2874                     return nil;
2875                 parent = parent->parentObject();
2876             }
2877             return nil;
2878         } else if (is<AccessibilityARIAGridRow>(*m_object)) {
2879             AccessibilityObject* row = downcast<AccessibilityARIAGridRow>(*m_object).disclosedByRow();
2880             if (!row)
2881                 return nil;
2882             return row->wrapper();
2883         }
2884     }
2885     
2886     if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
2887         // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
2888         int level = m_object->hierarchicalLevel();
2889         if (level > 0)
2890             level -= 1;
2891         return [NSNumber numberWithInt:level];
2892     }
2893     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2894         return [NSNumber numberWithBool:m_object->isExpanded()];
2895     
2896     if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
2897         return NSAccessibilityVerticalOrientationValue;
2898     
2899     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2900         return [self textMarkerRangeForSelection];
2901     
2902     if (m_object->renderer()) {
2903         if ([attributeName isEqualToString: @"AXStartTextMarker"])
2904             return [self textMarkerForVisiblePosition:startOfDocument(&m_object->renderer()->document())];
2905         if ([attributeName isEqualToString: @"AXEndTextMarker"])
2906             return [self textMarkerForVisiblePosition:endOfDocument(&m_object->renderer()->document())];
2907     }
2908     
2909     if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
2910         return [NSNumber numberWithUnsignedInt:m_object->blockquoteLevel()];
2911     if ([attributeName isEqualToString:@"AXTableLevel"])
2912         return [NSNumber numberWithInt:m_object->tableLevel()];
2913     
2914     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
2915         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
2916         m_object->linkedUIElements(linkedUIElements);
2917         return convertToNSArray(linkedUIElements);
2918     }
2919     
2920     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2921         return [NSNumber numberWithBool:m_object->isSelected()];
2922     
2923     if ([attributeName isEqualToString: NSAccessibilityARIACurrentAttribute])
2924         return m_object->ariaCurrentValue();
2925     
2926     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2927         AccessibilityObject* uiElement = downcast<AccessibilityRenderObject>(*m_object).menuForMenuButton();
2928         if (uiElement)
2929             return [NSArray arrayWithObject:uiElement->wrapper()];
2930     }
2931     
2932     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2933         if (!m_object->exposesTitleUIElement())
2934             return nil;
2935         
2936         AccessibilityObject* obj = m_object->titleUIElement();
2937         if (obj)
2938             return obj->wrapper();
2939         return nil;
2940     }
2941     
2942     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute]) {
2943         if (m_object->isMeter())
2944             return [self valueDescriptionForMeter];
2945         return m_object->valueDescription();
2946     }
2947     
2948     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2949         AccessibilityOrientation elementOrientation = m_object->orientation();
2950         if (elementOrientation == AccessibilityOrientationVertical)
2951             return NSAccessibilityVerticalOrientationValue;
2952         if (elementOrientation == AccessibilityOrientationHorizontal)
2953             return NSAccessibilityHorizontalOrientationValue;
2954         if (elementOrientation == AccessibilityOrientationUndefined)
2955             return NSAccessibilityUnknownOrientationValue;
2956         return nil;
2957     }
2958     
2959     if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2960         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2961         if (scrollBar)
2962             return scrollBar->wrapper();
2963         return nil;
2964     }
2965     if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2966         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2967         if (scrollBar)
2968             return scrollBar->wrapper();
2969         return nil;
2970     }
2971     
2972     if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2973         switch (m_object->sortDirection()) {
2974             case SortDirectionAscending:
2975                 return NSAccessibilityAscendingSortDirectionValue;
2976             case SortDirectionDescending:
2977                 return NSAccessibilityDescendingSortDirectionValue;
2978             default:
2979                 return NSAccessibilityUnknownSortDirectionValue;
2980         }
2981     }
2982     
2983     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2984         return m_object->language();
2985     
2986     if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2987         return [NSNumber numberWithBool:m_object->isExpanded()];
2988     
2989     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2990         return [NSNumber numberWithBool:m_object->isRequired()];
2991     
2992     if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2993         return m_object->invalidStatus();
2994     
2995     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2996         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2997         m_object->ariaOwnsElements(ariaOwns);
2998         return convertToNSArray(ariaOwns);
2999     }
3000     
3001     if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
3002         return [NSNumber numberWithInt:m_object->ariaPosInSet()];
3003     if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute])
3004         return [NSNumber numberWithInt:m_object->ariaSetSize()];
3005     
3006     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
3007         return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
3008     
3009     if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
3010         Vector<String> dropEffects;
3011         m_object->determineARIADropEffects(dropEffects);
3012         return convertStringsToNSArray(dropEffects);
3013     }
3014     
3015     if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
3016         return m_object->placeholderValue();
3017
3018     if ([attributeName isEqualToString:NSAccessibilityValueAutofillAvailableAttribute])
3019         return @(m_object->isValueAutofillAvailable());
3020     
3021     if ([attributeName isEqualToString:NSAccessibilityValueAutofillTypeAttribute]) {
3022         switch (m_object->valueAutofillButtonType()) {
3023         case AutoFillButtonType::None:
3024             return @"none";
3025         case AutoFillButtonType::Credentials:
3026             return @"credentials";
3027         case AutoFillButtonType::Contacts:
3028             return @"contacts";
3029         }
3030     }
3031     
3032     if ([attributeName isEqualToString:NSAccessibilityValueAutofilledAttribute])
3033         return @(m_object->isValueAutofilled());
3034
3035     if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
3036         return [NSNumber numberWithBool:m_object->ariaHasPopup()];
3037     
3038     // ARIA Live region attributes.
3039     if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
3040         return m_object->ariaLiveRegionStatus();
3041     if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
3042         return m_object->ariaLiveRegionRelevant();
3043     if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
3044         return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
3045     if ([attributeName isEqualToString:NSAccessibilityElementBusyAttribute])
3046         return [NSNumber numberWithBool:m_object->isBusy()];
3047     
3048     // MathML Attributes.
3049     if (m_object->isMathElement()) {
3050         if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute])
3051             return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0;
3052         if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute])
3053             return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0;
3054         if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
3055             return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0;
3056         if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
3057             return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0;
3058         if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
3059             return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0;
3060         if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
3061             return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0;
3062         if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])