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