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