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