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