805004aa88aa754ed08f74be7aa3046f9875e884
[WebKit-https.git] / Source / WebCore / accessibility / mac / WebAccessibilityObjectWrapperMac.mm
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "config.h"
30 #import "WebAccessibilityObjectWrapperMac.h"
31
32 #if HAVE(ACCESSIBILITY)
33
34 #import "AXObjectCache.h"
35 #import "AccessibilityARIAGridRow.h"
36 #import "AccessibilityList.h"
37 #import "AccessibilityListBox.h"
38 #import "AccessibilityRenderObject.h"
39 #import "AccessibilityScrollView.h"
40 #import "AccessibilitySpinButton.h"
41 #import "AccessibilityTable.h"
42 #import "AccessibilityTableCell.h"
43 #import "AccessibilityTableColumn.h"
44 #import "AccessibilityTableRow.h"
45 #import "Chrome.h"
46 #import "ChromeClient.h"
47 #import "ColorMac.h"
48 #import "ContextMenuController.h"
49 #import "Editor.h"
50 #import "Font.h"
51 #import "FontCascade.h"
52 #import "FrameLoaderClient.h"
53 #import "FrameSelection.h"
54 #import "HTMLAnchorElement.h"
55 #import "HTMLAreaElement.h"
56 #import "HTMLFrameOwnerElement.h"
57 #import "HTMLImageElement.h"
58 #import "HTMLInputElement.h"
59 #import "HTMLNames.h"
60 #import "HTMLTextAreaElement.h"
61 #import "LocalizedStrings.h"
62 #import "MainFrame.h"
63 #import "Page.h"
64 #import "RenderTextControl.h"
65 #import "RenderView.h"
66 #import "RenderWidget.h"
67 #import "ScrollView.h"
68 #import "TextCheckerClient.h"
69 #import "TextCheckingHelper.h"
70 #import "TextIterator.h"
71 #import "VisibleUnits.h"
72 #import "WebCoreFrameView.h"
73 #import "WebCoreObjCExtras.h"
74 #import "WebCoreSystemInterface.h"
75 #import "htmlediting.h"
76 #import <wtf/ObjcRuntimeExtras.h>
77
78 using namespace WebCore;
79 using namespace HTMLNames;
80
81 // Cell Tables
82 #ifndef NSAccessibilitySelectedCellsAttribute
83 #define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
84 #endif
85
86 #ifndef NSAccessibilityVisibleCellsAttribute
87 #define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
88 #endif
89
90 #ifndef NSAccessibilityRowIndexRangeAttribute
91 #define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
92 #endif
93
94 #ifndef NSAccessibilityColumnIndexRangeAttribute
95 #define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
96 #endif
97
98 #ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
99 #define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
100 #endif
101
102 #ifndef NSAccessibilityCellRole
103 #define NSAccessibilityCellRole @"AXCell"
104 #endif
105
106 // Lists
107 #ifndef NSAccessibilityContentListSubrole
108 #define NSAccessibilityContentListSubrole @"AXContentList"
109 #endif
110
111 #ifndef NSAccessibilityDefinitionListSubrole
112 #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
113 #endif
114
115 #ifndef NSAccessibilityDescriptionListSubrole
116 #define NSAccessibilityDescriptionListSubrole @"AXDescriptionList"
117 #endif
118
119 #ifndef NSAccessibilityContentSeparatorSubrole
120 #define NSAccessibilityContentSeparatorSubrole @"AXContentSeparator"
121 #endif
122
123 // Miscellaneous
124 #ifndef NSAccessibilityBlockQuoteLevelAttribute
125 #define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
126 #endif
127
128 #ifndef NSAccessibilityAccessKeyAttribute
129 #define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
130 #endif
131
132 #ifndef NSAccessibilityValueAutofilledAttribute
133 #define NSAccessibilityValueAutofilledAttribute @"AXValueAutofilled"
134 #endif
135
136 #ifndef NSAccessibilityLanguageAttribute
137 #define NSAccessibilityLanguageAttribute @"AXLanguage"
138 #endif
139
140 #ifndef NSAccessibilityRequiredAttribute
141 #define NSAccessibilityRequiredAttribute @"AXRequired"
142 #endif
143
144 #ifndef NSAccessibilityInvalidAttribute
145 #define NSAccessibilityInvalidAttribute @"AXInvalid"
146 #endif
147
148 #ifndef NSAccessibilityOwnsAttribute
149 #define NSAccessibilityOwnsAttribute @"AXOwns"
150 #endif
151
152 #ifndef NSAccessibilityGrabbedAttribute
153 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
154 #endif
155
156 #ifndef NSAccessibilityDropEffectsAttribute
157 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
158 #endif
159
160 #ifndef NSAccessibilityARIALiveAttribute
161 #define NSAccessibilityARIALiveAttribute @"AXARIALive"
162 #endif
163
164 #ifndef NSAccessibilityARIAAtomicAttribute
165 #define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
166 #endif
167
168 #ifndef NSAccessibilityARIARelevantAttribute
169 #define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
170 #endif
171
172 #ifndef NSAccessibilityElementBusyAttribute
173 #define NSAccessibilityElementBusyAttribute @"AXElementBusy"
174 #endif
175
176 #ifndef NSAccessibilityARIAPosInSetAttribute
177 #define NSAccessibilityARIAPosInSetAttribute @"AXARIAPosInSet"
178 #endif
179
180 #ifndef NSAccessibilityARIASetSizeAttribute
181 #define NSAccessibilityARIASetSizeAttribute @"AXARIASetSize"
182 #endif
183
184 #ifndef NSAccessibilityLoadingProgressAttribute
185 #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
186 #endif
187
188 #ifndef NSAccessibilityHasPopupAttribute
189 #define NSAccessibilityHasPopupAttribute @"AXHasPopup"
190 #endif
191
192 #ifndef NSAccessibilityPlaceholderValueAttribute
193 #define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
194 #endif
195
196 #define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid"
197 #define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
198 #define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
199
200 #ifndef NSAccessibilityScrollToVisibleAction
201 #define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
202 #endif
203
204 #ifndef NSAccessibilityPathAttribute
205 #define NSAccessibilityPathAttribute @"AXPath"
206 #endif
207
208 #ifndef NSAccessibilityExpandedTextValueAttribute
209 #define NSAccessibilityExpandedTextValueAttribute @"AXExpandedTextValue"
210 #endif
211
212 #define NSAccessibilityDOMIdentifierAttribute @"AXDOMIdentifier"
213 #define NSAccessibilityDOMClassListAttribute @"AXDOMClassList"
214
215 // Search
216 #ifndef NSAccessibilityImmediateDescendantsOnly
217 #define NSAccessibilityImmediateDescendantsOnly @"AXImmediateDescendantsOnly"
218 #endif
219
220 #ifndef NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
221 #define NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute @"AXUIElementCountForSearchPredicate"
222 #endif
223
224 #ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute
225 #define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate"
226 #endif
227
228 // Search Keys
229 #ifndef NSAccessibilityAnyTypeSearchKey
230 #define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey"
231 #endif
232
233 #ifndef NSAccessibilityBlockquoteSameLevelSearchKey
234 #define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey"
235 #endif
236
237 #ifndef NSAccessibilityBlockquoteSearchKey
238 #define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey"
239 #endif
240
241 #ifndef NSAccessibilityBoldFontSearchKey
242 #define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey"
243 #endif
244
245 #ifndef NSAccessibilityButtonSearchKey
246 #define NSAccessibilityButtonSearchKey @"AXButtonSearchKey"
247 #endif
248
249 #ifndef NSAccessibilityCheckBoxSearchKey
250 #define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey"
251 #endif
252
253 #ifndef NSAccessibilityControlSearchKey
254 #define NSAccessibilityControlSearchKey @"AXControlSearchKey"
255 #endif
256
257 #ifndef NSAccessibilityDifferentTypeSearchKey
258 #define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey"
259 #endif
260
261 #ifndef NSAccessibilityFontChangeSearchKey
262 #define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey"
263 #endif
264
265 #ifndef NSAccessibilityFontColorChangeSearchKey
266 #define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey"
267 #endif
268
269 #ifndef NSAccessibilityFrameSearchKey
270 #define NSAccessibilityFrameSearchKey @"AXFrameSearchKey"
271 #endif
272
273 #ifndef NSAccessibilityGraphicSearchKey
274 #define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey"
275 #endif
276
277 #ifndef NSAccessibilityHeadingLevel1SearchKey
278 #define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey"
279 #endif
280
281 #ifndef NSAccessibilityHeadingLevel2SearchKey
282 #define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey"
283 #endif
284
285 #ifndef NSAccessibilityHeadingLevel3SearchKey
286 #define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey"
287 #endif
288
289 #ifndef NSAccessibilityHeadingLevel4SearchKey
290 #define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey"
291 #endif
292
293 #ifndef NSAccessibilityHeadingLevel5SearchKey
294 #define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey"
295 #endif
296
297 #ifndef NSAccessibilityHeadingLevel6SearchKey
298 #define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey"
299 #endif
300
301 #ifndef NSAccessibilityHeadingSameLevelSearchKey
302 #define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey"
303 #endif
304
305 #ifndef NSAccessibilityHeadingSearchKey
306 #define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey"
307 #endif
308
309 #ifndef NSAccessibilityHighlightedSearchKey
310 #define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey"
311 #endif
312
313 #ifndef NSAccessibilityItalicFontSearchKey
314 #define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey"
315 #endif
316
317 #ifndef NSAccessibilityLandmarkSearchKey
318 #define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey"
319 #endif
320
321 #ifndef NSAccessibilityLinkSearchKey
322 #define NSAccessibilityLinkSearchKey @"AXLinkSearchKey"
323 #endif
324
325 #ifndef NSAccessibilityListSearchKey
326 #define NSAccessibilityListSearchKey @"AXListSearchKey"
327 #endif
328
329 #ifndef NSAccessibilityLiveRegionSearchKey
330 #define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey"
331 #endif
332
333 #ifndef NSAccessibilityMisspelledWordSearchKey
334 #define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey"
335 #endif
336
337 #ifndef NSAccessibilityOutlineSearchKey
338 #define NSAccessibilityOutlineSearchKey @"AXOutlineSearchKey"
339 #endif
340
341 #ifndef NSAccessibilityPlainTextSearchKey
342 #define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey"
343 #endif
344
345 #ifndef NSAccessibilityRadioGroupSearchKey
346 #define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey"
347 #endif
348
349 #ifndef NSAccessibilitySameTypeSearchKey
350 #define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey"
351 #endif
352
353 #ifndef NSAccessibilityStaticTextSearchKey
354 #define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey"
355 #endif
356
357 #ifndef NSAccessibilityStyleChangeSearchKey
358 #define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey"
359 #endif
360
361 #ifndef NSAccessibilityTableSameLevelSearchKey
362 #define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey"
363 #endif
364
365 #ifndef NSAccessibilityTableSearchKey
366 #define NSAccessibilityTableSearchKey @"AXTableSearchKey"
367 #endif
368
369 #ifndef NSAccessibilityTextFieldSearchKey
370 #define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey"
371 #endif
372
373 #ifndef NSAccessibilityUnderlineSearchKey
374 #define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey"
375 #endif
376
377 #ifndef NSAccessibilityUnvisitedLinkSearchKey
378 #define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey"
379 #endif
380
381 #ifndef NSAccessibilityVisitedLinkSearchKey
382 #define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey"
383 #endif
384
385 // Text markers
386 #ifndef NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute
387 #define NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute @"AXEndTextMarkerForBounds"
388 #endif
389
390 #ifndef NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute
391 #define NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute @"AXStartTextMarkerForBounds"
392 #endif
393
394 #ifndef NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute
395 #define NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute @"AXLineTextMarkerRangeForTextMarker"
396 #endif
397
398 // Text selection
399 #ifndef NSAccessibilitySelectTextActivity
400 #define NSAccessibilitySelectTextActivity @"AXSelectTextActivity"
401 #endif
402
403 #ifndef NSAccessibilitySelectTextActivityFindAndReplace
404 #define NSAccessibilitySelectTextActivityFindAndReplace @"AXSelectTextActivityFindAndReplace"
405 #endif
406
407 #ifndef NSAccessibilitySelectTextActivityFindAndSelect
408 #define NSAccessibilitySelectTextActivityFindAndSelect @"AXSelectTextActivityFindAndSelect"
409 #endif
410
411 #ifndef kAXSelectTextActivityFindAndCapitalize
412 #define kAXSelectTextActivityFindAndCapitalize @"AXSelectTextActivityFindAndCapitalize"
413 #endif
414
415 #ifndef kAXSelectTextActivityFindAndLowercase
416 #define kAXSelectTextActivityFindAndLowercase @"AXSelectTextActivityFindAndLowercase"
417 #endif
418
419 #ifndef kAXSelectTextActivityFindAndUppercase
420 #define kAXSelectTextActivityFindAndUppercase @"AXSelectTextActivityFindAndUppercase"
421 #endif
422
423 #ifndef NSAccessibilitySelectTextAmbiguityResolution
424 #define NSAccessibilitySelectTextAmbiguityResolution @"AXSelectTextAmbiguityResolution"
425 #endif
426
427 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection
428 #define NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection @"AXSelectTextAmbiguityResolutionClosestAfterSelection"
429 #endif
430
431 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection
432 #define NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection @"AXSelectTextAmbiguityResolutionClosestBeforeSelection"
433 #endif
434
435 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection
436 #define NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection @"AXSelectTextAmbiguityResolutionClosestToSelection"
437 #endif
438
439 #ifndef NSAccessibilitySelectTextReplacementString
440 #define NSAccessibilitySelectTextReplacementString @"AXSelectTextReplacementString"
441 #endif
442
443 #ifndef NSAccessibilitySelectTextSearchStrings
444 #define NSAccessibilitySelectTextSearchStrings @"AXSelectTextSearchStrings"
445 #endif
446
447 #ifndef NSAccessibilitySelectTextWithCriteriaParameterizedAttribute
448 #define NSAccessibilitySelectTextWithCriteriaParameterizedAttribute @"AXSelectTextWithCriteria"
449 #endif
450
451 // Math attributes
452 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
453 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
454 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
455 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
456 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
457 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
458 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
459 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
460 #define NSAccessibilityMathOverAttribute @"AXMathOver"
461 #define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
462 #define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
463 #define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
464 #define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
465 #define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
466
467 @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.fontCascade().primaryFont().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         // FIXME: Should the underline style be reported here?
886         Color underlineColor, overlineColor, linethroughColor;
887         TextDecorationStyle underlineStyle, overlineStyle, linethroughStyle;
888         renderer->getTextDecorationColorsAndStyles(decor, underlineColor, overlineColor, linethroughColor, underlineStyle, overlineStyle, linethroughStyle);
889         
890         if ((decor & TextDecorationUnderline) != 0) {
891             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
892             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underlineColor), range);
893         }
894         
895         if ((decor & TextDecorationLineThrough) != 0) {
896             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
897             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethroughColor), 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)
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)
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)
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     static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
1151
1152     // Action elements allow Press.
1153     // 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.
1154     static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
1155
1156     // Menu elements allow Press and Cancel.
1157     static NSArray *menuElementActions = [[actionElementActions arrayByAddingObject:NSAccessibilityCancelAction] retain];
1158
1159     // Slider elements allow Increment/Decrement.
1160     static NSArray *sliderActions = [[defaultElementActions arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]] retain];
1161     
1162     NSArray *actions;
1163     if (m_object->supportsPressAction())
1164         actions = actionElementActions;
1165     else if (m_object->isMenuRelated())
1166         actions = menuElementActions;
1167     else if (m_object->isSlider())
1168         actions = sliderActions;
1169     else if (m_object->isAttachment())
1170         actions = [[self attachmentView] accessibilityActionNames];
1171     else
1172         actions = defaultElementActions;
1173     
1174     return actions;
1175 }
1176
1177 - (NSArray*)additionalAccessibilityAttributeNames
1178 {
1179     if (!m_object)
1180         return nil;
1181     
1182     NSMutableArray *additional = [NSMutableArray array];
1183     if (m_object->supportsARIAOwns())
1184         [additional addObject:NSAccessibilityOwnsAttribute];
1185     
1186     if (m_object->supportsARIAExpanded())
1187         [additional addObject:NSAccessibilityExpandedAttribute];
1188     
1189     if (m_object->isScrollbar())
1190         [additional addObject:NSAccessibilityOrientationAttribute];
1191     
1192     if (m_object->supportsARIADragging())
1193         [additional addObject:NSAccessibilityGrabbedAttribute];
1194     
1195     if (m_object->supportsARIADropping())
1196         [additional addObject:NSAccessibilityDropEffectsAttribute];
1197     
1198     if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility() && downcast<AccessibilityTable>(*m_object).supportsSelectedRows())
1199         [additional addObject:NSAccessibilitySelectedRowsAttribute];
1200     
1201     if (m_object->supportsARIALiveRegion()) {
1202         [additional addObject:NSAccessibilityARIALiveAttribute];
1203         [additional addObject:NSAccessibilityARIARelevantAttribute];
1204     }
1205     
1206     if (m_object->supportsARIASetSize())
1207         [additional addObject:NSAccessibilityARIASetSizeAttribute];
1208     if (m_object->supportsARIAPosInSet())
1209         [additional addObject:NSAccessibilityARIAPosInSetAttribute];
1210     
1211     if (m_object->sortDirection() != SortDirectionNone)
1212         [additional addObject:NSAccessibilitySortDirectionAttribute];
1213     
1214     // If an object is a child of a live region, then add these
1215     if (m_object->isInsideARIALiveRegion())
1216         [additional addObject:NSAccessibilityARIAAtomicAttribute];
1217     // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
1218     [additional addObject:NSAccessibilityElementBusyAttribute];
1219     
1220     // Popup buttons on the Mac expose the value attribute.
1221     if (m_object->isPopUpButton()) {
1222         [additional addObject:NSAccessibilityValueAttribute];
1223     }
1224
1225     if (m_object->supportsRequiredAttribute()) {
1226         [additional addObject:NSAccessibilityRequiredAttribute];
1227     }
1228     
1229     if (m_object->ariaHasPopup())
1230         [additional addObject:NSAccessibilityHasPopupAttribute];
1231     
1232     if (m_object->isMathRoot()) {
1233         // The index of a square root is always known, so there's no object associated with it.
1234         if (!m_object->isMathSquareRoot())
1235             [additional addObject:NSAccessibilityMathRootIndexAttribute];
1236         [additional addObject:NSAccessibilityMathRootRadicandAttribute];
1237     } else if (m_object->isMathFraction()) {
1238         [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
1239         [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
1240         [additional addObject:NSAccessibilityMathLineThicknessAttribute];
1241     } else if (m_object->isMathSubscriptSuperscript()) {
1242         [additional addObject:NSAccessibilityMathBaseAttribute];
1243         [additional addObject:NSAccessibilityMathSubscriptAttribute];
1244         [additional addObject:NSAccessibilityMathSuperscriptAttribute];
1245     } else if (m_object->isMathUnderOver()) {
1246         [additional addObject:NSAccessibilityMathBaseAttribute];
1247         [additional addObject:NSAccessibilityMathUnderAttribute];
1248         [additional addObject:NSAccessibilityMathOverAttribute];
1249     } else if (m_object->isMathFenced()) {
1250         [additional addObject:NSAccessibilityMathFencedOpenAttribute];
1251         [additional addObject:NSAccessibilityMathFencedCloseAttribute];
1252     } else if (m_object->isMathMultiscript()) {
1253         [additional addObject:NSAccessibilityMathBaseAttribute];
1254         [additional addObject:NSAccessibilityMathPrescriptsAttribute];
1255         [additional addObject:NSAccessibilityMathPostscriptsAttribute];
1256     }
1257     
1258     if (m_object->supportsPath())
1259         [additional addObject:NSAccessibilityPathAttribute];
1260     
1261     if (m_object->supportsExpandedTextValue())
1262         [additional addObject:NSAccessibilityExpandedTextValueAttribute];
1263     
1264     return additional;
1265 }
1266
1267 - (NSArray*)accessibilityAttributeNames
1268 {
1269     if (![self updateObjectBackingStore])
1270         return nil;
1271     
1272     if (m_object->isAttachment())
1273         return [[self attachmentView] accessibilityAttributeNames];
1274     
1275     static NSArray* attributes = nil;
1276     static NSArray* anchorAttrs = nil;
1277     static NSArray* webAreaAttrs = nil;
1278     static NSArray* textAttrs = nil;
1279     static NSArray* listAttrs = nil;
1280     static NSArray* listBoxAttrs = nil;
1281     static NSArray* rangeAttrs = nil;
1282     static NSArray* commonMenuAttrs = nil;
1283     static NSArray* menuAttrs = nil;
1284     static NSArray* menuBarAttrs = nil;
1285     static NSArray* menuItemAttrs = nil;
1286     static NSArray* menuButtonAttrs = nil;
1287     static NSArray* controlAttrs = nil;
1288     static NSArray* tableAttrs = nil;
1289     static NSArray* tableRowAttrs = nil;
1290     static NSArray* tableColAttrs = nil;
1291     static NSArray* tableCellAttrs = nil;
1292     static NSArray* groupAttrs = nil;
1293     static NSArray* inputImageAttrs = nil;
1294     static NSArray* passwordFieldAttrs = nil;
1295     static NSArray* tabListAttrs = nil;
1296     static NSArray* comboBoxAttrs = nil;
1297     static NSArray* outlineAttrs = nil;
1298     static NSArray* outlineRowAttrs = nil;
1299     static NSArray* buttonAttrs = nil;
1300     static NSArray* scrollViewAttrs = nil;
1301     static NSArray* incrementorAttrs = nil;
1302     NSMutableArray* tempArray;
1303     if (attributes == nil) {
1304         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1305                       NSAccessibilitySubroleAttribute,
1306                       NSAccessibilityRoleDescriptionAttribute,
1307                       NSAccessibilityChildrenAttribute,
1308                       NSAccessibilityHelpAttribute,
1309                       NSAccessibilityParentAttribute,
1310                       NSAccessibilityPositionAttribute,
1311                       NSAccessibilitySizeAttribute,
1312                       NSAccessibilityTitleAttribute,
1313                       NSAccessibilityDescriptionAttribute,
1314                       NSAccessibilityValueAttribute,
1315                       NSAccessibilityFocusedAttribute,
1316                       NSAccessibilityEnabledAttribute,
1317                       NSAccessibilityWindowAttribute,
1318                       @"AXSelectedTextMarkerRange",
1319                       @"AXStartTextMarker",
1320                       @"AXEndTextMarker",
1321                       @"AXVisited",
1322                       NSAccessibilityLinkedUIElementsAttribute,
1323                       NSAccessibilitySelectedAttribute,
1324                       NSAccessibilityBlockQuoteLevelAttribute,
1325                       NSAccessibilityTopLevelUIElementAttribute,
1326                       NSAccessibilityLanguageAttribute,
1327                       NSAccessibilityDOMIdentifierAttribute,
1328                       NSAccessibilityDOMClassListAttribute,
1329                       nil];
1330     }
1331     if (commonMenuAttrs == nil) {
1332         commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1333                            NSAccessibilityRoleDescriptionAttribute,
1334                            NSAccessibilityChildrenAttribute,
1335                            NSAccessibilityParentAttribute,
1336                            NSAccessibilityEnabledAttribute,
1337                            NSAccessibilityPositionAttribute,
1338                            NSAccessibilitySizeAttribute,
1339                            nil];
1340     }
1341     if (anchorAttrs == nil) {
1342         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1343         [tempArray addObject:NSAccessibilityURLAttribute];
1344         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1345         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
1346         [tempArray release];
1347     }
1348     if (webAreaAttrs == nil) {
1349         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1350         // WebAreas should not expose AXSubrole.
1351         [tempArray removeObject:NSAccessibilitySubroleAttribute];
1352         [tempArray addObject:@"AXLinkUIElements"];
1353         [tempArray addObject:@"AXLoaded"];
1354         [tempArray addObject:@"AXLayoutCount"];
1355         [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
1356         [tempArray addObject:NSAccessibilityURLAttribute];
1357         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
1358         [tempArray release];
1359     }
1360     if (textAttrs == nil) {
1361         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1362         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
1363         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
1364         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
1365         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
1366         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
1367         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1368         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1369         [tempArray addObject:NSAccessibilityRequiredAttribute];
1370         [tempArray addObject:NSAccessibilityInvalidAttribute];
1371         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1372         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1373         textAttrs = [[NSArray alloc] initWithArray:tempArray];
1374         [tempArray release];
1375     }
1376     if (listAttrs == nil) {
1377         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1378         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1379         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1380         [tempArray addObject:NSAccessibilityOrientationAttribute];
1381         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1382         listAttrs = [[NSArray alloc] initWithArray:tempArray];
1383         [tempArray release];
1384     }
1385     if (listBoxAttrs == nil) {
1386         tempArray = [[NSMutableArray alloc] initWithArray:listAttrs];
1387         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1388         [tempArray addObject:NSAccessibilityRequiredAttribute];
1389         [tempArray addObject:NSAccessibilityInvalidAttribute];
1390         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1391         [tempArray release];
1392     }
1393     if (rangeAttrs == nil) {
1394         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1395         [tempArray addObject:NSAccessibilityMinValueAttribute];
1396         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1397         [tempArray addObject:NSAccessibilityOrientationAttribute];
1398         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1399         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1400         rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
1401         [tempArray release];
1402     }
1403     if (menuBarAttrs == nil) {
1404         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1405         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1406         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1407         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1408         menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
1409         [tempArray release];
1410     }
1411     if (menuAttrs == nil) {
1412         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1413         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1414         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1415         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1416         menuAttrs = [[NSArray alloc] initWithArray:tempArray];
1417         [tempArray release];
1418     }
1419     if (menuItemAttrs == nil) {
1420         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1421         [tempArray addObject:NSAccessibilityTitleAttribute];
1422         [tempArray addObject:NSAccessibilityDescriptionAttribute];
1423         [tempArray addObject:NSAccessibilityHelpAttribute];
1424         [tempArray addObject:NSAccessibilitySelectedAttribute];
1425         [tempArray addObject:NSAccessibilityValueAttribute];
1426         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
1427         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
1428         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
1429         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
1430         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
1431         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
1432         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
1433         [tempArray addObject:NSAccessibilityFocusedAttribute];
1434         menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
1435         [tempArray release];
1436     }
1437     if (menuButtonAttrs == nil) {
1438         menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
1439                            NSAccessibilityRoleDescriptionAttribute,
1440                            NSAccessibilityParentAttribute,
1441                            NSAccessibilityPositionAttribute,
1442                            NSAccessibilitySizeAttribute,
1443                            NSAccessibilityWindowAttribute,
1444                            NSAccessibilityEnabledAttribute,
1445                            NSAccessibilityFocusedAttribute,
1446                            NSAccessibilityTitleAttribute,
1447                            NSAccessibilityChildrenAttribute, nil];
1448     }
1449     if (controlAttrs == nil) {
1450         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1451         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1452         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1453         [tempArray addObject:NSAccessibilityRequiredAttribute];
1454         [tempArray addObject:NSAccessibilityInvalidAttribute];
1455         controlAttrs = [[NSArray alloc] initWithArray:tempArray];
1456         [tempArray release];
1457     }
1458     if (incrementorAttrs == nil) {
1459         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1460         [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
1461         [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
1462         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1463         [tempArray addObject:NSAccessibilityMinValueAttribute];
1464         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1465         incrementorAttrs = [[NSArray alloc] initWithArray:tempArray];
1466         [tempArray release];
1467     }
1468     if (buttonAttrs == nil) {
1469         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1470         // Buttons should not expose AXValue.
1471         [tempArray removeObject:NSAccessibilityValueAttribute];
1472         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1473         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1474         buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
1475         [tempArray release];
1476     }
1477     if (comboBoxAttrs == nil) {
1478         tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
1479         [tempArray addObject:NSAccessibilityExpandedAttribute];
1480         comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1481         [tempArray release];
1482     }
1483     if (tableAttrs == nil) {
1484         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1485         [tempArray addObject:NSAccessibilityRowsAttribute];
1486         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1487         [tempArray addObject:NSAccessibilityColumnsAttribute];
1488         [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
1489         [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
1490         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1491         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1492         [tempArray addObject:NSAccessibilityHeaderAttribute];
1493         [tempArray addObject:NSAccessibilityColumnCountAttribute];
1494         [tempArray addObject:NSAccessibilityRowCountAttribute];
1495         tableAttrs = [[NSArray alloc] initWithArray:tempArray];
1496         [tempArray release];
1497     }
1498     if (tableRowAttrs == nil) {
1499         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1500         [tempArray addObject:NSAccessibilityIndexAttribute];
1501         tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1502         [tempArray release];
1503     }
1504     if (tableColAttrs == nil) {
1505         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1506         [tempArray addObject:NSAccessibilityIndexAttribute];
1507         [tempArray addObject:NSAccessibilityHeaderAttribute];
1508         [tempArray addObject:NSAccessibilityRowsAttribute];
1509         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1510         tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
1511         [tempArray release];
1512     }
1513     if (tableCellAttrs == nil) {
1514         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1515         [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
1516         [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
1517         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1518         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1519         tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
1520         [tempArray release];
1521     }
1522     if (groupAttrs == nil) {
1523         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1524         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1525         groupAttrs = [[NSArray alloc] initWithArray:tempArray];
1526         [tempArray release];
1527     }
1528     if (inputImageAttrs == nil) {
1529         tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
1530         [tempArray addObject:NSAccessibilityURLAttribute];
1531         inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
1532         [tempArray release];
1533     }
1534     if (passwordFieldAttrs == nil) {
1535         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1536         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1537         [tempArray addObject:NSAccessibilityRequiredAttribute];
1538         [tempArray addObject:NSAccessibilityInvalidAttribute];
1539         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1540         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1541         passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
1542         [tempArray release];
1543     }
1544     if (tabListAttrs == nil) {
1545         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1546         [tempArray addObject:NSAccessibilityTabsAttribute];
1547         [tempArray addObject:NSAccessibilityContentsAttribute];
1548         tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
1549         [tempArray release];
1550     }
1551     if (outlineAttrs == nil) {
1552         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1553         [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
1554         [tempArray addObject:NSAccessibilityRowsAttribute];
1555         [tempArray addObject:NSAccessibilityColumnsAttribute];
1556         outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
1557         [tempArray release];
1558     }
1559     if (outlineRowAttrs == nil) {
1560         tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
1561         [tempArray addObject:NSAccessibilityDisclosingAttribute];
1562         [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
1563         [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
1564         [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1565         outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1566         [tempArray release];
1567     }
1568     if (scrollViewAttrs == nil) {
1569         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1570         [tempArray addObject:NSAccessibilityContentsAttribute];
1571         [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1572         [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1573         scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray];
1574         [tempArray release];
1575     }
1576     
1577     NSArray *objectAttributes = attributes;
1578     
1579     if (m_object->isPasswordField())
1580         objectAttributes = passwordFieldAttrs;
1581     
1582     else if (m_object->isWebArea())
1583         objectAttributes = webAreaAttrs;
1584     
1585     else if (m_object->isTextControl())
1586         objectAttributes = textAttrs;
1587     
1588     else if (m_object->isLink() || m_object->isImage())
1589         objectAttributes = anchorAttrs;
1590     
1591     else if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility())
1592         objectAttributes = tableAttrs;
1593     else if (m_object->isTableColumn())
1594         objectAttributes = tableColAttrs;
1595     else if (m_object->isTableCell())
1596         objectAttributes = tableCellAttrs;
1597     else if (m_object->isTableRow()) {
1598         // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1599         if (m_object->isARIATreeGridRow())
1600             objectAttributes = outlineRowAttrs;
1601         else
1602             objectAttributes = tableRowAttrs;
1603     }
1604     
1605     else if (m_object->isTree())
1606         objectAttributes = outlineAttrs;
1607     else if (m_object->isTreeItem())
1608         objectAttributes = outlineRowAttrs;
1609     
1610     else if (m_object->isListBox())
1611         objectAttributes = listBoxAttrs;
1612     else if (m_object->isList())
1613         objectAttributes = listAttrs;
1614     
1615     else if (m_object->isComboBox())
1616         objectAttributes = comboBoxAttrs;
1617     
1618     else if (m_object->isProgressIndicator() || m_object->isSlider())
1619         objectAttributes = rangeAttrs;
1620     
1621     // These are processed in order because an input image is a button, and a button is a control.
1622     else if (m_object->isInputImage())
1623         objectAttributes = inputImageAttrs;
1624     else if (m_object->isButton())
1625         objectAttributes = buttonAttrs;
1626     else if (m_object->isControl())
1627         objectAttributes = controlAttrs;
1628     
1629     else if (m_object->isGroup() || m_object->isListItem())
1630         objectAttributes = groupAttrs;
1631     else if (m_object->isTabList())
1632         objectAttributes = tabListAttrs;
1633     else if (m_object->isScrollView())
1634         objectAttributes = scrollViewAttrs;
1635     else if (m_object->isSpinButton())
1636         objectAttributes = incrementorAttrs;
1637     
1638     else if (m_object->isMenu())
1639         objectAttributes = menuAttrs;
1640     else if (m_object->isMenuBar())
1641         objectAttributes = menuBarAttrs;
1642     else if (m_object->isMenuButton())
1643         objectAttributes = menuButtonAttrs;
1644     else if (m_object->isMenuItem())
1645         objectAttributes = menuItemAttrs;
1646     
1647     NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1648     if ([additionalAttributes count])
1649         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1650     
1651     return objectAttributes;
1652 }
1653
1654 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange
1655 {
1656     if (!textMarkerRange)
1657         return VisiblePositionRange();
1658     AXObjectCache* cache = m_object->axObjectCache();
1659     return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1660 }
1661
1662 - (NSArray*)renderWidgetChildren
1663 {
1664     Widget* widget = m_object->widget();
1665     if (!widget)
1666         return nil;
1667 #pragma clang diagnostic push
1668 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1669     return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1670 #pragma clang diagnostic pop
1671 }
1672
1673 - (id)remoteAccessibilityParentObject
1674 {
1675     if (!m_object)
1676         return nil;
1677     
1678     Document* document = m_object->document();
1679     if (!document)
1680         return nil;
1681     
1682     Frame* frame = document->frame();
1683     if (!frame)
1684         return nil;
1685     
1686     return frame->loader().client().accessibilityRemoteObject();
1687 }
1688
1689 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1690 {
1691     unsigned length = [array count];
1692     vector.reserveInitialCapacity(length);
1693     for (unsigned i = 0; i < length; ++i) {
1694         AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1695         if (obj)
1696             vector.append(obj);
1697     }
1698 }
1699
1700 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1701 {
1702     NSMutableArray* array = [NSMutableArray arrayWithCapacity:vector.size()];
1703     for (const auto& child : vector) {
1704         WebAccessibilityObjectWrapper* wrapper = child->wrapper();
1705         ASSERT(wrapper);
1706         if (wrapper) {
1707             // we want to return the attachment view instead of the object representing the attachment.
1708             // otherwise, we get palindrome errors in the AX hierarchy
1709             if (child->isAttachment() && [wrapper attachmentView])
1710                 [array addObject:[wrapper attachmentView]];
1711             else
1712                 [array addObject:wrapper];
1713         }
1714     }
1715     return array;
1716 }
1717
1718 static NSMutableArray *convertStringsToNSArray(const Vector<String>& vector)
1719 {
1720     NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
1721     for (const auto& string : vector)
1722         [array addObject:string];
1723     return array;
1724 }
1725
1726 - (id)textMarkerRangeForSelection
1727 {
1728     VisibleSelection selection = m_object->selection();
1729     if (selection.isNone())
1730         return nil;
1731     return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1732 }
1733
1734 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1735 {
1736     FrameView* frameView = m_object->documentFrameView();
1737     
1738     // WebKit1 code path... platformWidget() exists.
1739     if (frameView && frameView->platformWidget()) {
1740         NSPoint nsPoint = (NSPoint)point;
1741         NSView* view = frameView->documentView();
1742 #pragma clang diagnostic push
1743 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1744         nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]];
1745 #pragma clang diagnostic pop
1746         return CGPointMake(nsPoint.x, nsPoint.y);
1747     } else {
1748         
1749         // Find the appropriate scroll view to use to convert the contents to the window.
1750         ScrollView* scrollView = nullptr;
1751         AccessibilityObject* parent = nullptr;
1752         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1753             if (is<AccessibilityScrollView>(*parent)) {
1754                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1755                 break;
1756             }
1757         }
1758         
1759         IntPoint intPoint = flooredIntPoint(point);
1760         if (scrollView)
1761             intPoint = scrollView->contentsToRootView(intPoint);
1762         
1763         Page* page = m_object->page();
1764         
1765         // If we have an empty chrome client (like SVG) then we should use the page
1766         // of the scroll view parent to help us get to the screen rect.
1767         if (parent && page && page->chrome().client().isEmptyChromeClient())
1768             page = parent->page();
1769         
1770         if (page) {
1771             IntRect rect = IntRect(intPoint, IntSize(0, 0));            
1772             intPoint = page->chrome().rootViewToScreen(rect).location();
1773         }
1774         
1775         return intPoint;
1776     }
1777 }
1778
1779 static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element)
1780 {
1781     NSBezierPath *bezierPath = (NSBezierPath *)info;
1782     switch (element->type) {
1783     case kCGPathElementMoveToPoint:
1784         [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])];
1785         break;
1786     case kCGPathElementAddLineToPoint:
1787         [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])];
1788         break;
1789     case kCGPathElementAddCurveToPoint:
1790         [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])];
1791         break;
1792     case kCGPathElementCloseSubpath:
1793         [bezierPath closePath];
1794         break;
1795     default:
1796         break;
1797     }
1798 }
1799
1800 - (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1801 {
1802     NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1803     CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath);
1804     return bezierPath;
1805 }
1806
1807 - (NSBezierPath *)path
1808 {
1809     Path path = m_object->elementPath();
1810     if (path.isEmpty())
1811         return NULL;
1812     
1813     CGPathRef transformedPath = [self convertPathToScreenSpace:path];
1814     return [self bezierPathFromPath:transformedPath];
1815 }
1816
1817 - (NSValue *)position
1818 {
1819     IntRect rect = snappedIntRect(m_object->elementRect());
1820     
1821     // The Cocoa accessibility API wants the lower-left corner.
1822     FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY());
1823
1824     CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint];
1825     
1826     return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)];
1827 }
1828
1829 typedef HashMap<int, NSString*> AccessibilityRoleMap;
1830
1831 static const AccessibilityRoleMap& createAccessibilityRoleMap()
1832 {
1833     struct RoleEntry {
1834         AccessibilityRole value;
1835         NSString* string;
1836     };
1837     
1838     static const RoleEntry roles[] = {
1839         { UnknownRole, NSAccessibilityUnknownRole },
1840         { ButtonRole, NSAccessibilityButtonRole },
1841         { RadioButtonRole, NSAccessibilityRadioButtonRole },
1842         { CheckBoxRole, NSAccessibilityCheckBoxRole },
1843         { SliderRole, NSAccessibilitySliderRole },
1844         { TabGroupRole, NSAccessibilityTabGroupRole },
1845         { TextFieldRole, NSAccessibilityTextFieldRole },
1846         { StaticTextRole, NSAccessibilityStaticTextRole },
1847         { TextAreaRole, NSAccessibilityTextAreaRole },
1848         { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1849         { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1850         { MenuButtonRole, NSAccessibilityMenuButtonRole },
1851         { TableRole, NSAccessibilityTableRole },
1852         { ApplicationRole, NSAccessibilityApplicationRole },
1853         { GroupRole, NSAccessibilityGroupRole },
1854         { RadioGroupRole, NSAccessibilityRadioGroupRole },
1855         { ListRole, NSAccessibilityListRole },
1856         { DirectoryRole, NSAccessibilityListRole },
1857         { ScrollBarRole, NSAccessibilityScrollBarRole },
1858         { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1859         { ImageRole, NSAccessibilityImageRole },
1860         { MenuBarRole, NSAccessibilityMenuBarRole },
1861         { MenuRole, NSAccessibilityMenuRole },
1862         { MenuItemRole, NSAccessibilityMenuItemRole },
1863         { MenuItemCheckboxRole, NSAccessibilityMenuItemRole },
1864         { MenuItemRadioRole, NSAccessibilityMenuItemRole },
1865         { ColumnRole, NSAccessibilityColumnRole },
1866         { RowRole, NSAccessibilityRowRole },
1867         { ToolbarRole, NSAccessibilityToolbarRole },
1868         { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1869         { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1870         { WindowRole, NSAccessibilityWindowRole },
1871         { DrawerRole, NSAccessibilityDrawerRole },
1872         { SystemWideRole, NSAccessibilitySystemWideRole },
1873         { OutlineRole, NSAccessibilityOutlineRole },
1874         { IncrementorRole, NSAccessibilityIncrementorRole },
1875         { BrowserRole, NSAccessibilityBrowserRole },
1876         { ComboBoxRole, NSAccessibilityComboBoxRole },
1877         { SplitGroupRole, NSAccessibilitySplitGroupRole },
1878         { SplitterRole, NSAccessibilitySplitterRole },
1879         { ColorWellRole, NSAccessibilityColorWellRole },
1880         { GrowAreaRole, NSAccessibilityGrowAreaRole },
1881         { SheetRole, NSAccessibilitySheetRole },
1882         { HelpTagRole, NSAccessibilityHelpTagRole },
1883         { MatteRole, NSAccessibilityMatteRole },
1884         { RulerRole, NSAccessibilityRulerRole },
1885         { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1886         { LinkRole, NSAccessibilityLinkRole },
1887         { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1888         { GridRole, NSAccessibilityGridRole },
1889         { WebCoreLinkRole, NSAccessibilityLinkRole },
1890         { ImageMapLinkRole, NSAccessibilityLinkRole },
1891         { ImageMapRole, @"AXImageMap" },
1892         { ListMarkerRole, @"AXListMarker" },
1893         { WebAreaRole, @"AXWebArea" },
1894         { HeadingRole, @"AXHeading" },
1895         { ListBoxRole, NSAccessibilityListRole },
1896         { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1897         { CellRole, NSAccessibilityCellRole },
1898         { TableHeaderContainerRole, NSAccessibilityGroupRole },
1899         { RowHeaderRole, NSAccessibilityGroupRole },
1900         { DefinitionRole, NSAccessibilityGroupRole },
1901         { DescriptionListDetailRole, NSAccessibilityGroupRole },
1902         { DescriptionListTermRole, NSAccessibilityGroupRole },
1903         { DescriptionListRole, NSAccessibilityListRole },
1904         { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1905         { LandmarkApplicationRole, NSAccessibilityGroupRole },
1906         { LandmarkBannerRole, NSAccessibilityGroupRole },
1907         { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1908         { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1909         { LandmarkMainRole, NSAccessibilityGroupRole },
1910         { LandmarkNavigationRole, NSAccessibilityGroupRole },
1911         { LandmarkSearchRole, NSAccessibilityGroupRole },
1912         { ApplicationAlertRole, NSAccessibilityGroupRole },
1913         { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1914         { ApplicationDialogRole, NSAccessibilityGroupRole },
1915         { ApplicationLogRole, NSAccessibilityGroupRole },
1916         { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1917         { ApplicationStatusRole, NSAccessibilityGroupRole },
1918         { ApplicationTimerRole, NSAccessibilityGroupRole },
1919         { DocumentRole, NSAccessibilityGroupRole },
1920         { DocumentArticleRole, NSAccessibilityGroupRole },
1921         { DocumentMathRole, NSAccessibilityGroupRole },
1922         { DocumentNoteRole, NSAccessibilityGroupRole },
1923         { DocumentRegionRole, NSAccessibilityGroupRole },
1924         { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1925         { TabRole, NSAccessibilityRadioButtonRole },
1926         { TabListRole, NSAccessibilityTabGroupRole },
1927         { TabPanelRole, NSAccessibilityGroupRole },
1928         { TreeRole, NSAccessibilityOutlineRole },
1929         { TreeItemRole, NSAccessibilityRowRole },
1930         { ListItemRole, NSAccessibilityGroupRole },
1931         { ParagraphRole, NSAccessibilityGroupRole },
1932         { LabelRole, NSAccessibilityGroupRole },
1933         { DivRole, NSAccessibilityGroupRole },
1934         { FormRole, NSAccessibilityGroupRole },
1935         { SpinButtonRole, NSAccessibilityIncrementorRole },
1936         { FooterRole, NSAccessibilityGroupRole },
1937         { ToggleButtonRole, NSAccessibilityButtonRole },
1938         { CanvasRole, NSAccessibilityImageRole },
1939         { SVGRootRole, NSAccessibilityGroupRole },
1940         { LegendRole, NSAccessibilityGroupRole },
1941         { MathElementRole, NSAccessibilityGroupRole },
1942         { AudioRole, NSAccessibilityGroupRole },
1943         { VideoRole, NSAccessibilityGroupRole },
1944         { HorizontalRuleRole, NSAccessibilitySplitterRole },
1945         { BlockquoteRole, NSAccessibilityGroupRole }
1946     };
1947     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1948     
1949     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1950     for (unsigned i = 0; i < numRoles; ++i)
1951         roleMap.set(roles[i].value, roles[i].string);
1952     return roleMap;
1953 }
1954
1955 static NSString* roleValueToNSString(AccessibilityRole value)
1956 {
1957     ASSERT(value);
1958     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1959     return roleMap.get(value);
1960 }
1961
1962 - (NSString*)role
1963 {
1964 #pragma clang diagnostic push
1965 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1966     if (m_object->isAttachment())
1967         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1968 #pragma clang diagnostic pop
1969     AccessibilityRole role = m_object->roleValue();
1970     if (role == CanvasRole && m_object->canvasHasFallbackContent())
1971         role = GroupRole;
1972     NSString* string = roleValueToNSString(role);
1973     if (string != nil)
1974         return string;
1975     return NSAccessibilityUnknownRole;
1976 }
1977
1978 #pragma clang diagnostic push
1979 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1980 - (NSString*)subrole
1981 {
1982     if (m_object->isPasswordField())
1983         return NSAccessibilitySecureTextFieldSubrole;
1984     if (m_object->isSearchField())
1985         return NSAccessibilitySearchFieldSubrole;
1986     
1987     if (m_object->isAttachment()) {
1988         NSView* attachView = [self attachmentView];
1989         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1990             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1991         }
1992     }
1993     
1994     if (m_object->roleValue() == HorizontalRuleRole)
1995         return NSAccessibilityContentSeparatorSubrole;
1996     
1997     if (is<AccessibilitySpinButtonPart>(*m_object)) {
1998         if (downcast<AccessibilitySpinButtonPart>(*m_object).isIncrementor())
1999             return NSAccessibilityIncrementArrowSubrole;
2000         
2001         return NSAccessibilityDecrementArrowSubrole;
2002     }
2003     
2004     if (m_object->isFileUploadButton())
2005         return @"AXFileUploadButton";
2006     
2007     if (m_object->isTreeItem())
2008         return NSAccessibilityOutlineRowSubrole;
2009     
2010     if (is<AccessibilityList>(*m_object)) {
2011         auto& listObject = downcast<AccessibilityList>(*m_object);
2012         if (listObject.isUnorderedList() || listObject.isOrderedList())
2013             return NSAccessibilityContentListSubrole;
2014         if (listObject.isDescriptionList()) {
2015             return NSAccessibilityDescriptionListSubrole;
2016         }
2017     }
2018     
2019     // ARIA content subroles.
2020     switch (m_object->roleValue()) {
2021         case LandmarkApplicationRole:
2022             return @"AXLandmarkApplication";
2023         case LandmarkBannerRole:
2024             return @"AXLandmarkBanner";
2025         case LandmarkComplementaryRole:
2026             return @"AXLandmarkComplementary";
2027             // Footer roles should appear as content info types.
2028         case FooterRole:
2029         case LandmarkContentInfoRole:
2030             return @"AXLandmarkContentInfo";
2031         case LandmarkMainRole:
2032             return @"AXLandmarkMain";
2033         case LandmarkNavigationRole:
2034             return @"AXLandmarkNavigation";
2035         case LandmarkSearchRole:
2036             return @"AXLandmarkSearch";
2037         case ApplicationAlertRole:
2038             return @"AXApplicationAlert";
2039         case ApplicationAlertDialogRole:
2040             return @"AXApplicationAlertDialog";
2041         case ApplicationDialogRole:
2042             return @"AXApplicationDialog";
2043         case ApplicationLogRole:
2044             return @"AXApplicationLog";
2045         case ApplicationMarqueeRole:
2046             return @"AXApplicationMarquee";
2047         case ApplicationStatusRole:
2048             return @"AXApplicationStatus";
2049         case ApplicationTimerRole:
2050             return @"AXApplicationTimer";
2051         case DocumentRole:
2052             return @"AXDocument";
2053         case DocumentArticleRole:
2054             return @"AXDocumentArticle";
2055         case DocumentMathRole:
2056             return @"AXDocumentMath";
2057         case DocumentNoteRole:
2058             return @"AXDocumentNote";
2059         case DocumentRegionRole:
2060             return @"AXDocumentRegion";
2061         case UserInterfaceTooltipRole:
2062             return @"AXUserInterfaceTooltip";
2063         case TabPanelRole:
2064             return @"AXTabPanel";
2065         case DefinitionRole:
2066             return @"AXDefinition";
2067         case DescriptionListTermRole:
2068             return @"AXTerm";
2069         case DescriptionListDetailRole:
2070             return @"AXDescription";
2071             // Default doesn't return anything, so roles defined below can be chosen.
2072         default:
2073             break;
2074     }
2075     
2076     if (m_object->roleValue() == MathElementRole) {
2077         if (m_object->isMathFraction())
2078             return @"AXMathFraction";
2079         if (m_object->isMathFenced())
2080             return @"AXMathFenced";
2081         if (m_object->isMathSubscriptSuperscript())
2082             return @"AXMathSubscriptSuperscript";
2083         if (m_object->isMathRow())
2084             return @"AXMathRow";
2085         if (m_object->isMathUnderOver())
2086             return @"AXMathUnderOver";
2087         if (m_object->isMathSquareRoot())
2088             return @"AXMathSquareRoot";
2089         if (m_object->isMathRoot())
2090             return @"AXMathRoot";
2091         if (m_object->isMathText())
2092             return @"AXMathText";
2093         if (m_object->isMathNumber())
2094             return @"AXMathNumber";
2095         if (m_object->isMathIdentifier())
2096             return @"AXMathIdentifier";
2097         if (m_object->isMathTable())
2098             return @"AXMathTable";
2099         if (m_object->isMathTableRow())
2100             return @"AXMathTableRow";
2101         if (m_object->isMathTableCell())
2102             return @"AXMathTableCell";
2103         if (m_object->isMathFenceOperator())
2104             return @"AXMathFenceOperator";
2105         if (m_object->isMathSeparatorOperator())
2106             return @"AXMathSeparatorOperator";
2107         if (m_object->isMathOperator())
2108             return @"AXMathOperator";
2109         if (m_object->isMathMultiscript())
2110             return @"AXMathMultiscript";
2111     }
2112     
2113     if (m_object->roleValue() == VideoRole)
2114         return @"AXVideo";
2115     if (m_object->roleValue() == AudioRole)
2116         return @"AXAudio";
2117     
2118     if (m_object->isMediaTimeline())
2119         return NSAccessibilityTimelineSubrole;
2120     
2121     return nil;
2122 }
2123 #pragma clang diagnostic pop
2124
2125 - (NSString*)roleDescription
2126 {
2127     if (!m_object)
2128         return nil;
2129
2130 #pragma clang diagnostic push
2131 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2132     // attachments have the AXImage role, but a different subrole
2133     if (m_object->isAttachment())
2134         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
2135 #pragma clang diagnostic pop
2136
2137     NSString* axRole = [self role];
2138     
2139     if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
2140         
2141         NSString *ariaLandmarkRoleDescription = [self ariaLandmarkRoleDescription];
2142         if (ariaLandmarkRoleDescription)
2143             return ariaLandmarkRoleDescription;
2144         
2145         switch (m_object->roleValue()) {
2146         case AudioRole:
2147             return localizedMediaControlElementString("AudioElement");
2148         case DefinitionRole:
2149             return AXDefinitionText();
2150         case DescriptionListTermRole:
2151             return AXDescriptionListTermText();
2152         case DescriptionListDetailRole:
2153             return AXDescriptionListDetailText();
2154         case FooterRole:
2155             return AXFooterRoleDescriptionText();
2156         case VideoRole:
2157             return localizedMediaControlElementString("VideoElement");
2158         default:
2159             return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
2160         }
2161     }
2162     
2163     if ([axRole isEqualToString:@"AXWebArea"])
2164         return AXWebAreaText();
2165     
2166     if ([axRole isEqualToString:@"AXLink"])
2167         return AXLinkText();
2168     
2169     if ([axRole isEqualToString:@"AXListMarker"])
2170         return AXListMarkerText();
2171     
2172     if ([axRole isEqualToString:@"AXImageMap"])
2173         return AXImageMapText();
2174     
2175     if ([axRole isEqualToString:@"AXHeading"])
2176         return AXHeadingText();
2177     
2178     if (m_object->isFileUploadButton())
2179         return AXFileUploadButtonText();
2180     
2181     // Only returning for DL (not UL or OL) because description changed with HTML5 from 'definition list' to
2182     // superset 'description list' and does not return the same values in AX API on some OS versions. 
2183     if (is<AccessibilityList>(*m_object)) {
2184         if (downcast<AccessibilityList>(*m_object).isDescriptionList())
2185             return AXDescriptionListText();
2186     }
2187     
2188     if (m_object->roleValue() == HorizontalRuleRole)
2189         return AXHorizontalRuleDescriptionText();
2190     
2191     // AppKit also returns AXTab for the role description for a tab item.
2192     if (m_object->isTabItem())
2193         return NSAccessibilityRoleDescription(@"AXTab", nil);
2194     
2195     // We should try the system default role description for all other roles.
2196     // If we get the same string back, then as a last resort, return unknown.
2197     NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
2198     
2199     // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description
2200     // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions
2201     // we should fallback on a role description ignoring the subrole in these cases.
2202     if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, [self subrole]]])
2203         defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil);
2204     
2205     if (![defaultRoleDescription isEqualToString:axRole])
2206         return defaultRoleDescription;
2207     
2208     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
2209 }
2210
2211 - (NSString *)computedRoleString
2212 {
2213     if (!m_object)
2214         return nil;
2215     return m_object->computedRoleString();
2216 }
2217
2218 - (id)scrollViewParent
2219 {
2220     if (!is<AccessibilityScrollView>(m_object))
2221         return nil;
2222     
2223     // If this scroll view provides it's parent object (because it's a sub-frame), then
2224     // we should not find the remoteAccessibilityParent.
2225     if (m_object->parentObject())
2226         return nil;
2227     
2228     ScrollView* scroll = downcast<AccessibilityScrollView>(*m_object).scrollView();
2229     if (!scroll)
2230         return nil;
2231     
2232     if (scroll->platformWidget())
2233         return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
2234     
2235     return [self remoteAccessibilityParentObject];
2236 }
2237
2238 // FIXME: split up this function in a better way.
2239 // suggestions: Use a hash table that maps attribute names to function calls,
2240 // or maybe pointers to member functions
2241 - (id)accessibilityAttributeValue:(NSString*)attributeName
2242 {
2243     if (![self updateObjectBackingStore])
2244         return nil;
2245     
2246     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
2247         return [self role];
2248     
2249     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
2250         return [self subrole];
2251     
2252     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
2253         return [self roleDescription];
2254
2255     // AXARIARole is only used by DumpRenderTree (so far).
2256     if ([attributeName isEqualToString:@"AXARIARole"])
2257         return [self computedRoleString];
2258     
2259     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
2260         
2261         // This will return the parent of the AXWebArea, if this is a web area.
2262         id scrollViewParent = [self scrollViewParent];
2263         if (scrollViewParent)
2264             return scrollViewParent;
2265         
2266         // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
2267         if (m_object->isTreeItem()) {
2268             AccessibilityObject* parent = m_object->parentObjectUnignored();
2269             while (parent) {
2270                 if (parent->isTree())
2271                     return parent->wrapper();
2272                 parent = parent->parentObjectUnignored();
2273             }
2274         }
2275         
2276         AccessibilityObject* parent = m_object->parentObjectUnignored();
2277         if (!parent)
2278             return nil;
2279         
2280         // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
2281         // should be reported directly as such.
2282         if (m_object->isWebArea() && parent->isAttachment())
2283             return [parent->wrapper() attachmentView];
2284         
2285         return parent->wrapper();
2286     }
2287     
2288     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
2289         if (m_object->children().isEmpty()) {
2290             NSArray* children = [self renderWidgetChildren];
2291             if (children != nil)
2292                 return children;
2293         }
2294         
2295         // The tree's (AXOutline) children are supposed to be its rows and columns.
2296         // The ARIA spec doesn't have columns, so we just need rows.
2297         if (m_object->isTree())
2298             return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
2299         
2300         // A tree item should only expose its content as its children (not its rows)
2301         if (m_object->isTreeItem()) {
2302             AccessibilityObject::AccessibilityChildrenVector contentCopy;
2303             m_object->ariaTreeItemContent(contentCopy);
2304             return convertToNSArray(contentCopy);
2305         }
2306         
2307         return convertToNSArray(m_object->children());
2308     }
2309     
2310     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2311         if (m_object->isListBox()) {
2312             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2313             m_object->selectedChildren(selectedChildrenCopy);
2314             return convertToNSArray(selectedChildrenCopy);
2315         }
2316         return nil;
2317     }
2318     
2319     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
2320         if (m_object->isListBox()) {
2321             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
2322             m_object->visibleChildren(visibleChildrenCopy);
2323             return convertToNSArray(visibleChildrenCopy);
2324         }
2325         else if (m_object->isList())
2326             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
2327         
2328         return nil;
2329     }
2330     
2331     
2332     if (m_object->isWebArea()) {
2333         if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
2334             AccessibilityObject::AccessibilityChildrenVector links;
2335             downcast<AccessibilityRenderObject>(*m_object).getDocumentLinks(links);
2336             return convertToNSArray(links);
2337         }
2338         if ([attributeName isEqualToString:@"AXLoaded"])
2339             return [NSNumber numberWithBool:m_object->isLoaded()];
2340         if ([attributeName isEqualToString:@"AXLayoutCount"])
2341             return [NSNumber numberWithInt:m_object->layoutCount()];
2342         if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
2343             return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
2344     }
2345     
2346     if (m_object->isTextControl()) {
2347         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
2348             int length = m_object->textLength();
2349             if (length < 0)
2350                 return nil;
2351             return [NSNumber numberWithUnsignedInt:length];
2352         }
2353         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2354             String selectedText = m_object->selectedText();
2355             if (selectedText.isNull())
2356                 return nil;
2357             return (NSString*)selectedText;
2358         }
2359         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2360             PlainTextRange textRange = m_object->selectedTextRange();
2361             if (textRange.isNull())
2362                 return [NSValue valueWithRange:NSMakeRange(0, 0)];
2363             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
2364         }
2365         // TODO: Get actual visible range. <rdar://problem/4712101>
2366         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2367             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
2368         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
2369             // if selectionEnd > 0, then there is selected text and this question should not be answered
2370             if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
2371                 return nil;
2372             
2373             AccessibilityObject* focusedObject = m_object->focusedUIElement();
2374             if (focusedObject != m_object)
2375                 return nil;
2376             
2377             VisiblePosition focusedPosition = focusedObject->visiblePositionForIndex(focusedObject->selectionStart(), true);
2378             int lineNumber = m_object->lineForPosition(focusedPosition);
2379             if (lineNumber < 0)
2380                 return nil;
2381             
2382             return [NSNumber numberWithInt:lineNumber];
2383         }
2384     }
2385     
2386     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
2387         URL url = m_object->url();
2388         if (url.isNull())
2389             return nil;
2390         return (NSURL*)url;
2391     }
2392
2393     // Only native spin buttons have increment and decrement buttons.
2394     if (is<AccessibilitySpinButton>(*m_object)) {
2395         if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute])
2396             return downcast<AccessibilitySpinButton>(*m_object).incrementButton()->wrapper();
2397         if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute])
2398             return downcast<AccessibilitySpinButton>(*m_object).decrementButton()->wrapper();
2399     }
2400     
2401     if ([attributeName isEqualToString: @"AXVisited"])
2402         return [NSNumber numberWithBool: m_object->isVisited()];
2403     
2404     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
2405         if (m_object->isAttachment()) {
2406             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
2407                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
2408         }
2409         
2410         // Meter elements should communicate their content via AXValueDescription.
2411         if (m_object->isMeter())
2412             return [NSString string];
2413         
2414         return [self baseAccessibilityTitle];
2415     }
2416     
2417     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
2418         if (m_object->isAttachment()) {
2419             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
2420                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
2421         }
2422         return [self baseAccessibilityDescription];
2423     }
2424     
2425     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2426         if (m_object->isAttachment()) {
2427             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
2428                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
2429         }
2430         if (m_object->supportsRangeValue())
2431             return [NSNumber numberWithFloat:m_object->valueForRange()];
2432         if (m_object->roleValue() == SliderThumbRole)
2433             return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
2434         if (m_object->isHeading())
2435             return [NSNumber numberWithInt:m_object->headingLevel()];
2436         
2437         if (m_object->isCheckboxOrRadio() || m_object->isMenuItem()) {
2438             switch (m_object->checkboxOrRadioValue()) {
2439                 case ButtonStateOff:
2440                     return [NSNumber numberWithInt:0];
2441                 case ButtonStateOn:
2442                     return [NSNumber numberWithInt:1];
2443                 case ButtonStateMixed:
2444                     return [NSNumber numberWithInt:2];
2445             }
2446         }
2447         
2448         // radio groups return the selected radio button as the AXValue
2449         if (m_object->isRadioGroup()) {
2450             AccessibilityObject* radioButton = m_object->selectedRadioButton();
2451             if (!radioButton)
2452                 return nil;
2453             return radioButton->wrapper();
2454         }
2455         
2456         if (m_object->isTabList()) {
2457             AccessibilityObject* tabItem = m_object->selectedTabItem();
2458             if (!tabItem)
2459                 return nil;
2460             return tabItem->wrapper();
2461         }
2462         
2463         if (m_object->isTabItem())
2464             return [NSNumber numberWithInt:m_object->isSelected()];
2465         
2466         if (m_object->isColorWell()) {
2467             int r, g, b;
2468             m_object->colorValue(r, g, b);
2469             return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.];
2470         }
2471         
2472         return m_object->stringValue();
2473     }
2474
2475     if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) {
2476         const unichar ch = 0x2713; // ✓ used on Mac for selected menu items.
2477         return (m_object->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil;
2478     }
2479
2480     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
2481         return [NSNumber numberWithFloat:m_object->minValueForRange()];
2482     
2483     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
2484         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
2485     
2486     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
2487         return [self baseAccessibilityHelpText];
2488     
2489     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2490         return [NSNumber numberWithBool: m_object->isFocused()];
2491     
2492     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
2493         return [NSNumber numberWithBool: m_object->isEnabled()];
2494     
2495     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
2496         IntSize s = m_object->elementRect().pixelSnappedSize();
2497         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
2498     }
2499     
2500     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
2501         return [self position];
2502     if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
2503         return [self path];
2504     
2505     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
2506         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
2507         
2508         id remoteParent = [self remoteAccessibilityParentObject];
2509         if (remoteParent)
2510             return [remoteParent accessibilityAttributeValue:attributeName];
2511         
2512         FrameView* fv = m_object->documentFrameView();
2513         if (fv)
2514             return [fv->platformWidget() window];
2515         return nil;
2516     }
2517     
2518     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
2519         AtomicString accessKey = m_object->accessKey();
2520         if (accessKey.isNull())
2521             return nil;
2522         return accessKey;
2523     }
2524     
2525     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
2526         if (m_object->isTabList()) {
2527             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2528             m_object->tabChildren(tabsChildren);
2529             return convertToNSArray(tabsChildren);
2530         }
2531     }
2532     
2533     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
2534         // The contents of a tab list are all the children except the tabs.
2535         if (m_object->isTabList()) {
2536             const auto& children = m_object->children();
2537             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2538             m_object->tabChildren(tabsChildren);
2539             
2540             AccessibilityObject::AccessibilityChildrenVector contents;
2541             unsigned childrenSize = children.size();
2542             for (unsigned k = 0; k < childrenSize; ++k) {
2543                 if (tabsChildren.find(children[k]) == WTF::notFound)
2544                     contents.append(children[k]);
2545             }
2546             return convertToNSArray(contents);
2547         } else if (m_object->isScrollView()) {
2548             // A scrollView's contents are everything except the scroll bars.
2549             AccessibilityObject::AccessibilityChildrenVector contents;
2550             for (const auto& child : m_object->children()) {
2551                 if (!child->isScrollbar())
2552                     contents.append(child);
2553             }
2554             return convertToNSArray(contents);
2555         }
2556     }
2557     
2558     if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility()) {
2559         auto& table = downcast<AccessibilityTable>(*m_object);
2560         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
2561             return convertToNSArray(table.rows());
2562         
2563         if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2564             AccessibilityObject::AccessibilityChildrenVector visibleRows;
2565             table.visibleRows(visibleRows);
2566             return convertToNSArray(visibleRows);
2567         }
2568         
2569         // TODO: distinguish between visible and non-visible columns
2570         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
2571             [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
2572             return convertToNSArray(table.columns());
2573         }
2574         
2575         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2576             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2577             m_object->selectedChildren(selectedChildrenCopy);
2578             return convertToNSArray(selectedChildrenCopy);
2579         }
2580         
2581         // HTML tables don't support these
2582         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
2583             [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
2584             return nil;
2585         
2586         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
2587             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2588             table.columnHeaders(columnHeaders);
2589             return convertToNSArray(columnHeaders);
2590         }
2591         
2592         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2593             AccessibilityObject* headerContainer = table.headerContainer();
2594             if (headerContainer)
2595                 return headerContainer->wrapper();
2596             return nil;
2597         }
2598         
2599         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2600             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2601             table.rowHeaders(rowHeaders);
2602             return convertToNSArray(rowHeaders);
2603         }
2604         
2605         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
2606             AccessibilityObject::AccessibilityChildrenVector cells;
2607             table.cells(cells);
2608             return convertToNSArray(cells);
2609         }
2610         
2611         if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
2612             return @(table.columnCount());
2613         
2614         if ([attributeName isEqualToString:NSAccessibilityRowCountAttribute])
2615             return @(table.rowCount());
2616     }
2617     
2618     if (is<AccessibilityTableColumn>(*m_object)) {
2619         auto& column = downcast<AccessibilityTableColumn>(*m_object);
2620         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2621             return [NSNumber numberWithInt:column.columnIndex()];
2622         
2623         // rows attribute for a column is the list of all the elements in that column at each row
2624         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2625             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2626             return convertToNSArray(column.children());
2627         }
2628         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2629             AccessibilityObject* header = column.headerObject();
2630             if (!header)
2631                 return nil;
2632             return header->wrapper();
2633         }
2634     }
2635     
2636     if (is<AccessibilityTableCell>(*m_object)) {
2637         auto& cell = downcast<AccessibilityTableCell>(*m_object);
2638         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
2639             std::pair<unsigned, unsigned> rowRange;
2640             cell.rowIndexRange(rowRange);
2641             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
2642         }
2643         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
2644             std::pair<unsigned, unsigned> columnRange;
2645             cell.columnIndexRange(columnRange);
2646             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
2647         }
2648         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
2649             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2650             cell.columnHeaders(columnHeaders);
2651             return convertToNSArray(columnHeaders);
2652         }
2653         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2654             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2655             cell.rowHeaders(rowHeaders);
2656             return convertToNSArray(rowHeaders);
2657         }
2658     }
2659     
2660     if (m_object->isTree()) {
2661         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2662             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2663             m_object->selectedChildren(selectedChildrenCopy);
2664             return convertToNSArray(selectedChildrenCopy);
2665         }
2666         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
2667             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2668             m_object->ariaTreeRows(rowsCopy);
2669             return convertToNSArray(rowsCopy);
2670         }
2671         
2672         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
2673         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
2674             return [NSArray array];
2675     }
2676     
2677     if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
2678         if (m_object->isTreeItem()) {
2679             AccessibilityObject* parent = m_object->parentObject();
2680             for (; parent && !parent->isTree(); parent = parent->parentObject())
2681             { }
2682             
2683             if (!parent)
2684                 return nil;
2685             
2686             // Find the index of this item by iterating the parents.
2687             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2688             parent->ariaTreeRows(rowsCopy);
2689             size_t count = rowsCopy.size();
2690             for (size_t k = 0; k < count; ++k)
2691                 if (rowsCopy[k]->wrapper() == self)
2692                     return [NSNumber numberWithUnsignedInt:k];
2693             
2694             return nil;
2695         }
2696         if (is<AccessibilityTableRow>(*m_object)) {
2697             if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2698                 return [NSNumber numberWithInt:downcast<AccessibilityTableRow>(*m_object).rowIndex()];
2699         }
2700     }
2701     
2702     // The rows that are considered inside this row.
2703     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
2704         if (m_object->isTreeItem()) {
2705             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2706             m_object->ariaTreeItemDisclosedRows(rowsCopy);
2707             return convertToNSArray(rowsCopy);
2708         } else if (is<AccessibilityARIAGridRow>(*m_object)) {
2709             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2710             downcast<AccessibilityARIAGridRow>(*m_object).disclosedRows(rowsCopy);
2711             return convertToNSArray(rowsCopy);
2712         }
2713     }
2714     
2715     // The row that contains this row. It should be the same as the first parent that is a treeitem.
2716     if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
2717         if (m_object->isTreeItem()) {
2718             AccessibilityObject* parent = m_object->parentObject();
2719             while (parent) {
2720                 if (parent->isTreeItem())
2721                     return parent->wrapper();
2722                 // If the parent is the tree itself, then this value == nil.
2723                 if (parent->isTree())
2724                     return nil;
2725                 parent = parent->parentObject();
2726             }
2727             return nil;
2728         } else if (is<AccessibilityARIAGridRow>(*m_object)) {
2729             AccessibilityObject* row = downcast<AccessibilityARIAGridRow>(*m_object).disclosedByRow();
2730             if (!row)
2731                 return nil;
2732             return row->wrapper();
2733         }
2734     }
2735     
2736     if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
2737         // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
2738         int level = m_object->hierarchicalLevel();
2739         if (level > 0)
2740             level -= 1;
2741         return [NSNumber numberWithInt:level];
2742     }
2743     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2744         return [NSNumber numberWithBool:m_object->isExpanded()];
2745     
2746     if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
2747         return NSAccessibilityVerticalOrientationValue;
2748     
2749     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2750         return [self textMarkerRangeForSelection];
2751     
2752     if (m_object->renderer()) {
2753         if ([attributeName isEqualToString: @"AXStartTextMarker"])
2754             return [self textMarkerForVisiblePosition:startOfDocument(&m_object->renderer()->document())];
2755         if ([attributeName isEqualToString: @"AXEndTextMarker"])
2756             return [self textMarkerForVisiblePosition:endOfDocument(&m_object->renderer()->document())];
2757     }
2758     
2759     if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
2760         return [NSNumber numberWithInt:m_object->blockquoteLevel()];
2761     if ([attributeName isEqualToString:@"AXTableLevel"])
2762         return [NSNumber numberWithInt:m_object->tableLevel()];
2763     
2764     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
2765         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
2766         m_object->linkedUIElements(linkedUIElements);
2767         return convertToNSArray(linkedUIElements);
2768     }
2769     
2770     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2771         return [NSNumber numberWithBool:m_object->isSelected()];
2772     
2773     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2774         AccessibilityObject* uiElement = downcast<AccessibilityRenderObject>(*m_object).menuForMenuButton();
2775         if (uiElement)
2776             return [NSArray arrayWithObject:uiElement->wrapper()];
2777     }
2778     
2779     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2780         if (!m_object->exposesTitleUIElement())
2781             return nil;
2782         
2783         AccessibilityObject* obj = m_object->titleUIElement();
2784         if (obj)
2785             return obj->wrapper();
2786         return nil;
2787     }
2788     
2789     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute]) {
2790         if (m_object->isMeter())
2791             return [self baseAccessibilityTitle];
2792         
2793         return m_object->valueDescription();
2794     }
2795     
2796     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2797         AccessibilityOrientation elementOrientation = m_object->orientation();
2798         if (elementOrientation == AccessibilityOrientationVertical)
2799             return NSAccessibilityVerticalOrientationValue;
2800         if (elementOrientation == AccessibilityOrientationHorizontal)
2801             return NSAccessibilityHorizontalOrientationValue;
2802         return nil;
2803     }
2804     
2805     if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2806         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2807         if (scrollBar)
2808             return scrollBar->wrapper();
2809         return nil;
2810     }
2811     if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2812         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2813         if (scrollBar)
2814             return scrollBar->wrapper();
2815         return nil;
2816     }
2817     
2818     if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2819         switch (m_object->sortDirection()) {
2820             case SortDirectionAscending:
2821                 return NSAccessibilityAscendingSortDirectionValue;
2822             case SortDirectionDescending:
2823                 return NSAccessibilityDescendingSortDirectionValue;
2824             default:
2825                 return NSAccessibilityUnknownSortDirectionValue;
2826         }
2827     }
2828     
2829     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2830         return m_object->language();
2831     
2832     if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2833         return [NSNumber numberWithBool:m_object->isExpanded()];
2834     
2835     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2836         return [NSNumber numberWithBool:m_object->isRequired()];
2837     
2838     if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2839         return m_object->invalidStatus();
2840     
2841     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2842         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2843         m_object->ariaOwnsElements(ariaOwns);
2844         return convertToNSArray(ariaOwns);
2845     }
2846     
2847     if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
2848         return [NSNumber numberWithInt:m_object->ariaPosInSet()];
2849     if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute])
2850         return [NSNumber numberWithInt:m_object->ariaSetSize()];
2851     
2852     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2853         return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
2854     
2855     if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
2856         Vector<String> dropEffects;
2857         m_object->determineARIADropEffects(dropEffects);
2858         return convertStringsToNSArray(dropEffects);
2859     }
2860     
2861     if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2862         return m_object->placeholderValue();
2863
2864     if ([attributeName isEqualToString:NSAccessibilityValueAutofilledAttribute])
2865         return @(m_object->isValueAutofilled());
2866
2867     if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2868         return [NSNumber numberWithBool:m_object->ariaHasPopup()];
2869     
2870     // ARIA Live region attributes.
2871     if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2872         return m_object->ariaLiveRegionStatus();
2873     if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2874         return m_object->ariaLiveRegionRelevant();
2875     if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2876         return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
2877     if ([attributeName isEqualToString:NSAccessibilityElementBusyAttribute])
2878         return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
2879     
2880     // MathML Attributes.
2881     if (m_object->isMathElement()) {
2882         if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute])
2883             return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0;
2884         if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute])
2885             return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0;
2886         if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
2887             return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0;
2888         if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
2889             return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0;
2890         if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
2891             return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0;
2892         if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
2893             return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0;
2894         if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])
2895             return (m_object->mathSuperscriptObject()) ? m_object->mathSuperscriptObject()->wrapper() : 0;
2896         if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute])
2897             return (m_object->mathUnderObject()) ? m_object->mathUnderObject()->wrapper() : 0;
2898         if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute])
2899             return (m_object->mathOverObject()) ? m_object->mathOverObject()->wrapper() : 0;
2900         if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute])
2901             return m_object->mathFencedOpenString();
2902         if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute])
2903             return m_object->mathFencedCloseString();
2904         if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute])
2905             return [NSNumber numberWithInteger:m_object->mathLineThickness()];
2906         if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute])
2907             return [self accessibilityMathPostscriptPairs];
2908         if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute])
2909             return [self accessibilityMathPrescriptPairs];
2910     }
2911     
2912     if ([attributeName isEqualToString:NSAccessibilityExpandedTextValueAttribute])
2913         return m_object->expandedTextValue();
2914     
2915     if ([attributeName isEqualToString:NSAccessibilityDOMIdentifierAttribute])
2916         return m_object->identifierAttribute();
2917     if ([attributeName isEqualToString:NSAccessibilityDOMClassListAttribute]) {
2918         Vector<String> classList;
2919         m_object->classList(classList);
2920         return convertStringsToNSArray(classList);
2921     }
2922     
2923     // this is used only by DumpRenderTree for testing
2924     if ([attributeName isEqualToString:@"AXClickPoint"])
2925         return [NSValue valueWithPoint:m_object->clickPoint()];
2926     
2927     // This is used by DRT to verify CSS3 speech works.
2928     if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) {
2929         ESpeak speakProperty = m_object->speakProperty();
2930         switch (speakProperty) {
2931             case SpeakNone:
2932                 return @"none";
2933             case SpeakSpellOut:
2934                 return @"spell-out";
2935             case SpeakDigits:
2936                 return @"digits";
2937             case SpeakLiteralPunctuation:
2938                 return @"literal-punctuation";
2939             case SpeakNoPunctuation:
2940                 return @"no-punctuation";
2941             default:
2942             case SpeakNormal:
2943                 return @"normal";
2944         }
2945     }
2946     
2947     // Used by DRT to find an accessible node by its element id.
2948     if ([attributeName isEqualToString:@"AXDRTElementIdAttribute"])
2949         return m_object->getAttribute(idAttr);
2950     
2951     return nil;
2952 }
2953
2954 - (NSString *)accessibilityPlatformMathSubscriptKey
2955 {
2956     return NSAccessibilityMathSubscriptAttribute;
2957 }
2958
2959 - (NSString *)accessibilityPlatformMathSuperscriptKey
2960 {
2961     return NSAccessibilityMathSuperscriptAttribute;
2962 }
2963
2964 - (id)accessibilityFocusedUIElement
2965 {
2966     if (![self updateObjectBackingStore])
2967         return nil;
2968     
2969     RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
2970     
2971     if (!focusedObj)
2972         return nil;
2973     
2974     return focusedObj->wrapper();
2975 }
2976
2977 - (id)accessibilityHitTest:(NSPoint)point
2978 {
2979     if (![self updateObjectBackingStore])
2980         return nil;
2981     
2982     m_object->updateChildrenIfNecessary();
2983     RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point));
2984     if (axObject)
2985         return NSAccessibilityUnignoredAncestor(axObject->wrapper());
2986     return NSAccessibilityUnignoredAncestor(self);
2987 }
2988
2989 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2990 {
2991     if (![self updateObjectBackingStore])
2992         return NO;
2993     
2994     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2995         return YES;
2996     
2997     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2998         return m_object->canSetFocusAttribute();
2999     
3000     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
3001         return m_object->canSetValueAttribute();
3002     
3003     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
3004         return m_object->canSetSelectedAttribute();
3005     
3006     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
3007         return m_object->canSetSelectedChildrenAttribute();
3008     
3009     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
3010         return m_object->canSetExpandedAttribute();
3011     
3012     if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
3013         return YES;
3014     
3015     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
3016         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
3017         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
3018         return m_object->canSetTextRangeAttributes();
3019     
3020     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
3021         return YES;
3022     
3023     return NO;
3024 }
3025
3026 // accessibilityShouldUseUniqueId is an AppKit method we override so that
3027 // objects will be given a unique ID, and therefore allow AppKit to know when they
3028 // become obsolete (e.g. when the user navigates to a new web page, making this one
3029 // unrendered but not deallocated because it is in the back/forward cache).
3030 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
3031 // appropriate place (e.g. dealloc) to remove these non-retained references from
3032 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
3033 //
3034 // Registering an object is also required for observing notifications. Only registered objects can be observed.
3035 - (BOOL)accessibilityIsIgnored
3036 {
3037     if (![self updateObjectBackingStore])
3038         return YES;
3039     
3040     if (m_object->isAttachment())
3041         return [[self attachmentView] accessibilityIsIgnored];
3042     return m_object->accessibilityIsIgnored();
3043 }
3044
3045 - (NSArray* )accessibilityParameterizedAttributeNames
3046 {
3047     if (![self updateObjectBackingStore])
3048         return nil;
3049     
3050     if (m_object->isAttachment())
3051         return nil;
3052     
3053     static NSArray* paramAttrs = nil;
3054     static NSArray* textParamAttrs = nil;
3055     static NSArray* tableParamAttrs = nil;
3056     static NSArray* webAreaParamAttrs = nil;
3057     if (paramAttrs == nil) {
3058         paramAttrs = [[NSArray alloc] initWithObjects:
3059                       @"AXUIElementForTextMarker",
3060                       @"AXTextMarkerRangeForUIElement",
3061                       @"AXLineForTextMarker",
3062                       @"AXTextMarkerRangeForLine",
3063                       @"AXStringForTextMarkerRange",
3064                       @"AXTextMarkerForPosition",
3065                       @"AXBoundsForTextMarkerRange",
3066                       @"AXAttributedStringForTextMarkerRange",
3067                       @"AXTextMarkerRangeForUnorderedTextMarkers",
3068                       @"AXNextTextMarkerForTextMarker",
3069                       @"AXPreviousTextMarkerForTextMarker",
3070                       @"AXLeftWordTextMarkerRangeForTextMarker",
3071                       @"AXRightWordTextMarkerRangeForTextMarker",
3072                       @"AXLeftLineTextMarkerRangeForTextMarker",
3073                       @"AXRightLineTextMarkerRangeForTextMarker",
3074                       @"AXSentenceTextMarkerRangeForTextMarker",
3075                       @"AXParagraphTextMarkerRangeForTextMarker",
3076                       @"AXNextWordEndTextMarkerForTextMarker",
3077                       @"AXPreviousWordStartTextMarkerForTextMarker",
3078                       @"AXNextLineEndTextMarkerForTextMarker",
3079                       @"AXPreviousLineStartTextMarkerForTextMarker",
3080                       @"AXNextSentenceEndTextMarkerForTextMarker",
3081                       @"AXPreviousSentenceStartTextMarkerForTextMarker",
3082                       @"AXNextParagraphEndTextMarkerForTextMarker",
3083                       @"AXPreviousParagraphStartTextMarkerForTextMarker",
3084                       @"AXStyleTextMarkerRangeForTextMarker",
3085                       @"AXLengthForTextMarkerRange",
3086                       NSAccessibilityBoundsForRangeParameterizedAttribute,
3087                       NSAccessibilityStringForRangeParameterizedAttribute,
3088                       NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute,
3089                       NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
3090                       NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute,
3091                       NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute,
3092                       NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute,
3093                       NSAccessibilitySelectTextWithCriteriaParameterizedAttribute,
3094                       nil];
3095     }
3096     
3097     if (textParamAttrs == nil) {
3098         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
3099         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
3100         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
3101         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
3102         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
3103         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
3104         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
3105         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
3106         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
3107         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
3108         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
3109         [tempArray release];
3110     }
3111     if (tableParamAttrs == nil) {
3112         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
3113         [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
3114         tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
3115         [tempArray release];
3116     }
3117     if (!webAreaParamAttrs) {
3118         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
3119         [tempArray addObject:NSAccessibilityTextMarkerForIndexParameterizedAttribute];
3120         [tempArray addObject:NSAccessibilityTextMarkerIsValidParameterizedAttribute];
3121         [tempArray addObject:NSAccessibilityIndexForTextMarkerParameterizedAttribute];
3122         webAreaParamAttrs = [[NSArray alloc] initWithArray:tempArray];
3123         [tempArray release];
3124     }
3125     
3126     if (m_object->isPasswordField())
3127         return @[ NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute ];
3128     
3129     if (!m_object->isAccessibilityRenderObject())
3130         return paramAttrs;
3131     
3132     if (m_object->isTextControl())
3133         return textParamAttrs;
3134     
3135     if (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility())
3136         return tableParamAttrs;
3137     
3138     if (m_object->isMenuRelated())
3139         return nil;
3140     
3141     if (m_object->isWebArea())
3142         return webAreaParamAttrs;
3143     
3144     return paramAttrs;
3145 }
3146
3147 #pragma clang diagnostic push
3148 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3149
3150 - (void)accessibilityPerformPressAction
3151 {
3152     if (![self updateObjectBackingStore])
3153         return;
3154     
3155     if (m_object->isAttachment())
3156         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
3157     else
3158         m_object->press();
3159 }
3160
3161 - (void)accessibilityPerformIncrementAction
3162 {
3163     if (![self updateObjectBackingStore])
3164         return;
3165     
3166     if (m_object->isAttachment())
3167         [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
3168     else
3169         m_object->increment();
3170 }
3171
3172 - (void)accessibilityPerformDecrementAction
3173 {
3174     if (![self updateObjectBackingStore])
3175         return;
3176     
3177     if (m_object->isAttachment())
3178         [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
3179     else
3180         m_object->decrement();
3181 }
3182
3183 #pragma clang diagnostic pop
3184
3185 - (void)accessibilityPerformShowMenuAction
3186 {
3187     if (m_object->roleValue() == ComboBoxRole)
3188         m_object->setIsExpanded(true);
3189     else {
3190         // This needs to be performed in an iteration of the run loop that did not start from an AX call.
3191         // If it's the same run loop iteration, the menu open notification won't be sent
3192         [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
3193     }
3194 }
3195
3196 - (void)accessibilityShowContextMenu
3197 {
3198     Page* page = m_object->page();
3199     if (!page)
3200         return;
3201     
3202     IntRect rect = snappedIntRect(m_object->elementRect());
3203     FrameView* frameView = m_object->documentFrameView();
3204     
3205     // On WK2, we need to account for the scroll position.
3206     // On WK1, this isn't necessary, it's taken care of by the attachment views.
3207     if (frameView && !frameView->platformWidget()) {
3208         // Find the appropriate scroll view to use to convert the contents to the window.
3209         for (AccessibilityObject* parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
3210             if (is<AccessibilityScrollView>(*parent)) {
3211                 ScrollView* scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
3212                 rect = scrollView->contentsToRootView(rect);
3213                 break;
3214             }
3215         }
3216     }
3217     
3218     page->contextMenuController().showContextMenuAt(&page->mainFrame(), rect.center());
3219 }
3220
3221 - (void)accessibilityScrollToVisible
3222 {
3223     m_object->scrollToMakeVisible();
3224 }
3225
3226 - (void)accessibilityPerformAction:(NSString*)action
3227 {
3228     if (![self updateObjectBackingStore])
3229         return;
3230     
3231     if ([action isEqualToString:NSAccessibilityPressAction])
3232         [self accessibilityPerformPressAction];
3233     
3234     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
3235         [self accessibilityPerformShowMenuAction];
3236     
3237     else if ([action isEqualToString:NSAccessibilityIncrementAction])
3238         [self accessibilityPerformIncrementAction];
3239     
3240     else if ([action isEqualToString:NSAccessibilityDecrementAction])
3241         [self accessibilityPerformDecrementAction];
3242     
3243     else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction])
3244         [self accessibilityScrollToVisible];
3245 }
3246
3247 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
3248 {
3249     // In case anything we do by changing values causes an alert or other modal
3250     // behaviors, we need to return now, so that VoiceOver doesn't hang indefinitely.
3251     dispatch_async(dispatch_get_main_queue(), ^{
3252         [self _accessibilitySetValue:value forAttribute:attributeName];
3253     });
3254 }
3255
3256 - (void)_accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
3257 {
3258     if (![self updateObjectBackingStore])
3259         return;
3260     
3261     id textMarkerRange = nil;
3262     NSNumber*               number = nil;
3263     NSString*               string = nil;
3264     NSRange                 range = {0, 0};
3265     NSArray*                array = nil;
3266     
3267     // decode the parameter
3268     if (AXObjectIsTextMarkerRange(value))
3269         textMarkerRange = value;
3270     
3271     else if ([value isKindOfClass:[NSNumber self]])
3272         number = value;
3273     
3274     else if ([value isKindOfClass:[NSString self]])
3275         string = value;
3276     
3277     else if ([value isKindOfClass:[NSValue self]])
3278         range = [value rangeValue];
3279     
3280     else if ([value isKindOfClass:[NSArray self]])
3281         array = value;
3282     
3283     // handle the command
3284     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
3285         ASSERT(textMarkerRange);
3286         m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
3287     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
3288         ASSERT(number);
3289         
3290         bool focus = [number boolValue];
3291         
3292         // If focus is just set without making the view the first responder, then keyboard focus won't move to the right place.
3293         if (focus && m_object->isWebArea() && !m_object->document()->frame()->selection().isFocusedAndActive()) {
3294             FrameView* frameView = m_object->documentFrameView();
3295             Page* page = m_object->page();
3296             if (page && frameView) {
3297                 ChromeClient& chromeClient = page->chrome().client();
3298                 chromeClient.focus();
3299                 if (frameView->platformWidget())
3300                     chromeClient.makeFirstResponder(frameView->platformWidget());
3301                 else
3302                     chromeClient.makeFirstResponder();
3303             }
3304         }
3305         
3306         m_object->setFocused(focus);
3307     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
3308         if (number && m_object->canSetNumericValue())
3309             m_object->setValue([number floatValue]);
3310         else if (string)
3311             m_object->setValue(string);
3312     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
3313         if (!number)
3314             return;
3315         m_object->setSelected([number boolValue]);
3316     } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
3317         if (!array || m_object->roleValue() != ListBoxRole)
3318             return;
3319         AccessibilityObject::AccessibilityChildrenVector selectedChildren;
3320         convertToVector(array, selectedChildren);
3321         downcast<AccessibilityListBox>(*m_object).setSelectedChildren(selectedChildren);
3322     } else if (m_object->isTextControl()) {
3323         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
3324             m_object->setSelectedText(string);
3325         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
3326             m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
3327         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
3328             m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
3329         }
3330     } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
3331         m_object->setIsExpanded([number boolValue]);
3332     else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
3333         AccessibilityObject::AccessibilityChildrenVector selectedRows;
3334         convertToVector(array, selectedRows);
3335         if (m_object->isTree() || (is<AccessibilityTable>(*m_object) && downcast<AccessibilityTable>(*m_object).isExposableThroughAccessibility()))
3336             m_object->setSelectedRows(selectedRows);
3337     } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
3338         m_object->setARIAGrabbed([number boolValue]);
3339 }
3340
3341 static RenderObject* rendererForView(NSView* view)
3342 {
3343     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
3344         return nullptr;
3345     
3346     NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
3347     Frame* frame = [frameView _web_frame];
3348     if (!frame)
3349         return nullptr;
3350     
3351     Node* node = frame->document()->ownerElement();
3352     if (!node)
3353         return nullptr;
3354     
3355     return node->renderer();
3356 }
3357
3358 - (id)_accessibilityParentForSubview:(NSView*)subview
3359 {
3360     RenderObject* renderer = rendererForView(subview);
3361     if (!renderer)
3362         return nil;
3363     
3364     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
3365     if (obj)
3366         return obj->parentObjectUnignored()->wrapper();
3367     return nil;
3368 }
3369
3370 - (NSString*)accessibilityActionDescription:(NSString*)action
3371 {
3372     // we have no custom actions
3373     return NSAccessibilityActionDescription(action);
3374 }
3375
3376 // The CFAttributedStringType representation of the text associated with this accessibility
3377 // object that is specified by the given range.
3378 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
3379 {
3380     PlainTextRange textRange = PlainTextRange(range.location, range.length);
3381     VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
3382     return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
3383 }
3384
3385 - (NSRange)_convertToNSRange:(Range*)range
3386 {
3387     NSRange result = NSMakeRange(NSNotFound, 0);
3388     if (!range || !range->startContainer())
3389         return result;
3390     
3391     Document* document = m_object->document();
3392     if (!document)
3393         return result;
3394     
3395     size_t location;
3396     size_t length;
3397     TextIterator::getLocationAndLengthFromRange(document->documentElement(), range, location, length);
3398     result.location = location;
3399     result.length = length;
3400     
3401     return result;
3402 }
3403
3404 - (NSInteger)_indexForTextMarker:(id)marker
3405 {
3406     if (!marker)
3407         return NSNotFound;
3408     
3409     VisibleSelection selection([self visiblePositionForTextMarker:marker]);
3410     return [self _convertToNSRange:selection.toNormalizedRange().get()].location;
3411 }
3412
3413 - (id)_textMarkerForIndex:(NSInteger)textIndex
3414 {
3415     Document* document = m_object->document();
3416     if (!document)
3417         return nil;
3418     
3419     PassRefPtr<Range> textRange = TextIterator::rangeFromLocationAndLength(document->documentElement(), textIndex, 0);
3420     if (!textRange || !textRange->boundaryPointsValid())
3421         return nil;
3422     
3423     VisiblePosition position(textRange->startPosition());
3424     return [self textMarkerForVisiblePosition:position];
3425 }
3426
3427 // The RTF representation of the text associated with this accessibility object that is
3428 // specified by the given range.
3429 - (NSData*)doAXRTFForRange:(NSRange)range
3430 {
3431     NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
3432     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
3433 }
3434
3435 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
3436 {
3437     id textMarker = nil;
3438     id textMarkerRange = nil;
3439     NSNumber* number = nil;
3440     NSArray* array = nil;
3441     NSDictionary* dictionary = nil;
3442     RefPtr<AccessibilityObject> uiElement = nullptr;
3443     NSPoint point = NSZeroPoint;
3444     bool pointSet = false;
3445     NSRange range = {0, 0};
3446     bool rangeSet = false;
3447     NSRect rect = NSZeroRect;
3448     bool rectSet = false;
3449     
3450     // basic parameter validation
3451     if (!m_object || !attribute || !parameter)
3452         return nil;
3453     
3454     if (![self updateObjectBackingStore])
3455         return nil;
3456     
3457     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
3458     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
3459     // a parameter of the wrong type.
3460     if (AXObjectIsTextMarker(parameter))
3461         textMarker = parameter;
3462     
3463     else if (AXObjectIsTextMarkerRange(parameter))
3464         textMarkerRange = parameter;
3465     
3466     else if ([parameter isKindOfClass:[WebAccessibilityObjectWrapper self]])
3467         uiElement = [(WebAccessibilityObjectWrapper*)parameter accessibilityObject];
3468     
3469     else if ([parameter isKindOfClass:[NSNumber self]])
3470         number = parameter;
3471     
3472     else if ([parameter isKindOfClass:[NSArray self]])
3473         array = parameter;
3474     
3475     else if ([parameter isKindOfClass:[NSDictionary self]])
3476         dictionary = parameter;
3477     
3478     else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
3479         pointSet = true;
3480         point = [(NSValue*)parameter pointValue];
3481         
3482     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
3483         rangeSet = true;
3484         range = [(NSValue*)parameter rangeValue];
3485     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRect)) == 0) {
3486         rectSet = true;
3487         rect = [(NSValue*)parameter rectValue];
3488     } else {
3489         // Attribute type is not supported. Allow super to handle.
3490         return [super accessibilityAttributeValue:attribute forParameter:parameter];
3491     }
3492     
3493     // dispatch
3494     if ([attribute isEqualToString:NSAccessibilitySelectTextWithCriteriaParameterizedAttribute]) {
3495         AccessibilitySelectTextCriteria criteria = accessibilitySelectTextCriteriaForCriteriaParameterizedAttribute(dictionary);
3496         return m_object->selectText(&criteria);
3497     }
3498     
3499     if ([attribute isEqualToString:NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute]) {
3500         AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
3501         AccessibilityObject::AccessibilityChildrenVector results;
3502         m_object->findMatchingObjects(&criteria, results);
3503         return @(results.size());
3504     }
3505     
3506     if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute]) {
3507         AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
3508         AccessibilityObject::AccessibilityChildrenVector results;
3509         m_object->findMatchingObjects(&criteria, results);
3510         return convertToNSArray(results);
3511     }
3