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