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