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