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