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