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