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