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