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