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