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