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