• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "config.h"
30#import "AccessibilityObjectWrapper.h"
31
32#if HAVE(ACCESSIBILITY)
33
34#import "AXObjectCache.h"
35#import "AccessibilityARIAGridRow.h"
36#import "AccessibilityListBox.h"
37#import "AccessibilityList.h"
38#import "AccessibilityRenderObject.h"
39#import "AccessibilityTable.h"
40#import "AccessibilityTableCell.h"
41#import "AccessibilityTableRow.h"
42#import "AccessibilityTableColumn.h"
43#import "ColorMac.h"
44#import "Frame.h"
45#import "HTMLAnchorElement.h"
46#import "HTMLAreaElement.h"
47#import "HTMLImageElement.h"
48#import "HTMLInputElement.h"
49#import "HTMLTextAreaElement.h"
50#import "LocalizedStrings.h"
51#import "RenderTextControl.h"
52#import "RenderView.h"
53#import "RenderWidget.h"
54#import "SelectionController.h"
55#import "SimpleFontData.h"
56#import "TextIterator.h"
57#import "WebCoreFrameView.h"
58#import "WebCoreObjCExtras.h"
59#import "WebCoreViewFactory.h"
60#import "htmlediting.h"
61#import "visible_units.h"
62#import <runtime/InitializeThreading.h>
63
64using namespace WebCore;
65using namespace HTMLNames;
66using namespace std;
67
68// Cell Tables
69#ifndef NSAccessibilitySelectedCellsAttribute
70#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
71#endif
72
73#ifndef NSAccessibilityVisibleCellsAttribute
74#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
75#endif
76
77#ifndef NSAccessibilityRowHeaderUIElementsAttribute
78#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements"
79#endif
80
81#ifndef NSAccessibilityRowIndexRangeAttribute
82#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
83#endif
84
85#ifndef NSAccessibilityColumnIndexRangeAttribute
86#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
87#endif
88
89#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
90#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
91#endif
92
93#ifndef NSAccessibilityCellRole
94#define NSAccessibilityCellRole @"AXCell"
95#endif
96
97// Lists
98#ifndef NSAccessibilityContentListSubrole
99#define NSAccessibilityContentListSubrole @"AXContentList"
100#endif
101
102#ifndef NSAccessibilityDefinitionListSubrole
103#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
104#endif
105
106// Miscellaneous
107#ifndef NSAccessibilityBlockQuoteLevelAttribute
108#define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
109#endif
110
111#ifndef NSAccessibilityAccessKeyAttribute
112#define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
113#endif
114
115#ifndef NSAccessibilityLanguageAttribute
116#define NSAccessibilityLanguageAttribute @"AXLanguage"
117#endif
118
119#ifndef NSAccessibilityRequiredAttribute
120#define NSAccessibilityRequiredAttribute @"AXRequired"
121#endif
122
123#ifndef NSAccessibilityOwnsAttribute
124#define NSAccessibilityOwnsAttribute @"AXOwns"
125#endif
126
127#ifndef NSAccessibilityGrabbedAttribute
128#define NSAccessibilityGrabbedAttribute @"AXGrabbed"
129#endif
130
131#ifndef NSAccessibilityDropEffectsAttribute
132#define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
133#endif
134
135#ifndef NSAccessibilityARIALiveAttribute
136#define NSAccessibilityARIALiveAttribute @"AXARIALive"
137#endif
138
139#ifndef NSAccessibilityARIAAtomicAttribute
140#define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
141#endif
142
143#ifndef NSAccessibilityARIARelevantAttribute
144#define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
145#endif
146
147#ifndef NSAccessibilityARIABusyAttribute
148#define NSAccessibilityARIABusyAttribute @"AXARIABusy"
149#endif
150
151#ifndef NSAccessibilityLoadingProgressAttribute
152#define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
153#endif
154
155#ifdef BUILDING_ON_TIGER
156typedef unsigned NSUInteger;
157#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
158#define NSAccessibilityTimelineSubrole @"AXTimeline"
159#endif
160
161@interface NSObject (WebKitAccessibilityArrayCategory)
162
163- (NSUInteger)accessibilityIndexOfChild:(id)child;
164- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
165- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
166
167@end
168
169@implementation AccessibilityObjectWrapper
170
171+ (void)initialize
172{
173    JSC::initializeThreading();
174#ifndef BUILDING_ON_TIGER
175    WebCoreObjCFinalizeOnMainThread(self);
176#endif
177}
178
179- (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
180{
181    [super init];
182
183    m_object = axObject;
184    return self;
185}
186
187- (void)unregisterUniqueIdForUIElement
188{
189    [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
190}
191
192- (void)detach
193{
194    // Send unregisterUniqueIdForUIElement unconditionally because if it is
195    // ever accidentally not done (via other bugs in our AX implementation) you
196    // end up with a crash like <rdar://problem/4273149>.  It is safe and not
197    // expensive to send even if the object is not registered.
198    [self unregisterUniqueIdForUIElement];
199    m_object = 0;
200}
201
202- (AccessibilityObject*)accessibilityObject
203{
204    return m_object;
205}
206
207- (NSView*)attachmentView
208{
209    ASSERT(m_object->isAttachment());
210    Widget* widget = m_object->widgetForAttachmentView();
211    if (!widget)
212        return nil;
213    return NSAccessibilityUnignoredDescendant(widget->platformWidget());
214}
215
216static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos)
217{
218    TextMarkerData textMarkerData;
219    AXObjectCache::textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
220    if (!textMarkerData.axID)
221        return nil;
222
223    return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)];
224}
225
226static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker)
227{
228    TextMarkerData textMarkerData;
229    if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)])
230        return VisiblePosition();
231
232    return AXObjectCache::visiblePositionForTextMarkerData(textMarkerData);
233}
234
235static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
236{
237    return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]);
238}
239
240static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
241{
242    return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]);
243}
244
245static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2)
246{
247    if (!textMarker1 || !textMarker2)
248        return nil;
249
250    return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
251}
252
253static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
254{
255    NSDictionary* dict;
256
257    if (font) {
258        dict = [NSDictionary dictionaryWithObjectsAndKeys:
259            [font fontName]                             , NSAccessibilityFontNameKey,
260            [font familyName]                           , NSAccessibilityFontFamilyKey,
261            [font displayName]                          , NSAccessibilityVisibleNameKey,
262            [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
263        nil];
264
265        [attrString addAttribute:attribute value:dict range:range];
266    } else
267        [attrString removeAttribute:attribute range:range];
268
269}
270
271static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
272{
273    // get color information assuming NSDeviceRGBColorSpace
274    NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
275    if (rgbColor == nil)
276        rgbColor = [NSColor blackColor];
277    CGFloat components[4];
278    [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
279
280    // create a new CGColorRef to return
281    CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
282    CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
283    CGColorSpaceRelease(cgColorSpace);
284
285    // check for match with existing color
286    if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
287        CGColorRelease(cgColor);
288        cgColor = 0;
289    }
290
291    return cgColor;
292}
293
294static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
295{
296    if (color) {
297        CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
298        CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
299        if (cgColor) {
300            [attrString addAttribute:attribute value:(id)cgColor range:range];
301            CGColorRelease(cgColor);
302        }
303    } else
304        [attrString removeAttribute:attribute range:range];
305}
306
307static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
308{
309    if (number)
310        [attrString addAttribute:attribute value:number range:range];
311    else
312        [attrString removeAttribute:attribute range:range];
313}
314
315static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
316{
317    RenderStyle* style = renderer->style();
318
319    // set basic font info
320    AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
321
322    // set basic colors
323    AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range);
324    AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range);
325
326    // set super/sub scripting
327    EVerticalAlign alignment = style->verticalAlign();
328    if (alignment == SUB)
329        AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
330    else if (alignment == SUPER)
331        AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
332    else
333        [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
334
335    // set shadow
336    if (style->textShadow())
337        AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
338    else
339        [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
340
341    // set underline and strikethrough
342    int decor = style->textDecorationsInEffect();
343    if ((decor & UNDERLINE) == 0) {
344        [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
345        [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
346    }
347
348    if ((decor & LINE_THROUGH) == 0) {
349        [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
350        [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
351    }
352
353    if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
354        // find colors using quirk mode approach (strict mode would use current
355        // color for all but the root line box, which would use getTextDecorationColors)
356        Color underline, overline, linethrough;
357        renderer->getTextDecorationColors(decor, underline, overline, linethrough);
358
359        if ((decor & UNDERLINE) != 0) {
360            AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
361            AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
362        }
363
364        if ((decor & LINE_THROUGH) != 0) {
365            AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
366            AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
367        }
368    }
369}
370
371static int blockquoteLevel(RenderObject* renderer)
372{
373    if (!renderer)
374        return 0;
375
376    int result = 0;
377    for (Node* node = renderer->node(); node; node = node->parent()) {
378        if (node->hasTagName(blockquoteTag))
379            result += 1;
380    }
381
382    return result;
383}
384
385static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
386{
387    int quoteLevel = blockquoteLevel(renderer);
388
389    if (quoteLevel)
390        [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
391    else
392        [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
393}
394
395static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range)
396{
397    Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node);
398    Vector<DocumentMarker>::iterator markerIt = markers.begin();
399
400    unsigned endOffset = (unsigned)offset + range.length;
401    for ( ; markerIt != markers.end(); markerIt++) {
402        DocumentMarker marker = *markerIt;
403
404        if (marker.type != DocumentMarker::Spelling)
405            continue;
406
407        if (marker.endOffset <= (unsigned)offset)
408            continue;
409
410        if (marker.startOffset > endOffset)
411            break;
412
413        // add misspelling attribute for the intersection of the marker and the range
414        int rStart = range.location + (marker.startOffset - offset);
415        int rLength = min(marker.endOffset, endOffset) - marker.startOffset;
416        NSRange spellRange = NSMakeRange(rStart, rLength);
417        AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
418
419        if (marker.endOffset > endOffset + 1)
420            break;
421    }
422}
423
424static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
425{
426    if (!renderer)
427        return;
428
429    AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent());
430    int parentHeadingLevel = parentObject->headingLevel();
431
432    if (parentHeadingLevel)
433        [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
434    else
435        [attrString removeAttribute:@"AXHeadingLevel" range:range];
436}
437
438static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
439{
440    if (object && object->isAccessibilityRenderObject()) {
441        // make a serializable AX object
442
443        RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
444        if (!renderer)
445            return;
446
447        Document* doc = renderer->document();
448        if (!doc)
449            return;
450
451        AXObjectCache* cache = doc->axObjectCache();
452        if (!cache)
453            return;
454
455        AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()];
456        if (axElement) {
457            [attrString addAttribute:attribute value:(id)axElement range:range];
458            CFRelease(axElement);
459        }
460    } else
461        [attrString removeAttribute:attribute range:range];
462}
463
464static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length)
465{
466    // skip invisible text
467    if (!node->renderer())
468        return;
469
470    // easier to calculate the range before appending the string
471    NSRange attrStringRange = NSMakeRange([attrString length], length);
472
473    // append the string from this node
474    [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
475
476    // add new attributes and remove irrelevant inherited ones
477    // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
478    // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
479    // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
480
481    // remove inherited attachment from prior AXAttributedStringAppendReplaced
482    [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
483
484    // set new attributes
485    AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
486    AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
487    AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
488    AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
489
490    // do spelling last because it tends to break up the range
491    AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);
492}
493
494static NSString* nsStringForReplacedNode(Node* replacedNode)
495{
496    // we should always be given a rendered node and a replaced node, but be safe
497    // replaced nodes are either attachments (widgets) or images
498    if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
499        ASSERT_NOT_REACHED();
500        return nil;
501    }
502
503    // create an AX object, but skip it if it is not supposed to be seen
504    RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
505    if (obj->accessibilityIsIgnored())
506        return nil;
507
508    // use the attachmentCharacter to represent the replaced node
509    const UniChar attachmentChar = NSAttachmentCharacter;
510    return [NSString stringWithCharacters:&attachmentChar length:1];
511}
512
513- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
514{
515    if (!m_object)
516        return nil;
517
518    // extract the start and end VisiblePosition
519    VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange);
520    if (startVisiblePosition.isNull())
521        return nil;
522
523    VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange);
524    if (endVisiblePosition.isNull())
525        return nil;
526
527    VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
528    // iterate over the range to build the AX attributed string
529    NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
530    TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
531    while (!it.atEnd()) {
532        // locate the node and starting offset for this range
533        int exception = 0;
534        Node* node = it.range()->startContainer(exception);
535        ASSERT(node == it.range()->endContainer(exception));
536        int offset = it.range()->startOffset(exception);
537
538        // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
539        if (it.length() != 0) {
540            // Add the text of the list marker item if necessary.
541            String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
542            if (!listMarkerText.isEmpty())
543                AXAttributedStringAppendText(attrString, node, offset, listMarkerText.characters(), listMarkerText.length());
544
545            AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length());
546        } else {
547            Node* replacedNode = node->childNode(offset);
548            NSString *attachmentString = nsStringForReplacedNode(replacedNode);
549            if (attachmentString) {
550                NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
551
552                // append the placeholder string
553                [[attrString mutableString] appendString:attachmentString];
554
555                // remove all inherited attributes
556                [attrString setAttributes:nil range:attrStringRange];
557
558                // add the attachment attribute
559                AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
560                AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
561            }
562        }
563        it.advance();
564    }
565
566    return [attrString autorelease];
567}
568
569static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition)
570{
571    WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition);
572    WebCoreTextMarker* endTextMarker   = textMarkerForVisiblePosition(endPosition);
573    return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
574}
575
576- (NSArray*)accessibilityActionNames
577{
578    if (!m_object)
579        return nil;
580
581    m_object->updateBackingStore();
582    if (!m_object)
583        return nil;
584
585    static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
586    static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
587    static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
588    static NSArray* sliderActions = [[NSArray alloc] initWithObjects: NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil];
589
590    NSArray *actions;
591    if (m_object->actionElement())
592        actions = actionElementActions;
593    else if (m_object->isMenuRelated())
594        actions = menuElementActions;
595    else if (m_object->isSlider())
596        actions = sliderActions;
597    else if (m_object->isAttachment())
598        actions = [[self attachmentView] accessibilityActionNames];
599    else
600        actions = defaultElementActions;
601
602    return actions;
603}
604
605- (NSArray*)additionalAccessibilityAttributeNames
606{
607    if (!m_object)
608        return nil;
609
610    NSMutableArray *additional = [NSMutableArray array];
611    if (m_object->supportsARIAOwns())
612        [additional addObject:NSAccessibilityOwnsAttribute];
613
614    if (m_object->isScrollbar())
615        [additional addObject:NSAccessibilityOrientationAttribute];
616
617    if (m_object->supportsARIADragging())
618        [additional addObject:NSAccessibilityGrabbedAttribute];
619
620    if (m_object->supportsARIADropping())
621        [additional addObject:NSAccessibilityDropEffectsAttribute];
622
623    if (m_object->isDataTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows())
624        [additional addObject:NSAccessibilitySelectedRowsAttribute];
625
626    if (m_object->supportsARIALiveRegion()) {
627        [additional addObject:NSAccessibilityARIALiveAttribute];
628        [additional addObject:NSAccessibilityARIARelevantAttribute];
629    }
630
631    // If an object is a child of a live region, then add these
632    if (m_object->isInsideARIALiveRegion()) {
633        [additional addObject:NSAccessibilityARIAAtomicAttribute];
634        [additional addObject:NSAccessibilityARIABusyAttribute];
635    }
636
637    return additional;
638}
639
640- (NSArray*)accessibilityAttributeNames
641{
642    if (!m_object)
643        return nil;
644
645    m_object->updateBackingStore();
646    if (!m_object)
647        return nil;
648
649    if (m_object->isAttachment())
650        return [[self attachmentView] accessibilityAttributeNames];
651
652    static NSArray* attributes = nil;
653    static NSArray* anchorAttrs = nil;
654    static NSArray* webAreaAttrs = nil;
655    static NSArray* textAttrs = nil;
656    static NSArray* listBoxAttrs = nil;
657    static NSArray* rangeAttrs = nil;
658    static NSArray* commonMenuAttrs = nil;
659    static NSArray* menuAttrs = nil;
660    static NSArray* menuBarAttrs = nil;
661    static NSArray* menuItemAttrs = nil;
662    static NSArray* menuButtonAttrs = nil;
663    static NSArray* controlAttrs = nil;
664    static NSArray* tableAttrs = nil;
665    static NSArray* tableRowAttrs = nil;
666    static NSArray* tableColAttrs = nil;
667    static NSArray* tableCellAttrs = nil;
668    static NSArray* groupAttrs = nil;
669    static NSArray* inputImageAttrs = nil;
670    static NSArray* passwordFieldAttrs = nil;
671    static NSArray* tabListAttrs = nil;
672    static NSArray* comboBoxAttrs = nil;
673    static NSArray* outlineAttrs = nil;
674    static NSArray* outlineRowAttrs = nil;
675    static NSArray* buttonAttrs = nil;
676    NSMutableArray* tempArray;
677    if (attributes == nil) {
678        attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
679                      NSAccessibilitySubroleAttribute,
680                      NSAccessibilityRoleDescriptionAttribute,
681                      NSAccessibilityChildrenAttribute,
682                      NSAccessibilityHelpAttribute,
683                      NSAccessibilityParentAttribute,
684                      NSAccessibilityPositionAttribute,
685                      NSAccessibilitySizeAttribute,
686                      NSAccessibilityTitleAttribute,
687                      NSAccessibilityDescriptionAttribute,
688                      NSAccessibilityValueAttribute,
689                      NSAccessibilityFocusedAttribute,
690                      NSAccessibilityEnabledAttribute,
691                      NSAccessibilityWindowAttribute,
692                      @"AXSelectedTextMarkerRange",
693                      @"AXStartTextMarker",
694                      @"AXEndTextMarker",
695                      @"AXVisited",
696                      NSAccessibilityLinkedUIElementsAttribute,
697                      NSAccessibilitySelectedAttribute,
698                      NSAccessibilityBlockQuoteLevelAttribute,
699                      NSAccessibilityTopLevelUIElementAttribute,
700                      nil];
701    }
702    if (commonMenuAttrs == nil) {
703        commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
704                            NSAccessibilityRoleDescriptionAttribute,
705                            NSAccessibilityChildrenAttribute,
706                            NSAccessibilityParentAttribute,
707                            NSAccessibilityEnabledAttribute,
708                            NSAccessibilityPositionAttribute,
709                            NSAccessibilitySizeAttribute,
710                            nil];
711    }
712    if (anchorAttrs == nil) {
713        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
714        [tempArray addObject:NSAccessibilityURLAttribute];
715        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
716        anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
717        [tempArray release];
718    }
719    if (webAreaAttrs == nil) {
720        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
721        [tempArray addObject:@"AXLinkUIElements"];
722        [tempArray addObject:@"AXLoaded"];
723        [tempArray addObject:@"AXLayoutCount"];
724        [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
725        [tempArray addObject:NSAccessibilityURLAttribute];
726        webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
727        [tempArray release];
728    }
729    if (textAttrs == nil) {
730        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
731        [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
732        [tempArray addObject:NSAccessibilitySelectedTextAttribute];
733        [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
734        [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
735        [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
736        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
737        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
738        [tempArray addObject:NSAccessibilityRequiredAttribute];
739        textAttrs = [[NSArray alloc] initWithArray:tempArray];
740        [tempArray release];
741    }
742    if (listBoxAttrs == nil) {
743        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
744        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
745        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
746        [tempArray addObject:NSAccessibilityOrientationAttribute];
747        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
748        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
749        [tempArray addObject:NSAccessibilityRequiredAttribute];
750        listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
751        [tempArray release];
752    }
753    if (rangeAttrs == nil) {
754        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
755        [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
756        [tempArray addObject:NSAccessibilityValueAttribute];
757        [tempArray addObject:NSAccessibilityMinValueAttribute];
758        [tempArray addObject:NSAccessibilityMaxValueAttribute];
759        [tempArray addObject:NSAccessibilityOrientationAttribute];
760        [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
761        rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
762        [tempArray release];
763    }
764    if (menuBarAttrs == nil) {
765        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
766        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
767        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
768        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
769        menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
770        [tempArray release];
771    }
772    if (menuAttrs == nil) {
773        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
774        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
775        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
776        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
777        menuAttrs = [[NSArray alloc] initWithArray:tempArray];
778        [tempArray release];
779    }
780    if (menuItemAttrs == nil) {
781        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
782        [tempArray addObject:NSAccessibilityTitleAttribute];
783        [tempArray addObject:NSAccessibilityHelpAttribute];
784        [tempArray addObject:NSAccessibilitySelectedAttribute];
785        [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
786        [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
787        [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
788        [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
789        [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
790        [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
791        [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
792        menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
793        [tempArray release];
794    }
795    if (menuButtonAttrs == nil) {
796        menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
797            NSAccessibilityRoleDescriptionAttribute,
798            NSAccessibilityParentAttribute,
799            NSAccessibilityPositionAttribute,
800            NSAccessibilitySizeAttribute,
801            NSAccessibilityWindowAttribute,
802            NSAccessibilityTopLevelUIElementAttribute,
803            NSAccessibilityEnabledAttribute,
804            NSAccessibilityFocusedAttribute,
805            NSAccessibilityTitleAttribute,
806            NSAccessibilityChildrenAttribute, nil];
807    }
808    if (controlAttrs == nil) {
809        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
810        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
811        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
812        [tempArray addObject:NSAccessibilityRequiredAttribute];
813        controlAttrs = [[NSArray alloc] initWithArray:tempArray];
814        [tempArray release];
815    }
816    if (buttonAttrs == nil) {
817        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
818        // Buttons should not expose AXValue.
819        [tempArray removeObject:NSAccessibilityValueAttribute];
820        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
821        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
822        buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
823        [tempArray release];
824    }
825    if (comboBoxAttrs == nil) {
826        tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
827        [tempArray addObject:NSAccessibilityExpandedAttribute];
828        comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
829        [tempArray release];
830    }
831    if (tableAttrs == nil) {
832        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
833        [tempArray addObject:NSAccessibilityRowsAttribute];
834        [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
835        [tempArray addObject:NSAccessibilityColumnsAttribute];
836        [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
837        [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
838        [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
839        [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
840        [tempArray addObject:NSAccessibilityHeaderAttribute];
841        tableAttrs = [[NSArray alloc] initWithArray:tempArray];
842        [tempArray release];
843    }
844    if (tableRowAttrs == nil) {
845        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
846        [tempArray addObject:NSAccessibilityIndexAttribute];
847        tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
848        [tempArray release];
849    }
850    if (tableColAttrs == nil) {
851        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
852        [tempArray addObject:NSAccessibilityIndexAttribute];
853        [tempArray addObject:NSAccessibilityHeaderAttribute];
854        [tempArray addObject:NSAccessibilityRowsAttribute];
855        [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
856        tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
857        [tempArray release];
858    }
859    if (tableCellAttrs == nil) {
860        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
861        [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
862        [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
863        tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
864        [tempArray release];
865    }
866    if (groupAttrs == nil) {
867        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
868        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
869        groupAttrs = [[NSArray alloc] initWithArray:tempArray];
870        [tempArray release];
871    }
872    if (inputImageAttrs == nil) {
873        tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
874        [tempArray addObject:NSAccessibilityURLAttribute];
875        inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
876        [tempArray release];
877    }
878    if (passwordFieldAttrs == nil) {
879        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
880        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
881        [tempArray addObject:NSAccessibilityRequiredAttribute];
882        passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
883        [tempArray release];
884    }
885    if (tabListAttrs == nil) {
886        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
887        [tempArray addObject:NSAccessibilityTabsAttribute];
888        [tempArray addObject:NSAccessibilityContentsAttribute];
889        tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
890        [tempArray release];
891    }
892    if (outlineAttrs == nil) {
893        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
894        [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
895        [tempArray addObject:NSAccessibilityRowsAttribute];
896        [tempArray addObject:NSAccessibilityColumnsAttribute];
897        outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
898        [tempArray release];
899    }
900    if (outlineRowAttrs == nil) {
901        tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
902        [tempArray addObject:NSAccessibilityDisclosingAttribute];
903        [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
904        [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
905        [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
906        outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
907        [tempArray release];
908    }
909
910    NSArray *objectAttributes = attributes;
911
912    if (m_object->isPasswordField())
913        objectAttributes = passwordFieldAttrs;
914
915    else if (m_object->isWebArea())
916        objectAttributes = webAreaAttrs;
917
918    else if (m_object->isTextControl())
919        objectAttributes = textAttrs;
920
921    else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
922        objectAttributes = anchorAttrs;
923
924    else if (m_object->isDataTable())
925        objectAttributes = tableAttrs;
926    else if (m_object->isTableColumn())
927        objectAttributes = tableColAttrs;
928    else if (m_object->isTableCell())
929        objectAttributes = tableCellAttrs;
930    else if (m_object->isTableRow()) {
931        // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
932        if (m_object->isARIATreeGridRow())
933            objectAttributes = outlineRowAttrs;
934        else
935            objectAttributes = tableRowAttrs;
936    }
937
938    else if (m_object->isTree())
939        objectAttributes = outlineAttrs;
940    else if (m_object->isTreeItem())
941        objectAttributes = outlineRowAttrs;
942
943    else if (m_object->isListBox() || m_object->isList())
944        objectAttributes = listBoxAttrs;
945
946    else if (m_object->isComboBox())
947        objectAttributes = comboBoxAttrs;
948
949    else if (m_object->isProgressIndicator() || m_object->isSlider())
950        objectAttributes = rangeAttrs;
951
952    // These are processed in order because an input image is a button, and a button is a control.
953    else if (m_object->isInputImage())
954        objectAttributes = inputImageAttrs;
955    else if (m_object->isButton())
956        objectAttributes = buttonAttrs;
957    else if (m_object->isControl())
958        objectAttributes = controlAttrs;
959
960    else if (m_object->isGroup())
961        objectAttributes = groupAttrs;
962    else if (m_object->isTabList())
963        objectAttributes = tabListAttrs;
964
965    else if (m_object->isMenu())
966        objectAttributes = menuAttrs;
967    else if (m_object->isMenuBar())
968        objectAttributes = menuBarAttrs;
969    else if (m_object->isMenuButton())
970        objectAttributes = menuButtonAttrs;
971    else if (m_object->isMenuItem())
972        objectAttributes = menuItemAttrs;
973
974    NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
975    if ([additionalAttributes count])
976        objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
977
978    return objectAttributes;
979}
980
981- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
982{
983    return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange));
984}
985
986- (NSArray*)renderWidgetChildren
987{
988    Widget* widget = m_object->widget();
989    if (!widget)
990        return nil;
991    return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
992}
993
994static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
995{
996    unsigned length = [array count];
997    vector.reserveInitialCapacity(length);
998    for (unsigned i = 0; i < length; ++i) {
999        AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1000        if (obj)
1001            vector.append(obj);
1002    }
1003}
1004
1005static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1006{
1007    unsigned length = vector.size();
1008    NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
1009    for (unsigned i = 0; i < length; ++i) {
1010        AccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
1011        ASSERT(wrapper);
1012        if (wrapper) {
1013            // we want to return the attachment view instead of the object representing the attachment.
1014            // otherwise, we get palindrome errors in the AX hierarchy
1015            if (vector[i]->isAttachment() && [wrapper attachmentView])
1016                [array addObject:[wrapper attachmentView]];
1017            else
1018                [array addObject:wrapper];
1019        }
1020    }
1021    return array;
1022}
1023
1024- (WebCoreTextMarkerRange*)textMarkerRangeForSelection
1025{
1026    VisibleSelection selection = m_object->selection();
1027    if (selection.isNone())
1028        return nil;
1029    return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd());
1030}
1031
1032- (NSValue*)position
1033{
1034    IntRect rect = m_object->elementRect();
1035
1036    // The Cocoa accessibility API wants the lower-left corner.
1037    NSPoint point = NSMakePoint(rect.x(), rect.bottom());
1038    FrameView* frameView = m_object->documentFrameView();
1039    if (frameView) {
1040        NSView* view = frameView->documentView();
1041        point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
1042    }
1043
1044    return [NSValue valueWithPoint: point];
1045}
1046
1047typedef HashMap<int, NSString*> AccessibilityRoleMap;
1048
1049static const AccessibilityRoleMap& createAccessibilityRoleMap()
1050{
1051    struct RoleEntry {
1052        AccessibilityRole value;
1053        NSString* string;
1054    };
1055
1056    static const RoleEntry roles[] = {
1057        { UnknownRole, NSAccessibilityUnknownRole },
1058        { ButtonRole, NSAccessibilityButtonRole },
1059        { RadioButtonRole, NSAccessibilityRadioButtonRole },
1060        { CheckBoxRole, NSAccessibilityCheckBoxRole },
1061        { SliderRole, NSAccessibilitySliderRole },
1062        { TabGroupRole, NSAccessibilityTabGroupRole },
1063        { TextFieldRole, NSAccessibilityTextFieldRole },
1064        { StaticTextRole, NSAccessibilityStaticTextRole },
1065        { TextAreaRole, NSAccessibilityTextAreaRole },
1066        { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1067        { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1068        { MenuButtonRole, NSAccessibilityMenuButtonRole },
1069        { TableRole, NSAccessibilityTableRole },
1070        { ApplicationRole, NSAccessibilityApplicationRole },
1071        { GroupRole, NSAccessibilityGroupRole },
1072        { RadioGroupRole, NSAccessibilityRadioGroupRole },
1073        { ListRole, NSAccessibilityListRole },
1074        { DirectoryRole, NSAccessibilityListRole },
1075        { ScrollBarRole, NSAccessibilityScrollBarRole },
1076        { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1077        { ImageRole, NSAccessibilityImageRole },
1078        { MenuBarRole, NSAccessibilityMenuBarRole },
1079        { MenuRole, NSAccessibilityMenuRole },
1080        { MenuItemRole, NSAccessibilityMenuItemRole },
1081        { ColumnRole, NSAccessibilityColumnRole },
1082        { RowRole, NSAccessibilityRowRole },
1083        { ToolbarRole, NSAccessibilityToolbarRole },
1084        { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1085        { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1086        { WindowRole, NSAccessibilityWindowRole },
1087        { DrawerRole, NSAccessibilityDrawerRole },
1088        { SystemWideRole, NSAccessibilitySystemWideRole },
1089        { OutlineRole, NSAccessibilityOutlineRole },
1090        { IncrementorRole, NSAccessibilityIncrementorRole },
1091        { BrowserRole, NSAccessibilityBrowserRole },
1092        { ComboBoxRole, NSAccessibilityComboBoxRole },
1093        { SplitGroupRole, NSAccessibilitySplitGroupRole },
1094        { SplitterRole, NSAccessibilitySplitterRole },
1095        { ColorWellRole, NSAccessibilityColorWellRole },
1096        { GrowAreaRole, NSAccessibilityGrowAreaRole },
1097        { SheetRole, NSAccessibilitySheetRole },
1098        { HelpTagRole, NSAccessibilityHelpTagRole },
1099        { MatteRole, NSAccessibilityMatteRole },
1100        { RulerRole, NSAccessibilityRulerRole },
1101        { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1102        { LinkRole, NSAccessibilityLinkRole },
1103#ifndef BUILDING_ON_TIGER
1104        { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1105        { GridRole, NSAccessibilityGridRole },
1106#endif
1107        { WebCoreLinkRole, NSAccessibilityLinkRole },
1108        { ImageMapLinkRole, NSAccessibilityLinkRole },
1109        { ImageMapRole, @"AXImageMap" },
1110        { ListMarkerRole, @"AXListMarker" },
1111        { WebAreaRole, @"AXWebArea" },
1112        { HeadingRole, @"AXHeading" },
1113        { ListBoxRole, NSAccessibilityListRole },
1114        { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1115#if ACCESSIBILITY_TABLES
1116        { CellRole, NSAccessibilityCellRole },
1117#else
1118        { CellRole, NSAccessibilityGroupRole },
1119#endif
1120        { TableHeaderContainerRole, NSAccessibilityGroupRole },
1121        { DefinitionListDefinitionRole, NSAccessibilityGroupRole },
1122        { DefinitionListTermRole, NSAccessibilityGroupRole },
1123        { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1124        { LandmarkApplicationRole, NSAccessibilityGroupRole },
1125        { LandmarkBannerRole, NSAccessibilityGroupRole },
1126        { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1127        { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1128        { LandmarkMainRole, NSAccessibilityGroupRole },
1129        { LandmarkNavigationRole, NSAccessibilityGroupRole },
1130        { LandmarkSearchRole, NSAccessibilityGroupRole },
1131        { ApplicationAlertRole, NSAccessibilityGroupRole },
1132        { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1133        { ApplicationDialogRole, NSAccessibilityGroupRole },
1134        { ApplicationLogRole, NSAccessibilityGroupRole },
1135        { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1136        { ApplicationStatusRole, NSAccessibilityGroupRole },
1137        { ApplicationTimerRole, NSAccessibilityGroupRole },
1138        { DocumentRole, NSAccessibilityGroupRole },
1139        { DocumentArticleRole, NSAccessibilityGroupRole },
1140        { DocumentMathRole, NSAccessibilityGroupRole },
1141        { DocumentNoteRole, NSAccessibilityGroupRole },
1142        { DocumentRegionRole, NSAccessibilityGroupRole },
1143        { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1144        { TabRole, NSAccessibilityRadioButtonRole },
1145        { TabListRole, NSAccessibilityTabGroupRole },
1146        { TabPanelRole, NSAccessibilityGroupRole },
1147        { TreeRole, NSAccessibilityOutlineRole },
1148        { TreeItemRole, NSAccessibilityRowRole },
1149    };
1150    AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1151
1152    const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1153    for (unsigned i = 0; i < numRoles; ++i)
1154        roleMap.set(roles[i].value, roles[i].string);
1155    return roleMap;
1156}
1157
1158static NSString* roleValueToNSString(AccessibilityRole value)
1159{
1160    ASSERT(value);
1161    static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1162    return roleMap.get(value);
1163}
1164
1165- (NSString*)role
1166{
1167    if (m_object->isAttachment())
1168        return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1169    NSString* string = roleValueToNSString(m_object->roleValue());
1170    if (string != nil)
1171        return string;
1172    return NSAccessibilityUnknownRole;
1173}
1174
1175- (NSString*)subrole
1176{
1177    if (m_object->isPasswordField())
1178        return NSAccessibilitySecureTextFieldSubrole;
1179
1180    if (m_object->isAttachment()) {
1181        NSView* attachView = [self attachmentView];
1182        if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1183            return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1184        }
1185    }
1186
1187    if (m_object->isTreeItem())
1188        return NSAccessibilityOutlineRowSubrole;
1189
1190    if (m_object->isList()) {
1191        AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
1192        if (listObject->isUnorderedList() || listObject->isOrderedList())
1193            return NSAccessibilityContentListSubrole;
1194        if (listObject->isDefinitionList())
1195            return NSAccessibilityDefinitionListSubrole;
1196    }
1197
1198    // ARIA content subroles.
1199    switch (m_object->roleValue()) {
1200        case LandmarkApplicationRole:
1201            return @"AXLandmarkApplication";
1202        case LandmarkBannerRole:
1203            return @"AXLandmarkBanner";
1204        case LandmarkComplementaryRole:
1205            return @"AXLandmarkComplementary";
1206        case LandmarkContentInfoRole:
1207            return @"AXLandmarkContentInfo";
1208        case LandmarkMainRole:
1209            return @"AXLandmarkMain";
1210        case LandmarkNavigationRole:
1211            return @"AXLandmarkNavigation";
1212        case LandmarkSearchRole:
1213            return @"AXLandmarkSearch";
1214        case ApplicationAlertRole:
1215            return @"AXApplicationAlert";
1216        case ApplicationAlertDialogRole:
1217            return @"AXApplicationAlertDialog";
1218        case ApplicationDialogRole:
1219            return @"AXApplicationDialog";
1220        case ApplicationLogRole:
1221            return @"AXApplicationLog";
1222        case ApplicationMarqueeRole:
1223            return @"AXApplicationMarquee";
1224        case ApplicationStatusRole:
1225            return @"AXApplicationStatus";
1226        case ApplicationTimerRole:
1227            return @"AXApplicationTimer";
1228        case DocumentRole:
1229            return @"AXDocument";
1230        case DocumentArticleRole:
1231            return @"AXDocumentArticle";
1232        case DocumentMathRole:
1233            return @"AXDocumentMath";
1234        case DocumentNoteRole:
1235            return @"AXDocumentNote";
1236        case DocumentRegionRole:
1237            return @"AXDocumentRegion";
1238        case UserInterfaceTooltipRole:
1239            return @"AXUserInterfaceTooltip";
1240        case TabPanelRole:
1241            return @"AXTabPanel";
1242        case DefinitionListTermRole:
1243            return @"AXTerm";
1244        case DefinitionListDefinitionRole:
1245            return @"AXDefinition";
1246        // Default doesn't return anything, so roles defined below can be chosen.
1247        default:
1248            break;
1249    }
1250
1251    if (m_object->isMediaTimeline())
1252        return NSAccessibilityTimelineSubrole;
1253
1254    return nil;
1255}
1256
1257- (NSString*)roleDescription
1258{
1259    if (!m_object)
1260        return nil;
1261
1262    // attachments have the AXImage role, but a different subrole
1263    if (m_object->isAttachment())
1264        return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1265
1266    NSString* axRole = [self role];
1267
1268    if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1269        switch (m_object->roleValue()) {
1270            default:
1271                return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1272            case LandmarkApplicationRole:
1273                return AXARIAContentGroupText(@"ARIALandmarkApplication");
1274            case LandmarkBannerRole:
1275                return AXARIAContentGroupText(@"ARIALandmarkBanner");
1276            case LandmarkComplementaryRole:
1277                return AXARIAContentGroupText(@"ARIALandmarkComplementary");
1278            case LandmarkContentInfoRole:
1279                return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
1280            case LandmarkMainRole:
1281                return AXARIAContentGroupText(@"ARIALandmarkMain");
1282            case LandmarkNavigationRole:
1283                return AXARIAContentGroupText(@"ARIALandmarkNavigation");
1284            case LandmarkSearchRole:
1285                return AXARIAContentGroupText(@"ARIALandmarkSearch");
1286            case ApplicationAlertRole:
1287                return AXARIAContentGroupText(@"ARIAApplicationAlert");
1288            case ApplicationAlertDialogRole:
1289                return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
1290            case ApplicationDialogRole:
1291                return AXARIAContentGroupText(@"ARIAApplicationDialog");
1292            case ApplicationLogRole:
1293                return AXARIAContentGroupText(@"ARIAApplicationLog");
1294            case ApplicationMarqueeRole:
1295                return AXARIAContentGroupText(@"ARIAApplicationMarquee");
1296            case ApplicationStatusRole:
1297                return AXARIAContentGroupText(@"ARIAApplicationStatus");
1298            case ApplicationTimerRole:
1299                return AXARIAContentGroupText(@"ARIAApplicationTimer");
1300            case DocumentRole:
1301                return AXARIAContentGroupText(@"ARIADocument");
1302            case DocumentArticleRole:
1303                return AXARIAContentGroupText(@"ARIADocumentArticle");
1304            case DocumentMathRole:
1305                return AXARIAContentGroupText(@"ARIADocumentMath");
1306            case DocumentNoteRole:
1307                return AXARIAContentGroupText(@"ARIADocumentNote");
1308            case DocumentRegionRole:
1309                return AXARIAContentGroupText(@"ARIADocumentRegion");
1310            case UserInterfaceTooltipRole:
1311                return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
1312            case TabPanelRole:
1313                return AXARIAContentGroupText(@"ARIATabPanel");
1314            case DefinitionListTermRole:
1315                return AXDefinitionListTermText();
1316            case DefinitionListDefinitionRole:
1317                return AXDefinitionListDefinitionText();
1318        }
1319    }
1320
1321    if ([axRole isEqualToString:@"AXWebArea"])
1322        return AXWebAreaText();
1323
1324    if ([axRole isEqualToString:@"AXLink"])
1325        return AXLinkText();
1326
1327    if ([axRole isEqualToString:@"AXListMarker"])
1328        return AXListMarkerText();
1329
1330    if ([axRole isEqualToString:@"AXImageMap"])
1331        return AXImageMapText();
1332
1333    if ([axRole isEqualToString:@"AXHeading"])
1334        return AXHeadingText();
1335
1336    // AppKit also returns AXTab for the role description for a tab item.
1337    if (m_object->isTabItem())
1338        return NSAccessibilityRoleDescription(@"AXTab", nil);
1339
1340    // We should try the system default role description for all other roles.
1341    // If we get the same string back, then as a last resort, return unknown.
1342    NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1343    if (![defaultRoleDescription isEqualToString:axRole])
1344        return defaultRoleDescription;
1345
1346    return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1347}
1348
1349// FIXME: split up this function in a better way.
1350// suggestions: Use a hash table that maps attribute names to function calls,
1351// or maybe pointers to member functions
1352- (id)accessibilityAttributeValue:(NSString*)attributeName
1353{
1354    if (!m_object)
1355        return nil;
1356
1357    m_object->updateBackingStore();
1358    if (!m_object)
1359        return nil;
1360
1361    if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1362        return [self role];
1363
1364    if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1365        return [self subrole];
1366
1367    if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1368        return [self roleDescription];
1369
1370    if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1371        if (m_object->isAccessibilityRenderObject()) {
1372            FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
1373            if (fv)
1374                return fv->platformWidget();
1375        }
1376
1377        // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1378        if (m_object->isTreeItem()) {
1379            AccessibilityObject* parent = m_object->parentObjectUnignored();
1380            while (parent) {
1381                if (parent->isTree())
1382                    return parent->wrapper();
1383                parent = parent->parentObjectUnignored();
1384            }
1385        }
1386
1387        return m_object->parentObjectUnignored()->wrapper();
1388    }
1389
1390    if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1391        if (m_object->children().isEmpty()) {
1392            NSArray* children = [self renderWidgetChildren];
1393            if (children != nil)
1394                return children;
1395        }
1396
1397        // The tree's (AXOutline) children are supposed to be its rows and columns.
1398        // The ARIA spec doesn't have columns, so we just need rows.
1399        if (m_object->isTree())
1400            return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1401
1402        // A tree item should only expose its content as its children (not its rows)
1403        if (m_object->isTreeItem()) {
1404            AccessibilityObject::AccessibilityChildrenVector contentCopy;
1405            m_object->ariaTreeItemContent(contentCopy);
1406            return convertToNSArray(contentCopy);
1407        }
1408
1409        return convertToNSArray(m_object->children());
1410    }
1411
1412    if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1413        if (m_object->isListBox()) {
1414            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1415            m_object->selectedChildren(selectedChildrenCopy);
1416            return convertToNSArray(selectedChildrenCopy);
1417        }
1418        return nil;
1419    }
1420
1421    if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
1422        if (m_object->isListBox()) {
1423            AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
1424            m_object->visibleChildren(visibleChildrenCopy);
1425            return convertToNSArray(visibleChildrenCopy);
1426        }
1427        else if (m_object->isList())
1428            return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1429
1430        return nil;
1431    }
1432
1433
1434    if (m_object->isWebArea()) {
1435        if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
1436            AccessibilityObject::AccessibilityChildrenVector links;
1437            static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
1438            return convertToNSArray(links);
1439        }
1440        if ([attributeName isEqualToString:@"AXLoaded"])
1441            return [NSNumber numberWithBool:m_object->isLoaded()];
1442        if ([attributeName isEqualToString:@"AXLayoutCount"])
1443            return [NSNumber numberWithInt:m_object->layoutCount()];
1444        if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
1445            return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
1446    }
1447
1448    if (m_object->isTextControl()) {
1449        if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1450            int length = m_object->textLength();
1451            if (length < 0)
1452                return nil;
1453            return [NSNumber numberWithUnsignedInt:length];
1454        }
1455        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1456            String selectedText = m_object->selectedText();
1457            if (selectedText.isNull())
1458                return nil;
1459            return (NSString*)selectedText;
1460        }
1461        if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1462            PlainTextRange textRange = m_object->selectedTextRange();
1463            if (textRange.isNull())
1464                return nil;
1465            return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1466        }
1467        // TODO: Get actual visible range. <rdar://problem/4712101>
1468        if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1469            return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1470        if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1471            // if selectionEnd > 0, then there is selected text and this question should not be answered
1472            if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
1473                return nil;
1474            int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
1475            if (lineNumber < 0)
1476                return nil;
1477            return [NSNumber numberWithInt:lineNumber];
1478        }
1479    }
1480
1481    if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1482        KURL url = m_object->url();
1483        if (url.isNull())
1484            return nil;
1485        return (NSURL*)url;
1486    }
1487
1488    if ([attributeName isEqualToString: @"AXVisited"])
1489        return [NSNumber numberWithBool: m_object->isVisited()];
1490
1491    if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1492        if (m_object->isAttachment()) {
1493            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
1494                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1495        }
1496        return m_object->title();
1497    }
1498
1499    if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1500        if (m_object->isAttachment()) {
1501            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1502                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1503        }
1504        return m_object->accessibilityDescription();
1505    }
1506
1507    if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1508        if (m_object->isAttachment()) {
1509            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
1510                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1511        }
1512        if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar())
1513            return [NSNumber numberWithFloat:m_object->valueForRange()];
1514        if (m_object->hasIntValue())
1515            return [NSNumber numberWithInt:m_object->intValue()];
1516
1517        // radio groups return the selected radio button as the AXValue
1518        if (m_object->isRadioGroup()) {
1519            AccessibilityObject* radioButton = m_object->selectedRadioButton();
1520            if (!radioButton)
1521                return nil;
1522            return radioButton->wrapper();
1523        }
1524
1525        if (m_object->isTabList()) {
1526            AccessibilityObject* tabItem = m_object->selectedTabItem();
1527            if (!tabItem)
1528                return nil;
1529            return tabItem->wrapper();
1530        }
1531
1532        if (m_object->isTabItem())
1533            return [NSNumber numberWithInt:m_object->isSelected()];
1534
1535        return m_object->stringValue();
1536    }
1537
1538    if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1539        return [NSNumber numberWithFloat:m_object->minValueForRange()];
1540
1541    if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1542        return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1543
1544    if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1545        return m_object->helpText();
1546
1547    if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1548        return [NSNumber numberWithBool: m_object->isFocused()];
1549
1550    if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1551        return [NSNumber numberWithBool: m_object->isEnabled()];
1552
1553    if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1554        IntSize s = m_object->size();
1555        return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1556    }
1557
1558    if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1559        return [self position];
1560
1561    if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1562        [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1563        FrameView* fv = m_object->documentFrameView();
1564        if (fv)
1565            return [fv->platformWidget() window];
1566        return nil;
1567    }
1568
1569    if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
1570        AtomicString accessKey = m_object->accessKey();
1571        if (accessKey.isNull())
1572            return nil;
1573        return accessKey;
1574    }
1575
1576    if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
1577        if (m_object->isTabList()) {
1578            AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1579            m_object->tabChildren(tabsChildren);
1580            return convertToNSArray(tabsChildren);
1581        }
1582    }
1583
1584    if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
1585        // The contents of a tab list are all the children except the tabs.
1586        if (m_object->isTabList()) {
1587            AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1588            AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1589            m_object->tabChildren(tabsChildren);
1590
1591            AccessibilityObject::AccessibilityChildrenVector contents;
1592            unsigned childrenSize = children.size();
1593            for (unsigned k = 0; k < childrenSize; ++k) {
1594                if (tabsChildren.find(children[k]) == WTF::notFound)
1595                    contents.append(children[k]);
1596            }
1597            return convertToNSArray(contents);
1598        }
1599    }
1600
1601    if (m_object->isDataTable()) {
1602        // TODO: distinguish between visible and non-visible rows
1603        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1604            [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1605            return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
1606        }
1607        // TODO: distinguish between visible and non-visible columns
1608        if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
1609            [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
1610            return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
1611        }
1612
1613        if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1614            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1615            m_object->selectedChildren(selectedChildrenCopy);
1616            return convertToNSArray(selectedChildrenCopy);
1617        }
1618
1619        // HTML tables don't support these
1620        if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
1621            [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1622            return nil;
1623
1624        if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
1625            AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1626            static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
1627            return convertToNSArray(columnHeaders);
1628        }
1629
1630        if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1631            AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
1632            if (headerContainer)
1633                return headerContainer->wrapper();
1634            return nil;
1635        }
1636
1637        if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
1638            AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1639            static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
1640            return convertToNSArray(rowHeaders);
1641        }
1642
1643        if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
1644            AccessibilityObject::AccessibilityChildrenVector cells;
1645            static_cast<AccessibilityTable*>(m_object)->cells(cells);
1646            return convertToNSArray(cells);
1647        }
1648    }
1649
1650    if (m_object->isTableColumn()) {
1651        if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1652            return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
1653
1654        // rows attribute for a column is the list of all the elements in that column at each row
1655        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1656            [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1657            return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
1658        }
1659        if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1660            AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
1661            if (!header)
1662                return nil;
1663            return header->wrapper();
1664        }
1665    }
1666
1667    if (m_object->isTableCell()) {
1668        if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1669            pair<int, int> rowRange;
1670            static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
1671            return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1672        }
1673        if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1674            pair<int, int> columnRange;
1675            static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
1676            return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1677        }
1678    }
1679
1680    if (m_object->isTree()) {
1681        if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1682            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1683            m_object->selectedChildren(selectedChildrenCopy);
1684            return convertToNSArray(selectedChildrenCopy);
1685        }
1686        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
1687            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1688            m_object->ariaTreeRows(rowsCopy);
1689            return convertToNSArray(rowsCopy);
1690        }
1691
1692        // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
1693        if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
1694            return [NSArray array];
1695    }
1696
1697    if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
1698        if (m_object->isTreeItem()) {
1699            AccessibilityObject* parent = m_object->parentObject();
1700            for (; parent && !parent->isTree(); parent = parent->parentObject())
1701            { }
1702
1703            if (!parent)
1704                return nil;
1705
1706            // Find the index of this item by iterating the parents.
1707            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1708            parent->ariaTreeRows(rowsCopy);
1709            size_t count = rowsCopy.size();
1710            for (size_t k = 0; k < count; ++k)
1711                if (rowsCopy[k]->wrapper() == self)
1712                    return [NSNumber numberWithUnsignedInt:k];
1713
1714            return nil;
1715        }
1716        if (m_object->isTableRow()) {
1717            if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1718                return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
1719        }
1720    }
1721
1722    // The rows that are considered inside this row.
1723    if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
1724        if (m_object->isTreeItem()) {
1725            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1726            m_object->ariaTreeItemDisclosedRows(rowsCopy);
1727            return convertToNSArray(rowsCopy);
1728        } else if (m_object->isARIATreeGridRow()) {
1729            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1730            static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
1731            return convertToNSArray(rowsCopy);
1732        }
1733    }
1734
1735    // The row that contains this row. It should be the same as the first parent that is a treeitem.
1736    if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
1737        if (m_object->isTreeItem()) {
1738            AccessibilityObject* parent = m_object->parentObject();
1739            while (parent) {
1740                if (parent->isTreeItem())
1741                    return parent->wrapper();
1742                // If the parent is the tree itself, then this value == nil.
1743                if (parent->isTree())
1744                    return nil;
1745                parent = parent->parentObject();
1746            }
1747            return nil;
1748        } else if (m_object->isARIATreeGridRow()) {
1749            AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
1750            if (!row)
1751                return nil;
1752            return row->wrapper();
1753        }
1754    }
1755
1756    if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute])
1757        return [NSNumber numberWithInt:m_object->hierarchicalLevel()];
1758    if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1759        return [NSNumber numberWithBool:m_object->isExpanded()];
1760
1761    if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1762        return NSAccessibilityVerticalOrientationValue;
1763
1764    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1765        return [self textMarkerRangeForSelection];
1766
1767    if (m_object->isAccessibilityRenderObject()) {
1768        RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1769        if (!renderer)
1770            return nil;
1771
1772        if ([attributeName isEqualToString: @"AXStartTextMarker"])
1773            return textMarkerForVisiblePosition(startOfDocument(renderer->document()));
1774        if ([attributeName isEqualToString: @"AXEndTextMarker"])
1775            return textMarkerForVisiblePosition(endOfDocument(renderer->document()));
1776
1777        if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
1778            return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1779    } else {
1780        if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) {
1781            AccessibilityObject* parent = m_object->parentObjectUnignored();
1782            if (!parent)
1783                return [NSNumber numberWithInt:0];
1784            return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute];
1785        }
1786    }
1787
1788    if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1789        AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1790        m_object->linkedUIElements(linkedUIElements);
1791        if (linkedUIElements.size() == 0)
1792            return nil;
1793        return convertToNSArray(linkedUIElements);
1794    }
1795
1796    if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1797        return [NSNumber numberWithBool:m_object->isSelected()];
1798
1799    if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
1800        AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
1801        if (uiElement)
1802            return [NSArray arrayWithObject:uiElement->wrapper()];
1803    }
1804
1805    if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
1806        AccessibilityObject* obj = m_object->titleUIElement();
1807        if (obj)
1808            return obj->wrapper();
1809        return nil;
1810    }
1811
1812    if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
1813        return m_object->valueDescription();
1814
1815    if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
1816        AccessibilityOrientation elementOrientation = m_object->orientation();
1817        if (elementOrientation == AccessibilityOrientationVertical)
1818            return NSAccessibilityVerticalOrientationValue;
1819        if (elementOrientation == AccessibilityOrientationHorizontal)
1820            return NSAccessibilityHorizontalOrientationValue;
1821        return nil;
1822    }
1823
1824    if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
1825        return m_object->language();
1826
1827    if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
1828        return [NSNumber numberWithBool:m_object->isExpanded()];
1829
1830    if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
1831        return [NSNumber numberWithBool:m_object->isRequired()];
1832
1833    if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
1834        AccessibilityObject::AccessibilityChildrenVector ariaOwns;
1835        m_object->ariaOwnsElements(ariaOwns);
1836        return convertToNSArray(ariaOwns);
1837    }
1838
1839    if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
1840        return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
1841
1842    if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
1843        Vector<String> dropEffects;
1844        m_object->determineARIADropEffects(dropEffects);
1845        size_t length = dropEffects.size();
1846
1847        NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
1848        for (size_t i = 0; i < length; ++i)
1849            [dropEffectsArray addObject:dropEffects[i]];
1850        return dropEffectsArray;
1851    }
1852
1853    // ARIA Live region attributes.
1854    if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
1855        return m_object->ariaLiveRegionStatus();
1856    if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
1857         return m_object->ariaLiveRegionRelevant();
1858    if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
1859        return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
1860    if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
1861        return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
1862
1863    // this is used only by DumpRenderTree for testing
1864    if ([attributeName isEqualToString:@"AXClickPoint"])
1865        return [NSValue valueWithPoint:m_object->clickPoint()];
1866
1867    return nil;
1868}
1869
1870- (id)accessibilityFocusedUIElement
1871{
1872    if (!m_object)
1873        return nil;
1874
1875    m_object->updateBackingStore();
1876    if (!m_object)
1877        return nil;
1878
1879    RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
1880
1881    if (!focusedObj)
1882        return nil;
1883
1884    return focusedObj->wrapper();
1885}
1886
1887- (id)accessibilityHitTest:(NSPoint)point
1888{
1889    if (!m_object)
1890        return nil;
1891
1892    m_object->updateBackingStore();
1893    if (!m_object)
1894        return nil;
1895
1896    RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
1897    if (axObject)
1898        return NSAccessibilityUnignoredAncestor(axObject->wrapper());
1899    return NSAccessibilityUnignoredAncestor(self);
1900}
1901
1902- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
1903{
1904    if (!m_object)
1905        return nil;
1906
1907    m_object->updateBackingStore();
1908    if (!m_object)
1909        return nil;
1910
1911    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1912        return YES;
1913
1914    if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1915        return m_object->canSetFocusAttribute();
1916
1917    if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1918        return m_object->canSetValueAttribute();
1919
1920    if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1921        return m_object->canSetSelectedAttribute();
1922
1923    if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
1924        return m_object->canSetSelectedChildrenAttribute();
1925
1926    if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1927        return m_object->canSetExpandedAttribute();
1928
1929    if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
1930        return YES;
1931
1932    if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
1933        [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
1934        [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1935        return m_object->canSetTextRangeAttributes();
1936
1937    if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
1938        return YES;
1939
1940    return NO;
1941}
1942
1943// accessibilityShouldUseUniqueId is an AppKit method we override so that
1944// objects will be given a unique ID, and therefore allow AppKit to know when they
1945// become obsolete (e.g. when the user navigates to a new web page, making this one
1946// unrendered but not deallocated because it is in the back/forward cache).
1947// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
1948// appropriate place (e.g. dealloc) to remove these non-retained references from
1949// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
1950//
1951// Registering an object is also required for observing notifications. Only registered objects can be observed.
1952- (BOOL)accessibilityIsIgnored
1953{
1954    if (!m_object)
1955        return nil;
1956
1957    m_object->updateBackingStore();
1958    if (!m_object)
1959        return nil;
1960
1961    if (m_object->isAttachment())
1962        return [[self attachmentView] accessibilityIsIgnored];
1963    return m_object->accessibilityIsIgnored();
1964}
1965
1966- (NSArray* )accessibilityParameterizedAttributeNames
1967{
1968    if (!m_object)
1969        return nil;
1970
1971    m_object->updateBackingStore();
1972    if (!m_object)
1973        return nil;
1974
1975    if (m_object->isAttachment())
1976        return nil;
1977
1978    static NSArray* paramAttrs = nil;
1979    static NSArray* textParamAttrs = nil;
1980    static NSArray* tableParamAttrs = nil;
1981    if (paramAttrs == nil) {
1982        paramAttrs = [[NSArray alloc] initWithObjects:
1983                      @"AXUIElementForTextMarker",
1984                      @"AXTextMarkerRangeForUIElement",
1985                      @"AXLineForTextMarker",
1986                      @"AXTextMarkerRangeForLine",
1987                      @"AXStringForTextMarkerRange",
1988                      @"AXTextMarkerForPosition",
1989                      @"AXBoundsForTextMarkerRange",
1990                      @"AXAttributedStringForTextMarkerRange",
1991                      @"AXTextMarkerRangeForUnorderedTextMarkers",
1992                      @"AXNextTextMarkerForTextMarker",
1993                      @"AXPreviousTextMarkerForTextMarker",
1994                      @"AXLeftWordTextMarkerRangeForTextMarker",
1995                      @"AXRightWordTextMarkerRangeForTextMarker",
1996                      @"AXLeftLineTextMarkerRangeForTextMarker",
1997                      @"AXRightLineTextMarkerRangeForTextMarker",
1998                      @"AXSentenceTextMarkerRangeForTextMarker",
1999                      @"AXParagraphTextMarkerRangeForTextMarker",
2000                      @"AXNextWordEndTextMarkerForTextMarker",
2001                      @"AXPreviousWordStartTextMarkerForTextMarker",
2002                      @"AXNextLineEndTextMarkerForTextMarker",
2003                      @"AXPreviousLineStartTextMarkerForTextMarker",
2004                      @"AXNextSentenceEndTextMarkerForTextMarker",
2005                      @"AXPreviousSentenceStartTextMarkerForTextMarker",
2006                      @"AXNextParagraphEndTextMarkerForTextMarker",
2007                      @"AXPreviousParagraphStartTextMarkerForTextMarker",
2008                      @"AXStyleTextMarkerRangeForTextMarker",
2009                      @"AXLengthForTextMarkerRange",
2010                      NSAccessibilityBoundsForRangeParameterizedAttribute,
2011                      NSAccessibilityStringForRangeParameterizedAttribute,
2012                      nil];
2013    }
2014
2015    if (textParamAttrs == nil) {
2016        NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2017        [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2018        [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2019        [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2020        [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2021        [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2022        [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2023        [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2024        [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2025        [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2026        textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2027        [tempArray release];
2028    }
2029    if (tableParamAttrs == nil) {
2030        NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2031        [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2032        tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2033        [tempArray release];
2034    }
2035
2036    if (m_object->isPasswordField())
2037        return [NSArray array];
2038
2039    if (!m_object->isAccessibilityRenderObject())
2040        return paramAttrs;
2041
2042    if (m_object->isTextControl())
2043        return textParamAttrs;
2044
2045    if (m_object->isDataTable())
2046        return tableParamAttrs;
2047
2048    if (m_object->isMenuRelated())
2049        return nil;
2050
2051    return paramAttrs;
2052}
2053
2054- (void)accessibilityPerformPressAction
2055{
2056    if (!m_object)
2057        return;
2058
2059    m_object->updateBackingStore();
2060    if (!m_object)
2061        return;
2062
2063    if (m_object->isAttachment())
2064        [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2065    else
2066        m_object->press();
2067}
2068
2069- (void)accessibilityPerformIncrementAction
2070{
2071    if (!m_object)
2072        return;
2073
2074    m_object->updateBackingStore();
2075    if (!m_object)
2076        return;
2077
2078    if (m_object->isAttachment())
2079        [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2080    else
2081        m_object->increment();
2082}
2083
2084- (void)accessibilityPerformDecrementAction
2085{
2086    if (!m_object)
2087        return;
2088
2089    m_object->updateBackingStore();
2090    if (!m_object)
2091        return;
2092
2093    if (m_object->isAttachment())
2094        [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2095    else
2096        m_object->decrement();
2097}
2098
2099- (void)accessibilityPerformShowMenuAction
2100{
2101    if (m_object->roleValue() == ComboBoxRole)
2102        m_object->setIsExpanded(true);
2103    else {
2104        // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2105        // If it's the same run loop iteration, the menu open notification won't be sent
2106        [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2107    }
2108}
2109
2110- (void)accessibilityShowContextMenu
2111{
2112    FrameView* frameView = m_object->documentFrameView();
2113    if (!frameView)
2114        return;
2115
2116    // simulate a click in the middle of the object
2117    IntPoint clickPoint = m_object->clickPoint();
2118    NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y());
2119
2120    NSView* view = nil;
2121    if (m_object->isAttachment())
2122        view = [self attachmentView];
2123    else
2124        view = frameView->documentView();
2125
2126    if (!view)
2127        return;
2128
2129    NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil];
2130
2131    // Show the contextual menu for this event.
2132    NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
2133    NSMenu* menu = [view menuForEvent:event];
2134
2135    if (menu)
2136        [NSMenu popUpContextMenu:menu withEvent:event forView:view];
2137}
2138
2139- (void)accessibilityPerformAction:(NSString*)action
2140{
2141    if (!m_object)
2142        return;
2143
2144    m_object->updateBackingStore();
2145    if (!m_object)
2146        return;
2147
2148    if ([action isEqualToString:NSAccessibilityPressAction])
2149        [self accessibilityPerformPressAction];
2150
2151    else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2152        [self accessibilityPerformShowMenuAction];
2153
2154    else if ([action isEqualToString:NSAccessibilityIncrementAction])
2155        [self accessibilityPerformIncrementAction];
2156
2157    else if ([action isEqualToString:NSAccessibilityDecrementAction])
2158        [self accessibilityPerformDecrementAction];
2159}
2160
2161- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2162{
2163    if (!m_object)
2164        return;
2165
2166    m_object->updateBackingStore();
2167    if (!m_object)
2168        return;
2169
2170    WebCoreTextMarkerRange* textMarkerRange = nil;
2171    NSNumber*               number = nil;
2172    NSString*               string = nil;
2173    NSRange                 range = {0, 0};
2174    NSArray*                array = nil;
2175
2176    // decode the parameter
2177    if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
2178        textMarkerRange = (WebCoreTextMarkerRange*) value;
2179
2180    else if ([value isKindOfClass:[NSNumber self]])
2181        number = value;
2182
2183    else if ([value isKindOfClass:[NSString self]])
2184        string = value;
2185
2186    else if ([value isKindOfClass:[NSValue self]])
2187        range = [value rangeValue];
2188
2189    else if ([value isKindOfClass:[NSArray self]])
2190        array = value;
2191
2192    // handle the command
2193    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2194        ASSERT(textMarkerRange);
2195        m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
2196    } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2197        ASSERT(number);
2198        m_object->setFocused([number intValue] != 0);
2199    } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2200        if (!string)
2201            return;
2202        m_object->setValue(string);
2203    } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
2204        if (!number)
2205            return;
2206        m_object->setSelected([number boolValue]);
2207    } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2208        if (!array || m_object->roleValue() != ListBoxRole)
2209            return;
2210        AccessibilityObject::AccessibilityChildrenVector selectedChildren;
2211        convertToVector(array, selectedChildren);
2212        static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
2213    } else if (m_object->isTextControl()) {
2214        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2215            m_object->setSelectedText(string);
2216        } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2217            m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2218        } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2219            m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
2220        }
2221    } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2222        m_object->setIsExpanded([number boolValue]);
2223    else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2224        AccessibilityObject::AccessibilityChildrenVector selectedRows;
2225        convertToVector(array, selectedRows);
2226        if (m_object->isTree() || m_object->isDataTable())
2227            m_object->setSelectedRows(selectedRows);
2228    } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2229        m_object->setARIAGrabbed([number boolValue]);
2230}
2231
2232static RenderObject* rendererForView(NSView* view)
2233{
2234    if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
2235        return 0;
2236
2237    NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
2238    Frame* frame = [frameView _web_frame];
2239    if (!frame)
2240        return 0;
2241
2242    Node* node = frame->document()->ownerElement();
2243    if (!node)
2244        return 0;
2245
2246    return node->renderer();
2247}
2248
2249- (id)_accessibilityParentForSubview:(NSView*)subview
2250{
2251    RenderObject* renderer = rendererForView(subview);
2252    if (!renderer)
2253        return nil;
2254
2255    AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
2256    if (obj)
2257        return obj->parentObjectUnignored()->wrapper();
2258    return nil;
2259}
2260
2261- (NSString*)accessibilityActionDescription:(NSString*)action
2262{
2263    // we have no custom actions
2264    return NSAccessibilityActionDescription(action);
2265}
2266
2267// The CFAttributedStringType representation of the text associated with this accessibility
2268// object that is specified by the given range.
2269- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
2270{
2271    PlainTextRange textRange = PlainTextRange(range.location, range.length);
2272    VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
2273    return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)];
2274}
2275
2276// The RTF representation of the text associated with this accessibility object that is
2277// specified by the given range.
2278- (NSData*)doAXRTFForRange:(NSRange)range
2279{
2280    NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
2281    return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
2282}
2283
2284- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2285{
2286    WebCoreTextMarker* textMarker = nil;
2287    WebCoreTextMarkerRange* textMarkerRange = nil;
2288    NSNumber* number = nil;
2289    NSArray* array = nil;
2290    RefPtr<AccessibilityObject> uiElement = 0;
2291    NSPoint point = NSZeroPoint;
2292    bool pointSet = false;
2293    NSRange range = {0, 0};
2294    bool rangeSet = false;
2295
2296    // basic parameter validation
2297    if (!m_object || !attribute || !parameter)
2298        return nil;
2299
2300    m_object->updateBackingStore();
2301    if (!m_object)
2302        return nil;
2303
2304    // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
2305    // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
2306    // a parameter of the wrong type.
2307    if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
2308        textMarker = (WebCoreTextMarker*) parameter;
2309
2310    else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
2311        textMarkerRange = (WebCoreTextMarkerRange*) parameter;
2312
2313    else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
2314        uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
2315
2316    else if ([parameter isKindOfClass:[NSNumber self]])
2317        number = parameter;
2318
2319    else if ([parameter isKindOfClass:[NSArray self]])
2320        array = parameter;
2321
2322    else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2323        pointSet = true;
2324        point = [(NSValue*)parameter pointValue];
2325
2326    } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2327        rangeSet = true;
2328        range = [(NSValue*)parameter rangeValue];
2329
2330    } else {
2331        // got a parameter of a type we never use
2332        // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally
2333        // while using accesstool (e.g.), forcing you to start over
2334        return nil;
2335    }
2336
2337    // Convert values to WebCore types
2338    // FIXME: prepping all of these values as WebCore types is unnecessary in many
2339    // cases. Re-organization of this function or performing the conversion on a
2340    // need basis are possible improvements.
2341    VisiblePosition visiblePos;
2342    if (textMarker)
2343        visiblePos = visiblePositionForTextMarker(textMarker);
2344    int intNumber = [number intValue];
2345    VisiblePositionRange visiblePosRange;
2346    if (textMarkerRange)
2347        visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2348    IntPoint webCorePoint = IntPoint(point);
2349    PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2350
2351    // dispatch
2352    if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
2353        return m_object->accessibilityObjectForPosition(visiblePos)->wrapper();
2354
2355    if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) {
2356        VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
2357        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2358    }
2359
2360    if ([attribute isEqualToString: @"AXLineForTextMarker"])
2361        return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
2362
2363    if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) {
2364        VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber);
2365        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2366    }
2367
2368    if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
2369        return m_object->stringForVisiblePositionRange(visiblePosRange);
2370
2371    if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
2372        return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil;
2373
2374    if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) {
2375        NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
2376        return [NSValue valueWithRect:rect];
2377    }
2378
2379    if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2380        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2381        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2382        if (start.isNull() || end.isNull())
2383            return nil;
2384        NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
2385        return [NSValue valueWithRect:rect];
2386    }
2387
2388    if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
2389        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2390        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2391        if (start.isNull() || end.isNull())
2392            return nil;
2393        return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
2394    }
2395
2396    if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
2397        return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
2398
2399    if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) {
2400        if ([array count] < 2)
2401            return nil;
2402
2403        WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
2404        WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
2405        if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1]
2406            || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
2407            return nil;
2408
2409        VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1);
2410        VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2);
2411        VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
2412        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2413    }
2414
2415    if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
2416        return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos));
2417
2418    if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
2419        return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos));
2420
2421    if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) {
2422        VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
2423        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2424    }
2425
2426    if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) {
2427        VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
2428        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2429    }
2430
2431    if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) {
2432        VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
2433        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2434    }
2435
2436    if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) {
2437        VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
2438        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2439    }
2440
2441    if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) {
2442        VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
2443        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2444    }
2445
2446    if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) {
2447        VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
2448        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2449    }
2450
2451    if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
2452        return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos));
2453
2454    if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
2455        return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos));
2456
2457    if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
2458        return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos));
2459
2460    if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
2461        return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos));
2462
2463    if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
2464        return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos));
2465
2466    if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
2467        return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos));
2468
2469    if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
2470        return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos));
2471
2472    if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
2473        return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos));
2474
2475    if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) {
2476        VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
2477        return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
2478    }
2479
2480    if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) {
2481        int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
2482        if (length < 0)
2483            return nil;
2484        return [NSNumber numberWithInt:length];
2485    }
2486
2487    if (m_object->isDataTable()) {
2488        if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
2489            if (array == nil || [array count] != 2)
2490                return nil;
2491            AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
2492            if (!cell)
2493                return nil;
2494
2495            return cell->wrapper();
2496        }
2497    }
2498
2499    if (m_object->isTextControl()) {
2500        if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
2501            int lineNumber = m_object->doAXLineForIndex(intNumber);
2502            if (lineNumber < 0)
2503                return nil;
2504            return [NSNumber numberWithUnsignedInt:lineNumber];
2505        }
2506
2507        if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
2508            PlainTextRange textRange = m_object->doAXRangeForLine(intNumber);
2509            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2510        }
2511
2512        if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
2513            return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
2514
2515        if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
2516            if (!pointSet)
2517                return nil;
2518            PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
2519            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2520        }
2521
2522        if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
2523            PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber);
2524            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2525        }
2526
2527        if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
2528            if (!rangeSet)
2529                return nil;
2530            NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
2531            return [NSValue valueWithRect:rect];
2532        }
2533
2534        if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2535            return rangeSet ? [self doAXRTFForRange:range] : nil;
2536
2537        if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2538            return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
2539
2540        if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
2541            PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber);
2542            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2543        }
2544    }
2545
2546    return nil;
2547}
2548
2549- (BOOL)accessibilityShouldUseUniqueId
2550{
2551    return m_object->accessibilityShouldUseUniqueId();
2552}
2553
2554// API that AppKit uses for faster access
2555- (NSUInteger)accessibilityIndexOfChild:(id)child
2556{
2557    if (!m_object)
2558        return NSNotFound;
2559
2560    m_object->updateBackingStore();
2561    if (!m_object)
2562        return NSNotFound;
2563
2564    // Tree objects return their rows as their children. We can use the original method
2565    // here, because we won't gain any speed up.
2566    if (m_object->isTree())
2567        return [super accessibilityIndexOfChild:child];
2568
2569    const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2570
2571    if (children.isEmpty())
2572        return [[self renderWidgetChildren] indexOfObject:child];
2573
2574    unsigned count = children.size();
2575    for (unsigned k = 0; k < count; ++k) {
2576        AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
2577        if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child))
2578            return k;
2579    }
2580
2581    return NSNotFound;
2582}
2583
2584- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
2585{
2586    if (!m_object)
2587        return 0;
2588
2589    m_object->updateBackingStore();
2590    if (!m_object)
2591        return 0;
2592
2593    if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2594        // Tree items object returns a different set of children than those that are in children()
2595        // because an AXOutline (the mac role is becomes) has some odd stipulations.
2596        if (m_object->isTree() || m_object->isTreeItem())
2597            return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
2598
2599        const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2600        if (children.isEmpty())
2601            return [[self renderWidgetChildren] count];
2602
2603        return children.size();
2604    }
2605
2606    return [super accessibilityArrayAttributeCount:attribute];
2607}
2608
2609- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
2610{
2611    if (!m_object)
2612        return nil;
2613
2614    m_object->updateBackingStore();
2615    if (!m_object)
2616        return nil;
2617
2618    if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2619        if (m_object->children().isEmpty()) {
2620            NSArray *children = [self renderWidgetChildren];
2621            if (!children)
2622                return nil;
2623
2624            NSUInteger childCount = [children count];
2625            if (index >= childCount)
2626                return nil;
2627
2628            NSUInteger arrayLength = min(childCount - index, maxCount);
2629            return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
2630        } else if (m_object->isTree()) {
2631            // Tree objects return their rows as their children. We can use the original method in this case.
2632            return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2633        }
2634
2635        const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2636        unsigned childCount = children.size();
2637        if (index >= childCount)
2638            return nil;
2639
2640        unsigned available = min(childCount - index, maxCount);
2641
2642        NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
2643        for (unsigned added = 0; added < available; ++index, ++added) {
2644            AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
2645            if (wrapper) {
2646                // The attachment view should be returned, otherwise AX palindrome errors occur.
2647                if (children[index]->isAttachment() && [wrapper attachmentView])
2648                    [subarray addObject:[wrapper attachmentView]];
2649                else
2650                    [subarray addObject:wrapper];
2651            }
2652        }
2653
2654        return subarray;
2655    }
2656
2657    return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2658}
2659
2660// These are used by DRT so that it can know when notifications are sent.
2661// Since they are static, only one callback can be installed at a time (that's all DRT should need).
2662typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
2663static AXPostedNotificationCallback AXNotificationCallback = 0;
2664static void* AXPostedNotificationContext = 0;
2665
2666- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context
2667{
2668    AXNotificationCallback = function;
2669    AXPostedNotificationContext = context;
2670}
2671
2672- (void)accessibilityPostedNotification:(NSString *)notification
2673{
2674    if (AXNotificationCallback)
2675        AXNotificationCallback(self, notification, AXPostedNotificationContext);
2676}
2677
2678@end
2679
2680#endif // HAVE(ACCESSIBILITY)
2681