Support ARIA "tab" roles
[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     if (!m_object)
550         return nil;
551
552     static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
553     static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
554     static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
555     static NSArray* sliderActions = [[NSArray alloc] initWithObjects: NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil];
556
557     NSArray *actions;
558     if (m_object->actionElement()) 
559         actions = actionElementActions;
560     else if (m_object->isMenuRelated())
561         actions = menuElementActions;
562     else if (m_object->isSlider())
563         actions = sliderActions;
564     else if (m_object->isAttachment())
565         actions = [[self attachmentView] accessibilityActionNames];
566     else
567         actions = defaultElementActions;
568
569     return actions;
570 }
571
572 - (NSArray*)accessibilityAttributeNames
573 {
574     if (!m_object)
575         return nil;
576     
577     m_object->updateBackingStore();
578     if (!m_object)
579         return nil;
580     
581     if (m_object->isAttachment())
582         return [[self attachmentView] accessibilityAttributeNames];
583
584     static NSArray* attributes = nil;
585     static NSArray* anchorAttrs = nil;
586     static NSArray* webAreaAttrs = nil;
587     static NSArray* textAttrs = nil;
588     static NSArray* listBoxAttrs = nil;
589     static NSArray* rangeAttrs = nil;
590     static NSArray* commonMenuAttrs = nil;
591     static NSArray* menuAttrs = nil;
592     static NSArray* menuBarAttrs = nil;
593     static NSArray* menuItemAttrs = nil;
594     static NSArray* menuButtonAttrs = nil;
595     static NSArray* controlAttrs = nil;
596     static NSArray* tableAttrs = nil;
597     static NSArray* tableRowAttrs = nil;
598     static NSArray* tableColAttrs = nil;
599     static NSArray* tableCellAttrs = nil;
600     static NSArray* groupAttrs = nil;
601     static NSArray* inputImageAttrs = nil;
602     static NSArray* passwordFieldAttrs = nil;
603     static NSArray *tabListAttrs = nil;
604     NSMutableArray* tempArray;
605     if (attributes == nil) {
606         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
607                       NSAccessibilitySubroleAttribute,
608                       NSAccessibilityRoleDescriptionAttribute,
609                       NSAccessibilityChildrenAttribute,
610                       NSAccessibilityHelpAttribute,
611                       NSAccessibilityParentAttribute,
612                       NSAccessibilityPositionAttribute,
613                       NSAccessibilitySizeAttribute,
614                       NSAccessibilityTitleAttribute,
615                       NSAccessibilityDescriptionAttribute,
616                       NSAccessibilityValueAttribute,
617                       NSAccessibilityFocusedAttribute,
618                       NSAccessibilityEnabledAttribute,
619                       NSAccessibilityWindowAttribute,
620                       @"AXSelectedTextMarkerRange",
621                       @"AXStartTextMarker",
622                       @"AXEndTextMarker",
623                       @"AXVisited",
624                       NSAccessibilityLinkedUIElementsAttribute,
625                       NSAccessibilitySelectedAttribute,
626                       NSAccessibilityBlockQuoteLevelAttribute,
627                       NSAccessibilityTopLevelUIElementAttribute,
628                       nil];
629     }
630     if (commonMenuAttrs == nil) {
631         commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
632                             NSAccessibilityRoleDescriptionAttribute,
633                             NSAccessibilityChildrenAttribute,
634                             NSAccessibilityParentAttribute,
635                             NSAccessibilityEnabledAttribute,
636                             NSAccessibilityPositionAttribute,
637                             NSAccessibilitySizeAttribute,
638                             nil];
639     }
640     if (anchorAttrs == nil) {
641         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
642         [tempArray addObject:NSAccessibilityURLAttribute];
643         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
644         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
645         [tempArray release];
646     }
647     if (webAreaAttrs == nil) {
648         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
649         [tempArray addObject:@"AXLinkUIElements"];
650         [tempArray addObject:@"AXLoaded"];
651         [tempArray addObject:@"AXLayoutCount"];
652         [tempArray addObject:NSAccessibilityURLAttribute];
653         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
654         [tempArray release];
655     }
656     if (textAttrs == nil) {
657         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
658         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
659         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
660         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
661         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
662         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
663         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
664         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
665         [tempArray addObject:NSAccessibilityRequiredAttribute];
666         textAttrs = [[NSArray alloc] initWithArray:tempArray];
667         [tempArray release];
668     }
669     if (listBoxAttrs == nil) {
670         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
671         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
672         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
673         [tempArray addObject:NSAccessibilityOrientationAttribute];
674         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
675         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
676         [tempArray addObject:NSAccessibilityRequiredAttribute];
677         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
678         [tempArray release];
679     }
680     if (rangeAttrs == nil) {
681         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
682         [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
683         [tempArray addObject:NSAccessibilityValueAttribute];
684         [tempArray addObject:NSAccessibilityMinValueAttribute];
685         [tempArray addObject:NSAccessibilityMaxValueAttribute];
686         [tempArray addObject:NSAccessibilityOrientationAttribute];
687         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
688         rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
689         [tempArray release];
690     }
691     if (menuBarAttrs == nil) {
692         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
693         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
694         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
695         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
696         menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
697         [tempArray release];
698     }
699     if (menuAttrs == nil) {
700         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
701         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
702         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
703         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
704         menuAttrs = [[NSArray alloc] initWithArray:tempArray];
705         [tempArray release];
706     }
707     if (menuItemAttrs == nil) {
708         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
709         [tempArray addObject:NSAccessibilityTitleAttribute];
710         [tempArray addObject:NSAccessibilityHelpAttribute];
711         [tempArray addObject:NSAccessibilitySelectedAttribute];
712         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
713         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
714         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
715         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
716         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
717         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
718         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
719         menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
720         [tempArray release];
721     }
722     if (menuButtonAttrs == nil) {
723         menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
724             NSAccessibilityRoleDescriptionAttribute,
725             NSAccessibilityParentAttribute,
726             NSAccessibilityPositionAttribute,
727             NSAccessibilitySizeAttribute,
728             NSAccessibilityWindowAttribute,
729             NSAccessibilityTopLevelUIElementAttribute,
730             NSAccessibilityEnabledAttribute,
731             NSAccessibilityFocusedAttribute,
732             NSAccessibilityTitleAttribute,
733             NSAccessibilityChildrenAttribute, nil];
734     }
735     if (controlAttrs == nil) {
736         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
737         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
738         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
739         [tempArray addObject:NSAccessibilityRequiredAttribute];
740         controlAttrs = [[NSArray alloc] initWithArray:tempArray];
741         [tempArray release];
742     }
743     if (tableAttrs == nil) {
744         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
745         [tempArray addObject:NSAccessibilityRowsAttribute];
746         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
747         [tempArray addObject:NSAccessibilityColumnsAttribute];
748         [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
749         [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
750         [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
751         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
752         [tempArray addObject:NSAccessibilityHeaderAttribute];
753         tableAttrs = [[NSArray alloc] initWithArray:tempArray];
754         [tempArray release];
755     }
756     if (tableRowAttrs == nil) {
757         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
758         [tempArray addObject:NSAccessibilityIndexAttribute];
759         tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
760         [tempArray release];
761     }
762     if (tableColAttrs == nil) {
763         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
764         [tempArray addObject:NSAccessibilityIndexAttribute];
765         [tempArray addObject:NSAccessibilityHeaderAttribute];
766         [tempArray addObject:NSAccessibilityRowsAttribute];
767         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
768         tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
769         [tempArray release];
770     }
771     if (tableCellAttrs == nil) {
772         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
773         [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
774         [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
775         tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
776         [tempArray release];        
777     }
778     if (groupAttrs == nil) {
779         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
780         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
781         groupAttrs = [[NSArray alloc] initWithArray:tempArray];
782         [tempArray release];
783     }
784     if (inputImageAttrs == nil) {
785         tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
786         [tempArray addObject:NSAccessibilityURLAttribute];
787         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
788         inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
789         [tempArray release];
790     }
791     if (passwordFieldAttrs == nil) {
792         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
793         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
794         [tempArray addObject:NSAccessibilityRequiredAttribute];
795         passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
796         [tempArray release];
797     }
798     if (tabListAttrs == nil) {
799         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
800         [tempArray addObject:NSAccessibilityTabsAttribute];
801         [tempArray addObject:NSAccessibilityContentsAttribute];
802         tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
803         [tempArray release];        
804     }
805     
806     if (m_object->isPasswordField())
807         return passwordFieldAttrs;
808
809     if (m_object->isWebArea())
810         return webAreaAttrs;
811     
812     if (m_object->isTextControl())
813         return textAttrs;
814
815     if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
816         return anchorAttrs;
817
818     if (m_object->isDataTable())
819         return tableAttrs;
820     if (m_object->isTableRow())
821         return tableRowAttrs;
822     if (m_object->isTableColumn())
823         return tableColAttrs;
824     if (m_object->isTableCell())
825         return tableCellAttrs;
826     
827     if (m_object->isListBox() || m_object->isList())
828         return listBoxAttrs;
829
830     if (m_object->isProgressIndicator() || m_object->isSlider())
831         return rangeAttrs;
832
833     if (m_object->isInputImage())
834         return inputImageAttrs;
835     
836     if (m_object->isControl())
837         return controlAttrs;
838     
839     if (m_object->isGroup())
840         return groupAttrs;
841     if (m_object->isTabList())
842         return tabListAttrs;
843     
844     if (m_object->isMenu())
845         return menuAttrs;
846     if (m_object->isMenuBar())
847         return menuBarAttrs;
848     if (m_object->isMenuButton())
849         return menuButtonAttrs;
850     if (m_object->isMenuItem())
851         return menuItemAttrs;
852
853     return attributes;
854 }
855
856 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
857 {
858     return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange));
859 }
860
861 - (NSArray*)renderWidgetChildren
862 {
863     Widget* widget = m_object->widget();
864     if (!widget)
865         return nil;
866     return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
867 }
868
869 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
870 {
871     unsigned length = [array count];
872     vector.reserveInitialCapacity(length);
873     for (unsigned i = 0; i < length; ++i) {
874         AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
875         if (obj)
876             vector.append(obj);
877     }
878 }
879
880 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
881 {
882     unsigned length = vector.size();
883     NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
884     for (unsigned i = 0; i < length; ++i) {
885         AccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
886         ASSERT(wrapper);
887         if (wrapper) {
888             // we want to return the attachment view instead of the object representing the attachment.
889             // otherwise, we get palindrome errors in the AX hierarchy
890             if (vector[i]->isAttachment() && [wrapper attachmentView])
891                 [array addObject:[wrapper attachmentView]];
892             else
893                 [array addObject:wrapper];
894         }
895     }
896     return array;
897 }
898
899 - (WebCoreTextMarkerRange*)textMarkerRangeForSelection
900 {
901     VisibleSelection selection = m_object->selection();
902     if (selection.isNone())
903         return nil;
904     return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd());
905 }
906
907 - (NSValue*)position
908 {
909     IntRect rect = m_object->elementRect();
910     
911     // The Cocoa accessibility API wants the lower-left corner.
912     NSPoint point = NSMakePoint(rect.x(), rect.bottom());
913     FrameView* frameView = m_object->documentFrameView();
914     if (frameView) {
915         NSView* view = frameView->documentView();
916         point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
917     }
918
919     return [NSValue valueWithPoint: point];
920 }
921
922 typedef HashMap<int, NSString*> AccessibilityRoleMap;
923
924 static const AccessibilityRoleMap& createAccessibilityRoleMap()
925 {
926     struct RoleEntry {
927         AccessibilityRole value;
928         NSString* string;
929     };
930     
931     static const RoleEntry roles[] = {
932         { UnknownRole, NSAccessibilityUnknownRole },
933         { ButtonRole, NSAccessibilityButtonRole },
934         { RadioButtonRole, NSAccessibilityRadioButtonRole },
935         { CheckBoxRole, NSAccessibilityCheckBoxRole },
936         { SliderRole, NSAccessibilitySliderRole },
937         { TabGroupRole, NSAccessibilityTabGroupRole },
938         { TextFieldRole, NSAccessibilityTextFieldRole },
939         { StaticTextRole, NSAccessibilityStaticTextRole },
940         { TextAreaRole, NSAccessibilityTextAreaRole },
941         { ScrollAreaRole, NSAccessibilityScrollAreaRole },
942         { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
943         { MenuButtonRole, NSAccessibilityMenuButtonRole },
944         { TableRole, NSAccessibilityTableRole },
945         { ApplicationRole, NSAccessibilityApplicationRole },
946         { GroupRole, NSAccessibilityGroupRole },
947         { RadioGroupRole, NSAccessibilityRadioGroupRole },
948         { ListRole, NSAccessibilityListRole },
949         { ScrollBarRole, NSAccessibilityScrollBarRole },
950         { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
951         { ImageRole, NSAccessibilityImageRole },
952         { MenuBarRole, NSAccessibilityMenuBarRole },
953         { MenuRole, NSAccessibilityMenuRole },
954         { MenuItemRole, NSAccessibilityMenuItemRole },
955         { ColumnRole, NSAccessibilityColumnRole },
956         { RowRole, NSAccessibilityRowRole },
957         { ToolbarRole, NSAccessibilityToolbarRole },
958         { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
959         { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
960         { WindowRole, NSAccessibilityWindowRole },
961         { DrawerRole, NSAccessibilityDrawerRole },
962         { SystemWideRole, NSAccessibilitySystemWideRole },
963         { OutlineRole, NSAccessibilityOutlineRole },
964         { IncrementorRole, NSAccessibilityIncrementorRole },
965         { BrowserRole, NSAccessibilityBrowserRole },
966         { ComboBoxRole, NSAccessibilityComboBoxRole },
967         { SplitGroupRole, NSAccessibilitySplitGroupRole },
968         { SplitterRole, NSAccessibilitySplitterRole },
969         { ColorWellRole, NSAccessibilityColorWellRole },
970         { GrowAreaRole, NSAccessibilityGrowAreaRole },
971         { SheetRole, NSAccessibilitySheetRole },
972         { HelpTagRole, NSAccessibilityHelpTagRole },
973         { MatteRole, NSAccessibilityMatteRole }, 
974         { RulerRole, NSAccessibilityRulerRole },
975         { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
976         { LinkRole, NSAccessibilityLinkRole },
977 #ifndef BUILDING_ON_TIGER        
978         { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
979         { GridRole, NSAccessibilityGridRole },
980 #endif
981         { WebCoreLinkRole, NSAccessibilityLinkRole }, 
982         { ImageMapLinkRole, NSAccessibilityLinkRole },
983         { ImageMapRole, @"AXImageMap" },
984         { ListMarkerRole, @"AXListMarker" },
985         { WebAreaRole, @"AXWebArea" },
986         { HeadingRole, @"AXHeading" },
987         { ListBoxRole, NSAccessibilityListRole },
988         { ListBoxOptionRole, NSAccessibilityStaticTextRole },
989 #if ACCESSIBILITY_TABLES
990         { CellRole, NSAccessibilityCellRole },
991 #else
992         { CellRole, NSAccessibilityGroupRole },
993 #endif
994         { TableHeaderContainerRole, NSAccessibilityGroupRole },
995         { DefinitionListDefinitionRole, NSAccessibilityGroupRole },
996         { DefinitionListTermRole, NSAccessibilityGroupRole },
997         { SliderThumbRole, NSAccessibilityValueIndicatorRole },
998         { LandmarkApplicationRole, NSAccessibilityGroupRole },
999         { LandmarkBannerRole, NSAccessibilityGroupRole },
1000         { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1001         { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1002         { LandmarkMainRole, NSAccessibilityGroupRole },
1003         { LandmarkNavigationRole, NSAccessibilityGroupRole },
1004         { LandmarkSearchRole, NSAccessibilityGroupRole },
1005         { ApplicationLogRole, NSAccessibilityGroupRole },
1006         { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1007         { ApplicationStatusRole, NSAccessibilityGroupRole },
1008         { ApplicationTimerRole, NSAccessibilityGroupRole },
1009         { DocumentRole, NSAccessibilityGroupRole },
1010         { DocumentArticleRole, NSAccessibilityGroupRole },
1011         { DocumentNoteRole, NSAccessibilityGroupRole },
1012         { DocumentRegionRole, NSAccessibilityGroupRole },
1013         { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1014         { TabRole, NSAccessibilityRadioButtonRole },
1015         { TabListRole, NSAccessibilityTabGroupRole },
1016         { TabPanelRole, NSAccessibilityGroupRole },
1017     };
1018     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1019     
1020     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1021     for (unsigned i = 0; i < numRoles; ++i)
1022         roleMap.set(roles[i].value, roles[i].string);
1023     return roleMap;
1024 }
1025
1026 static NSString* roleValueToNSString(AccessibilityRole value)
1027 {
1028     ASSERT(value);
1029     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1030     return roleMap.get(value);
1031 }
1032
1033 - (NSString*)role
1034 {
1035     if (m_object->isAttachment())
1036         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1037     NSString* string = roleValueToNSString(m_object->roleValue());
1038     if (string != nil)
1039         return string;
1040     return NSAccessibilityUnknownRole;
1041 }
1042
1043 - (NSString*)subrole
1044 {
1045     if (m_object->isPasswordField())
1046         return NSAccessibilitySecureTextFieldSubrole;
1047     
1048     if (m_object->isAttachment()) {
1049         NSView* attachView = [self attachmentView];
1050         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1051             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1052         }
1053     }
1054     
1055     if (m_object->isList()) {
1056         AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
1057         if (listObject->isUnorderedList() || listObject->isOrderedList())
1058             return NSAccessibilityContentListSubrole;
1059         if (listObject->isDefinitionList())
1060             return NSAccessibilityDefinitionListSubrole;
1061     }
1062     
1063     // ARIA content subroles.
1064     switch (m_object->roleValue()) {
1065         case LandmarkApplicationRole:
1066             return @"AXLandmarkApplication";
1067         case LandmarkBannerRole:
1068             return @"AXLandmarkBanner";
1069         case LandmarkComplementaryRole:
1070             return @"AXLandmarkComplementary";
1071         case LandmarkContentInfoRole:
1072             return @"AXLandmarkContentInfo";
1073         case LandmarkMainRole:
1074             return @"AXLandmarkMain";
1075         case LandmarkNavigationRole:
1076             return @"AXLandmarkNavigation";
1077         case LandmarkSearchRole:
1078             return @"AXLandmarkSearch";
1079         case ApplicationLogRole:
1080             return @"AXApplicationLog";
1081         case ApplicationMarqueeRole:
1082             return @"AXApplicationMarquee";
1083         case ApplicationStatusRole:
1084             return @"AXApplicationStatus";
1085         case ApplicationTimerRole:
1086             return @"AXApplicationTimer";
1087         case DocumentRole:
1088             return @"AXDocument";
1089         case DocumentArticleRole:
1090             return @"AXDocumentArticle";
1091         case DocumentNoteRole:
1092             return @"AXDocumentNote";
1093         case DocumentRegionRole:
1094             return @"AXDocumentRegion";
1095         case UserInterfaceTooltipRole:
1096             return @"AXUserInterfaceTooltip";
1097         case TabPanelRole:
1098             return @"AXTabPanel";
1099         default:
1100             return nil;
1101     }
1102     
1103     if (m_object->isMediaTimeline())
1104         return NSAccessibilityTimelineSubrole;
1105
1106     return nil;
1107 }
1108
1109 - (NSString*)roleDescription
1110 {
1111     if (!m_object)
1112         return nil;
1113
1114     // attachments have the AXImage role, but a different subrole
1115     if (m_object->isAttachment())
1116         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1117     
1118     NSString* axRole = [self role];
1119     
1120     if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1121         switch (m_object->roleValue()) {
1122             default:
1123                 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1124             case LandmarkApplicationRole:
1125                 return AXARIAContentGroupText(@"ARIALandmarkApplication");
1126             case LandmarkBannerRole:
1127                 return AXARIAContentGroupText(@"ARIALandmarkBanner");
1128             case LandmarkComplementaryRole:
1129                 return AXARIAContentGroupText(@"ARIALandmarkComplementary");
1130             case LandmarkContentInfoRole:
1131                 return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
1132             case LandmarkMainRole:
1133                 return AXARIAContentGroupText(@"ARIALandmarkMain");
1134             case LandmarkNavigationRole:
1135                 return AXARIAContentGroupText(@"ARIALandmarkNavigation");
1136             case LandmarkSearchRole:
1137                 return AXARIAContentGroupText(@"ARIALandmarkSearch");
1138             case ApplicationLogRole:
1139                 return AXARIAContentGroupText(@"ARIAApplicationLog");
1140             case ApplicationMarqueeRole:
1141                 return AXARIAContentGroupText(@"ARIAApplicationMarquee");
1142             case ApplicationStatusRole:
1143                 return AXARIAContentGroupText(@"ARIAApplicationStatus");
1144             case ApplicationTimerRole:
1145                 return AXARIAContentGroupText(@"ARIAApplicationTimer");
1146             case DocumentRole:
1147                 return AXARIAContentGroupText(@"ARIADocument");
1148             case DocumentArticleRole:
1149                 return AXARIAContentGroupText(@"ARIADocumentArticle");
1150             case DocumentNoteRole:
1151                 return AXARIAContentGroupText(@"ARIADocumentNote");
1152             case DocumentRegionRole:
1153                 return AXARIAContentGroupText(@"ARIADocumentRegion");
1154             case UserInterfaceTooltipRole:
1155                 return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
1156             case TabPanelRole:
1157                 return AXARIAContentGroupText(@"ARIATabPanel");
1158         }
1159     }        
1160     
1161     if ([axRole isEqualToString:@"AXWebArea"])
1162         return AXWebAreaText();
1163     
1164     if ([axRole isEqualToString:@"AXLink"])
1165         return AXLinkText();
1166     
1167     if ([axRole isEqualToString:@"AXListMarker"])
1168         return AXListMarkerText();
1169     
1170     if ([axRole isEqualToString:@"AXImageMap"])
1171         return AXImageMapText();
1172
1173     if ([axRole isEqualToString:@"AXHeading"])
1174         return AXHeadingText();
1175
1176     // AppKit also returns AXTab for the role description for a tab item.
1177     if (m_object->isTabItem())
1178         return NSAccessibilityRoleDescription(@"AXTab", nil);
1179     
1180     // We should try the system default role description for all other roles.
1181     // If we get the same string back, then as a last resort, return unknown.
1182     NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1183     if (![defaultRoleDescription isEqualToString:axRole])
1184         return defaultRoleDescription;
1185
1186     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1187 }
1188
1189 // FIXME: split up this function in a better way.  
1190 // suggestions: Use a hash table that maps attribute names to function calls,
1191 // or maybe pointers to member functions
1192 - (id)accessibilityAttributeValue:(NSString*)attributeName
1193 {
1194     if (!m_object)
1195         return nil;
1196
1197     m_object->updateBackingStore();
1198     if (!m_object)
1199         return nil;
1200     
1201     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1202         return [self role];
1203
1204     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1205         return [self subrole];
1206
1207     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1208         return [self roleDescription];
1209
1210     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1211         if (m_object->isAccessibilityRenderObject()) {
1212             FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
1213             if (fv)
1214                 return fv->platformWidget();
1215         }
1216         
1217         return m_object->parentObjectUnignored()->wrapper();
1218     }
1219
1220     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1221         if (m_object->children().isEmpty()) {
1222             NSArray* children = [self renderWidgetChildren];
1223             if (children != nil)
1224                 return children;
1225         }
1226         return convertToNSArray(m_object->children());
1227     }
1228     
1229     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1230         if (m_object->isListBox()) {
1231             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1232             m_object->selectedChildren(selectedChildrenCopy);
1233             return convertToNSArray(selectedChildrenCopy);
1234         }
1235         return nil;
1236     }
1237     
1238     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
1239         if (m_object->isListBox()) {
1240             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
1241             m_object->visibleChildren(visibleChildrenCopy);
1242             return convertToNSArray(visibleChildrenCopy);
1243         }
1244         else if (m_object->isList())
1245             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1246
1247         return nil;
1248     }
1249     
1250     
1251     if (m_object->isWebArea()) {
1252         if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
1253             AccessibilityObject::AccessibilityChildrenVector links;
1254             static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
1255             return convertToNSArray(links);
1256         }
1257         if ([attributeName isEqualToString: @"AXLoaded"])
1258             return [NSNumber numberWithBool: m_object->isLoaded()];
1259         if ([attributeName isEqualToString: @"AXLayoutCount"])
1260             return [NSNumber numberWithInt: m_object->layoutCount()];
1261     }
1262     
1263     if (m_object->isTextControl()) {
1264         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1265             int length = m_object->textLength();
1266             if (length < 0)
1267                 return nil;
1268             return [NSNumber numberWithUnsignedInt:length];
1269         }
1270         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1271             String selectedText = m_object->selectedText();
1272             if (selectedText.isNull())
1273                 return nil;
1274             return (NSString*)selectedText;
1275         }
1276         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1277             PlainTextRange textRange = m_object->selectedTextRange();
1278             if (textRange.isNull())
1279                 return nil;
1280             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1281         }
1282         // TODO: Get actual visible range. <rdar://problem/4712101>
1283         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1284             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1285         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1286             // if selectionEnd > 0, then there is selected text and this question should not be answered
1287             if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
1288                 return nil;
1289             int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
1290             if (lineNumber < 0)
1291                 return nil;
1292             return [NSNumber numberWithInt:lineNumber];
1293         }
1294     }
1295     
1296     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1297         KURL url = m_object->url();
1298         if (url.isNull())
1299             return nil;
1300         return (NSURL*)url;
1301     }
1302
1303     if ([attributeName isEqualToString: @"AXVisited"])
1304         return [NSNumber numberWithBool: m_object->isVisited()];
1305     
1306     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1307         if (m_object->isAttachment()) {
1308             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 
1309                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1310         }
1311         return m_object->title();
1312     }
1313     
1314     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1315         if (m_object->isAttachment()) {
1316             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1317                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1318         }
1319         return m_object->accessibilityDescription();
1320     }
1321
1322     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1323         if (m_object->isAttachment()) {
1324             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 
1325                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1326         }
1327         if (m_object->isProgressIndicator() || m_object->isSlider())
1328             return [NSNumber numberWithFloat:m_object->valueForRange()];
1329         if (m_object->hasIntValue())
1330             return [NSNumber numberWithInt:m_object->intValue()];
1331
1332         // radio groups return the selected radio button as the AXValue
1333         if (m_object->isRadioGroup()) {
1334             AccessibilityObject* radioButton = m_object->selectedRadioButton();
1335             if (!radioButton)
1336                 return nil;
1337             return radioButton->wrapper();
1338         }
1339         
1340         if (m_object->isTabList()) {
1341             AccessibilityObject* tabItem = m_object->selectedTabItem();
1342             if (!tabItem)
1343                 return nil;
1344             return tabItem->wrapper();
1345         }
1346         
1347         if (m_object->isTabItem())
1348             return [NSNumber numberWithInt:m_object->isSelected()];
1349         
1350         return m_object->stringValue();
1351     }
1352
1353     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1354         return [NSNumber numberWithFloat:m_object->minValueForRange()];
1355
1356     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1357         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1358
1359     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1360         return m_object->helpText();
1361
1362     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1363         return [NSNumber numberWithBool: m_object->isFocused()];
1364
1365     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1366         return [NSNumber numberWithBool: m_object->isEnabled()];
1367
1368     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1369         IntSize s = m_object->size();
1370         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1371     }
1372
1373     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1374         return [self position];
1375
1376     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1377         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1378         FrameView* fv = m_object->documentFrameView();
1379         if (fv)
1380             return [fv->platformWidget() window];
1381         return nil;
1382     }
1383     
1384     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
1385         AtomicString accessKey = m_object->accessKey();
1386         if (accessKey.isNull())
1387             return nil;
1388         return accessKey;
1389     }
1390     
1391     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
1392         if (m_object->isTabList()) {
1393             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1394             m_object->tabChildren(tabsChildren);
1395             return convertToNSArray(tabsChildren);
1396         }
1397     }
1398     
1399     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
1400         // The contents of a tab list are all the children except the tabs.
1401         if (m_object->isTabList()) {
1402             AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1403             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1404             m_object->tabChildren(tabsChildren);
1405
1406             AccessibilityObject::AccessibilityChildrenVector contents;
1407             unsigned childrenSize = children.size();
1408             for (unsigned k = 0; k < childrenSize; ++k) {
1409                 if (tabsChildren.find(children[k]) == WTF::notFound)
1410                     contents.append(children[k]);
1411             }
1412             return convertToNSArray(contents);
1413         }
1414     }    
1415     
1416     if (m_object->isDataTable()) {
1417         // TODO: distinguish between visible and non-visible rows
1418         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 
1419             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1420             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
1421         }
1422         // TODO: distinguish between visible and non-visible columns
1423         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] || 
1424             [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
1425             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
1426         }
1427         
1428         // HTML tables don't support these
1429         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] || 
1430             [attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute] ||
1431             [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1432             return nil;
1433         
1434         if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
1435             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1436             static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
1437             return convertToNSArray(columnHeaders);            
1438         }
1439         
1440         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1441             AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
1442             if (headerContainer)
1443                 return headerContainer->wrapper();
1444             return nil;
1445         }
1446
1447         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
1448             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1449             static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
1450             return convertToNSArray(rowHeaders);                        
1451         }
1452         
1453         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
1454             AccessibilityObject::AccessibilityChildrenVector cells;
1455             static_cast<AccessibilityTable*>(m_object)->cells(cells);
1456             return convertToNSArray(cells);
1457         }        
1458     }
1459     
1460     if (m_object->isTableRow()) {
1461         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1462             return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
1463     }
1464     
1465     if (m_object->isTableColumn()) {
1466         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1467             return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
1468         
1469         // rows attribute for a column is the list of all the elements in that column at each row
1470         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 
1471             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1472             return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
1473         }
1474         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1475             AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
1476             if (!header)
1477                 return nil;
1478             return header->wrapper();
1479         }
1480     }
1481     
1482     if (m_object->isTableCell()) {
1483         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1484             pair<int, int> rowRange;
1485             static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
1486             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1487         }  
1488         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1489             pair<int, int> columnRange;
1490             static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
1491             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1492         }  
1493     }
1494     
1495     if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1496         return NSAccessibilityVerticalOrientationValue;
1497
1498     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1499         return [self textMarkerRangeForSelection];
1500     
1501     if (m_object->isAccessibilityRenderObject()) {
1502         RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1503         if (!renderer)
1504             return nil;
1505         
1506         if ([attributeName isEqualToString: @"AXStartTextMarker"])
1507             return textMarkerForVisiblePosition(startOfDocument(renderer->document()));
1508         if ([attributeName isEqualToString: @"AXEndTextMarker"])
1509             return textMarkerForVisiblePosition(endOfDocument(renderer->document()));
1510
1511         if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
1512             return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1513     } else {
1514         if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) {
1515             AccessibilityObject* parent = m_object->parentObjectUnignored();
1516             if (!parent)
1517                 return [NSNumber numberWithInt:0];
1518             return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute];        
1519         }
1520     }
1521     
1522     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1523         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1524         m_object->linkedUIElements(linkedUIElements);
1525         if (linkedUIElements.size() == 0)
1526             return nil;
1527         return convertToNSArray(linkedUIElements);
1528     }
1529
1530     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1531         return [NSNumber numberWithBool:m_object->isSelected()];
1532
1533     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
1534         AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
1535         if (uiElement)
1536             return [NSArray arrayWithObject:uiElement->wrapper()];
1537     }
1538
1539     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
1540         AccessibilityObject* obj = m_object->titleUIElement();
1541         if (obj)
1542             return obj->wrapper();
1543         return nil;
1544     }
1545     
1546     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
1547         return m_object->valueDescription();
1548     
1549     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
1550         AccessibilityOrientation elementOrientation = m_object->orientation();
1551         if (elementOrientation == AccessibilityOrientationVertical)
1552             return NSAccessibilityVerticalOrientationValue;
1553         if (elementOrientation == AccessibilityOrientationHorizontal)
1554             return NSAccessibilityHorizontalOrientationValue;
1555         return nil;
1556     }
1557     
1558     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute]) 
1559         return m_object->language();
1560     
1561     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
1562         return [NSNumber numberWithBool:m_object->isRequired()];
1563
1564     // this is used only by DumpRenderTree for testing
1565     if ([attributeName isEqualToString:@"AXClickPoint"])
1566         return [NSValue valueWithPoint:m_object->clickPoint()];
1567     
1568     return nil;
1569 }
1570
1571 - (id)accessibilityFocusedUIElement
1572 {
1573     if (!m_object)
1574         return nil;
1575
1576     m_object->updateBackingStore();
1577     if (!m_object)
1578         return nil;
1579
1580     RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
1581
1582     if (!focusedObj)
1583         return nil;
1584     
1585     return focusedObj->wrapper();
1586 }
1587
1588 - (id)accessibilityHitTest:(NSPoint)point
1589 {
1590     if (!m_object)
1591         return nil;
1592
1593     m_object->updateBackingStore();
1594     if (!m_object)
1595         return nil;
1596
1597     RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
1598     if (axObject)
1599         return NSAccessibilityUnignoredAncestor(axObject->wrapper());
1600     return NSAccessibilityUnignoredAncestor(self);
1601 }
1602
1603 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
1604 {
1605     if (!m_object)
1606         return nil;
1607
1608     m_object->updateBackingStore();
1609     if (!m_object)
1610         return nil;
1611
1612     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1613         return YES;
1614
1615     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1616         return m_object->canSetFocusAttribute();
1617
1618     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1619         return m_object->canSetValueAttribute();
1620
1621     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1622         return m_object->canSetSelectedAttribute();
1623     
1624     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
1625         return m_object->canSetSelectedChildrenAttribute();
1626
1627     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
1628         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
1629         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1630         return m_object->canSetTextRangeAttributes();
1631     
1632     return NO;
1633 }
1634
1635 // accessibilityShouldUseUniqueId is an AppKit method we override so that
1636 // objects will be given a unique ID, and therefore allow AppKit to know when they
1637 // become obsolete (e.g. when the user navigates to a new web page, making this one
1638 // unrendered but not deallocated because it is in the back/forward cache).
1639 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
1640 // appropriate place (e.g. dealloc) to remove these non-retained references from
1641 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
1642 //
1643 // Registering an object is also required for observing notifications. Only registered objects can be observed.
1644 - (BOOL)accessibilityIsIgnored
1645 {
1646     if (!m_object)
1647         return nil;
1648
1649     m_object->updateBackingStore();
1650     if (!m_object)
1651         return nil;
1652
1653     if (m_object->isAttachment())
1654         return [[self attachmentView] accessibilityIsIgnored];
1655     return m_object->accessibilityIsIgnored();
1656 }
1657
1658 - (NSArray* )accessibilityParameterizedAttributeNames
1659 {
1660     if (!m_object)
1661         return nil;
1662
1663     m_object->updateBackingStore();
1664     if (!m_object)
1665         return nil;
1666
1667     if (m_object->isAttachment()) 
1668         return nil;
1669
1670     static NSArray* paramAttrs = nil;
1671     static NSArray* textParamAttrs = nil;
1672     static NSArray* tableParamAttrs = nil;
1673     if (paramAttrs == nil) {
1674         paramAttrs = [[NSArray alloc] initWithObjects:
1675                       @"AXUIElementForTextMarker",
1676                       @"AXTextMarkerRangeForUIElement",
1677                       @"AXLineForTextMarker",
1678                       @"AXTextMarkerRangeForLine",
1679                       @"AXStringForTextMarkerRange",
1680                       @"AXTextMarkerForPosition",
1681                       @"AXBoundsForTextMarkerRange",
1682                       @"AXAttributedStringForTextMarkerRange",
1683                       @"AXTextMarkerRangeForUnorderedTextMarkers",
1684                       @"AXNextTextMarkerForTextMarker",
1685                       @"AXPreviousTextMarkerForTextMarker",
1686                       @"AXLeftWordTextMarkerRangeForTextMarker",
1687                       @"AXRightWordTextMarkerRangeForTextMarker",
1688                       @"AXLeftLineTextMarkerRangeForTextMarker",
1689                       @"AXRightLineTextMarkerRangeForTextMarker",
1690                       @"AXSentenceTextMarkerRangeForTextMarker",
1691                       @"AXParagraphTextMarkerRangeForTextMarker",
1692                       @"AXNextWordEndTextMarkerForTextMarker",
1693                       @"AXPreviousWordStartTextMarkerForTextMarker",
1694                       @"AXNextLineEndTextMarkerForTextMarker",
1695                       @"AXPreviousLineStartTextMarkerForTextMarker",
1696                       @"AXNextSentenceEndTextMarkerForTextMarker",
1697                       @"AXPreviousSentenceStartTextMarkerForTextMarker",
1698                       @"AXNextParagraphEndTextMarkerForTextMarker",
1699                       @"AXPreviousParagraphStartTextMarkerForTextMarker",
1700                       @"AXStyleTextMarkerRangeForTextMarker",
1701                       @"AXLengthForTextMarkerRange",
1702                       NSAccessibilityBoundsForRangeParameterizedAttribute,
1703                       NSAccessibilityStringForRangeParameterizedAttribute,
1704                       nil];
1705     }
1706
1707     if (textParamAttrs == nil) {
1708         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
1709         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
1710         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
1711         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
1712         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
1713         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
1714         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
1715         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
1716         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
1717         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
1718         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
1719         [tempArray release];
1720     }
1721     if (tableParamAttrs == nil) {
1722         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
1723         [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
1724         tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
1725         [tempArray release];
1726     }
1727     
1728     if (m_object->isPasswordField())
1729         return [NSArray array];
1730     
1731     if (!m_object->isAccessibilityRenderObject())
1732         return paramAttrs;
1733
1734     if (m_object->isTextControl())
1735         return textParamAttrs;
1736     
1737     if (m_object->isDataTable())
1738         return tableParamAttrs;
1739     
1740     if (m_object->isMenuRelated())
1741         return nil;
1742
1743     return paramAttrs;
1744 }
1745
1746 - (void)accessibilityPerformPressAction
1747 {
1748     if (!m_object)
1749         return;
1750
1751     m_object->updateBackingStore();
1752     if (!m_object)
1753         return;
1754
1755     if (m_object->isAttachment())
1756         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
1757     else
1758         m_object->press();    
1759 }
1760
1761 - (void)accessibilityPerformIncrementAction
1762 {
1763     if (!m_object)
1764         return;
1765
1766     m_object->updateBackingStore();
1767     if (!m_object)
1768         return;
1769
1770     if (m_object->isAttachment())
1771         [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
1772     else
1773         m_object->increment();    
1774 }
1775
1776 - (void)accessibilityPerformDecrementAction
1777 {
1778     if (!m_object)
1779         return;
1780
1781     m_object->updateBackingStore();
1782     if (!m_object)
1783         return;
1784
1785     if (m_object->isAttachment())
1786         [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
1787     else
1788         m_object->decrement();    
1789 }
1790
1791 - (void)accessibilityPerformShowMenuAction
1792 {
1793     // This needs to be performed in an iteration of the run loop that did not start from an AX call. 
1794     // If it's the same run loop iteration, the menu open notification won't be sent
1795     [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
1796 }
1797
1798 - (void)accessibilityShowContextMenu
1799 {    
1800     FrameView* frameView = m_object->documentFrameView();
1801     if (!frameView)
1802         return;
1803
1804     // simulate a click in the middle of the object
1805     IntPoint clickPoint = m_object->clickPoint();
1806     NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y());
1807     
1808     NSView* view = nil;
1809     if (m_object->isAttachment())
1810         view = [self attachmentView];
1811     else
1812         view = frameView->documentView();
1813     
1814     if (!view)
1815         return;
1816     
1817     NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil];
1818     
1819     // Show the contextual menu for this event.
1820     NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
1821     NSMenu* menu = [view menuForEvent:event];
1822     
1823     if (menu)
1824         [NSMenu popUpContextMenu:menu withEvent:event forView:view];    
1825 }
1826
1827 - (void)accessibilityPerformAction:(NSString*)action
1828 {
1829     if (!m_object)
1830         return;
1831
1832     m_object->updateBackingStore();
1833     if (!m_object)
1834         return;
1835
1836     if ([action isEqualToString:NSAccessibilityPressAction])
1837         [self accessibilityPerformPressAction];
1838     
1839     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
1840         [self accessibilityPerformShowMenuAction];
1841
1842     else if ([action isEqualToString:NSAccessibilityIncrementAction])
1843         [self accessibilityPerformIncrementAction];
1844
1845     else if ([action isEqualToString:NSAccessibilityDecrementAction])
1846         [self accessibilityPerformDecrementAction];
1847 }
1848
1849 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
1850 {
1851     if (!m_object)
1852         return;
1853
1854     m_object->updateBackingStore();
1855     if (!m_object)
1856         return;
1857
1858     WebCoreTextMarkerRange* textMarkerRange = nil;
1859     NSNumber*               number = nil;
1860     NSString*               string = nil;
1861     NSRange                 range = {0, 0};
1862     NSArray*                array = nil;
1863     
1864     // decode the parameter
1865     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
1866         textMarkerRange = (WebCoreTextMarkerRange*) value;
1867
1868     else if ([value isKindOfClass:[NSNumber self]])
1869         number = value;
1870
1871     else if ([value isKindOfClass:[NSString self]])
1872         string = value;
1873     
1874     else if ([value isKindOfClass:[NSValue self]])
1875         range = [value rangeValue];
1876     
1877     else if ([value isKindOfClass:[NSArray self]])
1878         array = value;
1879     
1880     // handle the command
1881     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
1882         ASSERT(textMarkerRange);
1883         m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);        
1884     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
1885         ASSERT(number);
1886         m_object->setFocused([number intValue] != 0);
1887     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1888         if (!string)
1889             return;
1890         m_object->setValue(string);
1891     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
1892         if (!number)
1893             return;
1894         m_object->setSelected([number boolValue]);
1895     } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1896         if (!array || m_object->roleValue() != ListBoxRole)
1897             return;
1898         AccessibilityObject::AccessibilityChildrenVector selectedChildren;
1899         convertToVector(array, selectedChildren);
1900         static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
1901     } else if (m_object->isTextControl()) {
1902         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1903             m_object->setSelectedText(string);
1904         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1905             m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
1906         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
1907             m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
1908         }
1909     }
1910 }
1911
1912 static RenderObject* rendererForView(NSView* view)
1913 {
1914     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1915         return 0;
1916
1917     NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
1918     Frame* frame = [frameView _web_frame];
1919     if (!frame)
1920         return 0;
1921
1922     Node* node = frame->document()->ownerElement();
1923     if (!node)
1924         return 0;
1925
1926     return node->renderer();
1927 }
1928
1929 - (id)_accessibilityParentForSubview:(NSView*)subview
1930 {   
1931     RenderObject* renderer = rendererForView(subview);
1932     if (!renderer)
1933         return nil;
1934
1935     AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
1936     if (obj)
1937         return obj->parentObjectUnignored()->wrapper();
1938     return nil;
1939 }
1940
1941 - (NSString*)accessibilityActionDescription:(NSString*)action
1942 {
1943     // we have no custom actions
1944     return NSAccessibilityActionDescription(action);
1945 }
1946
1947 // The CFAttributedStringType representation of the text associated with this accessibility
1948 // object that is specified by the given range.
1949 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
1950 {
1951     PlainTextRange textRange = PlainTextRange(range.location, range.length);
1952     VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
1953     return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)];
1954 }
1955
1956 // The RTF representation of the text associated with this accessibility object that is
1957 // specified by the given range.
1958 - (NSData*)doAXRTFForRange:(NSRange)range
1959 {
1960     NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
1961     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
1962 }
1963
1964 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
1965 {
1966     WebCoreTextMarker* textMarker = nil;
1967     WebCoreTextMarkerRange* textMarkerRange = nil;
1968     NSNumber* number = nil;
1969     NSArray* array = nil;
1970     RefPtr<AccessibilityObject> uiElement = 0;
1971     NSPoint point = NSZeroPoint;
1972     bool pointSet = false;
1973     NSRange range = {0, 0};
1974     bool rangeSet = false;
1975     
1976     // basic parameter validation
1977     if (!m_object || !attribute || !parameter)
1978         return nil;
1979
1980     m_object->updateBackingStore();
1981     if (!m_object)
1982         return nil;
1983     
1984     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
1985     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
1986     // a parameter of the wrong type.
1987     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
1988         textMarker = (WebCoreTextMarker*) parameter;
1989
1990     else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
1991         textMarkerRange = (WebCoreTextMarkerRange*) parameter;
1992
1993     else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
1994         uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
1995
1996     else if ([parameter isKindOfClass:[NSNumber self]])
1997         number = parameter;
1998
1999     else if ([parameter isKindOfClass:[NSArray self]])
2000         array = parameter;
2001
2002     else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2003         pointSet = true;
2004         point = [(NSValue*)parameter pointValue];
2005
2006     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2007         rangeSet = true;
2008         range = [(NSValue*)parameter rangeValue];
2009
2010     } else {
2011         // got a parameter of a type we never use
2012         // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally
2013         // while using accesstool (e.g.), forcing you to start over
2014         return nil;
2015     }
2016     
2017     // Convert values to WebCore types
2018     // FIXME: prepping all of these values as WebCore types is unnecessary in many 
2019     // cases. Re-organization of this function or performing the conversion on a 
2020     // need basis are possible improvements. 
2021     VisiblePosition visiblePos;
2022     if (textMarker)
2023         visiblePos = visiblePositionForTextMarker(textMarker);
2024     int intNumber = [number intValue];
2025     VisiblePositionRange visiblePosRange;
2026     if (textMarkerRange)
2027         visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2028     IntPoint webCorePoint = IntPoint(point);
2029     PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2030
2031     // dispatch
2032     if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
2033         return m_object->accessibilityObjectForPosition(visiblePos)->wrapper();
2034
2035     if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) {
2036         VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
2037         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2038     }
2039
2040     if ([attribute isEqualToString: @"AXLineForTextMarker"])
2041         return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
2042
2043     if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) {
2044         VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber);
2045         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2046     }
2047
2048     if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
2049         return m_object->stringForVisiblePositionRange(visiblePosRange);
2050
2051     if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
2052         return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil;
2053
2054     if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) {
2055         NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
2056         return [NSValue valueWithRect:rect];
2057     }
2058     
2059     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2060         VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2061         VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2062         if (start.isNull() || end.isNull())
2063             return nil;
2064         NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
2065         return [NSValue valueWithRect:rect];
2066     }
2067     
2068     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
2069         VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2070         VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2071         if (start.isNull() || end.isNull())
2072             return nil;
2073         return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
2074     }
2075
2076     if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
2077         return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
2078
2079     if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) {
2080         if ([array count] < 2)
2081             return nil;
2082
2083         WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
2084         WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
2085         if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1] 
2086             || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
2087             return nil;
2088
2089         VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1);
2090         VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2);
2091         VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
2092         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2093     }
2094
2095     if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
2096         return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos));
2097
2098     if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
2099         return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos));
2100
2101     if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) {
2102         VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
2103         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2104     }
2105
2106     if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) {
2107         VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
2108         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2109     }
2110
2111     if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) {
2112         VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
2113         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2114     }
2115
2116     if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) {
2117         VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
2118         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2119     }
2120
2121     if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) {
2122         VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
2123         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2124     }
2125
2126     if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) {
2127         VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
2128         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2129     }
2130
2131     if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
2132         return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos));
2133
2134     if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
2135         return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos));
2136
2137     if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
2138         return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos));
2139
2140     if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
2141         return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos));
2142
2143     if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
2144         return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos));
2145
2146     if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
2147         return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos));
2148
2149     if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
2150         return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos));
2151
2152     if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
2153         return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos));
2154
2155     if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) {
2156         VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
2157         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2158     }
2159
2160     if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) {
2161         int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
2162         if (length < 0)
2163             return nil;
2164         return [NSNumber numberWithInt:length];
2165     }
2166
2167     if (m_object->isDataTable()) {
2168         if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
2169             if (array == nil || [array count] != 2)
2170                 return nil;
2171             AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
2172             if (!cell)
2173                 return nil;
2174             
2175             return cell->wrapper();
2176         }
2177     }
2178
2179     if (m_object->isTextControl()) {
2180         if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
2181             int lineNumber = m_object->doAXLineForIndex(intNumber);
2182             if (lineNumber < 0)
2183                 return nil;
2184             return [NSNumber numberWithUnsignedInt:lineNumber];
2185         }
2186
2187         if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
2188             PlainTextRange textRange = m_object->doAXRangeForLine(intNumber);
2189             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2190         }
2191
2192         if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
2193             return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
2194
2195         if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
2196             if (!pointSet)
2197                 return nil;
2198             PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
2199             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2200         }
2201
2202         if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
2203             PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber);
2204             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2205         }
2206
2207         if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
2208             if (!rangeSet)
2209                 return nil;
2210             NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
2211             return [NSValue valueWithRect:rect];
2212         }
2213
2214         if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2215             return rangeSet ? [self doAXRTFForRange:range] : nil;
2216
2217         if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2218             return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
2219
2220         if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
2221             PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber);
2222             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2223         }
2224     }
2225
2226     return nil;
2227 }
2228
2229 - (BOOL)accessibilityShouldUseUniqueId
2230 {
2231     return m_object->accessibilityShouldUseUniqueId();
2232 }
2233
2234 // API that AppKit uses for faster access
2235 - (NSUInteger)accessibilityIndexOfChild:(id)child
2236 {
2237     if (!m_object)
2238         return NSNotFound;
2239
2240     m_object->updateBackingStore();
2241     if (!m_object)
2242         return NSNotFound;
2243
2244     const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2245        
2246     if (children.isEmpty())
2247         return [[self renderWidgetChildren] indexOfObject:child];
2248     
2249     unsigned count = children.size();
2250     for (unsigned k = 0; k < count; ++k) {
2251         AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
2252         if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child)) 
2253             return k;
2254     }
2255
2256     return NSNotFound;
2257 }
2258
2259 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
2260 {
2261     if (!m_object)
2262         return 0;
2263
2264     m_object->updateBackingStore();
2265     if (!m_object)
2266         return 0;
2267     
2268     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2269         const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2270         if (children.isEmpty())
2271             return [[self renderWidgetChildren] count];
2272         
2273         return children.size();
2274     }
2275     
2276     return [super accessibilityArrayAttributeCount:attribute];
2277 }
2278
2279 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount 
2280 {
2281     if (!m_object)
2282         return nil;
2283
2284     m_object->updateBackingStore();
2285     if (!m_object)
2286         return nil;
2287     
2288     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2289         if (m_object->children().isEmpty()) {
2290             NSArray *children = [self renderWidgetChildren];
2291             if (!children) 
2292                 return nil;
2293             
2294             NSUInteger childCount = [children count];
2295             if (index >= childCount)
2296                 return nil;
2297             
2298             NSUInteger arrayLength = min(childCount - index, maxCount);
2299             return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
2300         }
2301         
2302         const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2303         unsigned childCount = children.size();
2304         if (index >= childCount)
2305             return nil;
2306         
2307         unsigned available = min(childCount - index, maxCount);
2308         
2309         NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
2310         for (unsigned added = 0; added < available; ++index, ++added) {
2311             AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
2312             if (wrapper) {
2313                 // The attachment view should be returned, otherwise AX palindrome errors occur.
2314                 if (children[index]->isAttachment() && [wrapper attachmentView])
2315                     [subarray addObject:[wrapper attachmentView]];
2316                 else
2317                     [subarray addObject:wrapper];
2318             }
2319         }
2320         
2321         return subarray;
2322     }
2323     
2324     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2325 }
2326
2327 @end
2328
2329 #endif // HAVE(ACCESSIBILITY)