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