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