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