c0dd7955965b4529c37c41bb583a257dd630558e
[WebKit.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         { ParagraphRole, NSAccessibilityGroupRole },
1292         { LabelRole, NSAccessibilityGroupRole },
1293         { DivRole, NSAccessibilityGroupRole },
1294         { FormRole, NSAccessibilityGroupRole }
1295     };
1296     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1297     
1298     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1299     for (unsigned i = 0; i < numRoles; ++i)
1300         roleMap.set(roles[i].value, roles[i].string);
1301     return roleMap;
1302 }
1303
1304 static NSString* roleValueToNSString(AccessibilityRole value)
1305 {
1306     ASSERT(value);
1307     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1308     return roleMap.get(value);
1309 }
1310
1311 - (NSString*)role
1312 {
1313     if (m_object->isAttachment())
1314         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1315     NSString* string = roleValueToNSString(m_object->roleValue());
1316     if (string != nil)
1317         return string;
1318     return NSAccessibilityUnknownRole;
1319 }
1320
1321 - (NSString*)subrole
1322 {
1323     if (m_object->isPasswordField())
1324         return NSAccessibilitySecureTextFieldSubrole;
1325     
1326     if (m_object->isAttachment()) {
1327         NSView* attachView = [self attachmentView];
1328         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1329             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1330         }
1331     }
1332     
1333     if (m_object->isTreeItem())
1334         return NSAccessibilityOutlineRowSubrole;
1335     
1336     if (m_object->isList()) {
1337         AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
1338         if (listObject->isUnorderedList() || listObject->isOrderedList())
1339             return NSAccessibilityContentListSubrole;
1340         if (listObject->isDefinitionList())
1341             return NSAccessibilityDefinitionListSubrole;
1342     }
1343     
1344     // ARIA content subroles.
1345     switch (m_object->roleValue()) {
1346         case LandmarkApplicationRole:
1347             return @"AXLandmarkApplication";
1348         case LandmarkBannerRole:
1349             return @"AXLandmarkBanner";
1350         case LandmarkComplementaryRole:
1351             return @"AXLandmarkComplementary";
1352         case LandmarkContentInfoRole:
1353             return @"AXLandmarkContentInfo";
1354         case LandmarkMainRole:
1355             return @"AXLandmarkMain";
1356         case LandmarkNavigationRole:
1357             return @"AXLandmarkNavigation";
1358         case LandmarkSearchRole:
1359             return @"AXLandmarkSearch";
1360         case ApplicationAlertRole:
1361             return @"AXApplicationAlert";
1362         case ApplicationAlertDialogRole:
1363             return @"AXApplicationAlertDialog";
1364         case ApplicationDialogRole:
1365             return @"AXApplicationDialog";
1366         case ApplicationLogRole:
1367             return @"AXApplicationLog";
1368         case ApplicationMarqueeRole:
1369             return @"AXApplicationMarquee";
1370         case ApplicationStatusRole:
1371             return @"AXApplicationStatus";
1372         case ApplicationTimerRole:
1373             return @"AXApplicationTimer";
1374         case DocumentRole:
1375             return @"AXDocument";
1376         case DocumentArticleRole:
1377             return @"AXDocumentArticle";
1378         case DocumentMathRole:
1379             return @"AXDocumentMath";
1380         case DocumentNoteRole:
1381             return @"AXDocumentNote";
1382         case DocumentRegionRole:
1383             return @"AXDocumentRegion";
1384         case UserInterfaceTooltipRole:
1385             return @"AXUserInterfaceTooltip";
1386         case TabPanelRole:
1387             return @"AXTabPanel";
1388         case DefinitionListTermRole:
1389             return @"AXTerm";
1390         case DefinitionListDefinitionRole:
1391             return @"AXDefinition";
1392         // Default doesn't return anything, so roles defined below can be chosen.
1393         default:
1394             break;
1395     }
1396     
1397     if (m_object->isMediaTimeline())
1398         return NSAccessibilityTimelineSubrole;
1399
1400     return nil;
1401 }
1402
1403 - (NSString*)roleDescription
1404 {
1405     if (!m_object)
1406         return nil;
1407
1408     // attachments have the AXImage role, but a different subrole
1409     if (m_object->isAttachment())
1410         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1411     
1412     NSString* axRole = [self role];
1413     
1414     if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1415         switch (m_object->roleValue()) {
1416             default:
1417                 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1418             case LandmarkApplicationRole:
1419                 return AXARIAContentGroupText(@"ARIALandmarkApplication");
1420             case LandmarkBannerRole:
1421                 return AXARIAContentGroupText(@"ARIALandmarkBanner");
1422             case LandmarkComplementaryRole:
1423                 return AXARIAContentGroupText(@"ARIALandmarkComplementary");
1424             case LandmarkContentInfoRole:
1425                 return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
1426             case LandmarkMainRole:
1427                 return AXARIAContentGroupText(@"ARIALandmarkMain");
1428             case LandmarkNavigationRole:
1429                 return AXARIAContentGroupText(@"ARIALandmarkNavigation");
1430             case LandmarkSearchRole:
1431                 return AXARIAContentGroupText(@"ARIALandmarkSearch");
1432             case ApplicationAlertRole:
1433                 return AXARIAContentGroupText(@"ARIAApplicationAlert");
1434             case ApplicationAlertDialogRole:
1435                 return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
1436             case ApplicationDialogRole:
1437                 return AXARIAContentGroupText(@"ARIAApplicationDialog");
1438             case ApplicationLogRole:
1439                 return AXARIAContentGroupText(@"ARIAApplicationLog");
1440             case ApplicationMarqueeRole:
1441                 return AXARIAContentGroupText(@"ARIAApplicationMarquee");
1442             case ApplicationStatusRole:
1443                 return AXARIAContentGroupText(@"ARIAApplicationStatus");
1444             case ApplicationTimerRole:
1445                 return AXARIAContentGroupText(@"ARIAApplicationTimer");
1446             case DocumentRole:
1447                 return AXARIAContentGroupText(@"ARIADocument");
1448             case DocumentArticleRole:
1449                 return AXARIAContentGroupText(@"ARIADocumentArticle");
1450             case DocumentMathRole:
1451                 return AXARIAContentGroupText(@"ARIADocumentMath");
1452             case DocumentNoteRole:
1453                 return AXARIAContentGroupText(@"ARIADocumentNote");
1454             case DocumentRegionRole:
1455                 return AXARIAContentGroupText(@"ARIADocumentRegion");
1456             case UserInterfaceTooltipRole:
1457                 return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
1458             case TabPanelRole:
1459                 return AXARIAContentGroupText(@"ARIATabPanel");
1460             case DefinitionListTermRole:
1461                 return AXDefinitionListTermText();
1462             case DefinitionListDefinitionRole:
1463                 return AXDefinitionListDefinitionText();
1464         }
1465     }        
1466     
1467     if ([axRole isEqualToString:@"AXWebArea"])
1468         return AXWebAreaText();
1469     
1470     if ([axRole isEqualToString:@"AXLink"])
1471         return AXLinkText();
1472     
1473     if ([axRole isEqualToString:@"AXListMarker"])
1474         return AXListMarkerText();
1475     
1476     if ([axRole isEqualToString:@"AXImageMap"])
1477         return AXImageMapText();
1478
1479     if ([axRole isEqualToString:@"AXHeading"])
1480         return AXHeadingText();
1481
1482     // AppKit also returns AXTab for the role description for a tab item.
1483     if (m_object->isTabItem())
1484         return NSAccessibilityRoleDescription(@"AXTab", nil);
1485     
1486     // We should try the system default role description for all other roles.
1487     // If we get the same string back, then as a last resort, return unknown.
1488     NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1489     if (![defaultRoleDescription isEqualToString:axRole])
1490         return defaultRoleDescription;
1491
1492     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1493 }
1494
1495 - (id)scrollViewParent
1496 {
1497     if (!m_object || !m_object->isAccessibilityScrollView())
1498         return nil;
1499     
1500     // If this scroll view provides it's parent object (because it's a sub-frame), then
1501     // we should not find the remoteAccessibilityParent.
1502     if (m_object->parentObject())
1503         return nil;
1504     
1505     AccessibilityScrollView* scrollView = toAccessibilityScrollView(m_object);
1506     ScrollView* scroll = scrollView->scrollView();
1507     if (!scroll)
1508         return nil;
1509     
1510     if (scroll->platformWidget())
1511         return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
1512
1513     return [self remoteAccessibilityParentObject];
1514 }
1515
1516 // FIXME: split up this function in a better way.  
1517 // suggestions: Use a hash table that maps attribute names to function calls,
1518 // or maybe pointers to member functions
1519 - (id)accessibilityAttributeValue:(NSString*)attributeName
1520 {
1521     if (![self updateObjectBackingStore])
1522         return nil;
1523     
1524     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1525         return [self role];
1526
1527     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1528         return [self subrole];
1529
1530     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1531         return [self roleDescription];
1532
1533     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1534
1535         // This will return the parent of the AXWebArea, if this is a web area.
1536         id scrollViewParent = [self scrollViewParent];
1537         if (scrollViewParent)
1538             return scrollViewParent;
1539         
1540         // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1541         if (m_object->isTreeItem()) {
1542             AccessibilityObject* parent = m_object->parentObjectUnignored();
1543             while (parent) {
1544                 if (parent->isTree())
1545                     return parent->wrapper();
1546                 parent = parent->parentObjectUnignored();
1547             }
1548         }
1549         
1550         AccessibilityObject* parent = m_object->parentObjectUnignored();
1551         if (!parent)
1552             return nil;
1553
1554         // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
1555         // should be reported directly as such.
1556         if (m_object->isWebArea() && parent->isAttachment())
1557             return [parent->wrapper() attachmentView];
1558         
1559         return parent->wrapper();
1560     }
1561
1562     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1563         if (m_object->children().isEmpty()) {
1564             NSArray* children = [self renderWidgetChildren];
1565             if (children != nil)
1566                 return children;
1567         }
1568
1569         // The tree's (AXOutline) children are supposed to be its rows and columns.
1570         // The ARIA spec doesn't have columns, so we just need rows.
1571         if (m_object->isTree())
1572             return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1573
1574         // A tree item should only expose its content as its children (not its rows)
1575         if (m_object->isTreeItem()) {
1576             AccessibilityObject::AccessibilityChildrenVector contentCopy;
1577             m_object->ariaTreeItemContent(contentCopy);
1578             return convertToNSArray(contentCopy);
1579         }
1580         
1581         return convertToNSArray(m_object->children());
1582     }
1583     
1584     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1585         if (m_object->isListBox()) {
1586             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1587             m_object->selectedChildren(selectedChildrenCopy);
1588             return convertToNSArray(selectedChildrenCopy);
1589         }
1590         return nil;
1591     }
1592     
1593     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
1594         if (m_object->isListBox()) {
1595             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
1596             m_object->visibleChildren(visibleChildrenCopy);
1597             return convertToNSArray(visibleChildrenCopy);
1598         }
1599         else if (m_object->isList())
1600             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1601
1602         return nil;
1603     }
1604     
1605     
1606     if (m_object->isWebArea()) {
1607         if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
1608             AccessibilityObject::AccessibilityChildrenVector links;
1609             static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
1610             return convertToNSArray(links);
1611         }
1612         if ([attributeName isEqualToString:@"AXLoaded"])
1613             return [NSNumber numberWithBool:m_object->isLoaded()];
1614         if ([attributeName isEqualToString:@"AXLayoutCount"])
1615             return [NSNumber numberWithInt:m_object->layoutCount()];
1616         if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
1617             return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
1618     }
1619     
1620     if (m_object->isTextControl()) {
1621         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1622             int length = m_object->textLength();
1623             if (length < 0)
1624                 return nil;
1625             return [NSNumber numberWithUnsignedInt:length];
1626         }
1627         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1628             String selectedText = m_object->selectedText();
1629             if (selectedText.isNull())
1630                 return nil;
1631             return (NSString*)selectedText;
1632         }
1633         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1634             PlainTextRange textRange = m_object->selectedTextRange();
1635             if (textRange.isNull())
1636                 return [NSValue valueWithRange:NSMakeRange(0, 0)];
1637             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1638         }
1639         // TODO: Get actual visible range. <rdar://problem/4712101>
1640         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1641             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1642         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1643             // if selectionEnd > 0, then there is selected text and this question should not be answered
1644             if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
1645                 return nil;
1646             int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
1647             if (lineNumber < 0)
1648                 return nil;
1649             return [NSNumber numberWithInt:lineNumber];
1650         }
1651     }
1652     
1653     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1654         KURL url = m_object->url();
1655         if (url.isNull())
1656             return nil;
1657         return (NSURL*)url;
1658     }
1659
1660     if ([attributeName isEqualToString: @"AXVisited"])
1661         return [NSNumber numberWithBool: m_object->isVisited()];
1662     
1663     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1664         if (m_object->isAttachment()) {
1665             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 
1666                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1667         }
1668         return m_object->title();
1669     }
1670     
1671     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1672         if (m_object->isAttachment()) {
1673             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1674                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1675         }
1676         return m_object->accessibilityDescription();
1677     }
1678
1679     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1680         if (m_object->isAttachment()) {
1681             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 
1682                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1683         }
1684         if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar())
1685             return [NSNumber numberWithFloat:m_object->valueForRange()];
1686         if (m_object->roleValue() == SliderThumbRole)
1687             return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
1688         if (m_object->isHeading())
1689             return [NSNumber numberWithInt:m_object->headingLevel()];
1690         
1691         if (m_object->isCheckboxOrRadio()) {
1692             switch (m_object->checkboxOrRadioValue()) {
1693             case ButtonStateOff:
1694                 return [NSNumber numberWithInt:0];
1695             case ButtonStateOn:
1696                 return [NSNumber numberWithInt:1];
1697             case ButtonStateMixed:
1698                 return [NSNumber numberWithInt:2];
1699             }
1700         }
1701
1702         // radio groups return the selected radio button as the AXValue
1703         if (m_object->isRadioGroup()) {
1704             AccessibilityObject* radioButton = m_object->selectedRadioButton();
1705             if (!radioButton)
1706                 return nil;
1707             return radioButton->wrapper();
1708         }
1709         
1710         if (m_object->isTabList()) {
1711             AccessibilityObject* tabItem = m_object->selectedTabItem();
1712             if (!tabItem)
1713                 return nil;
1714             return tabItem->wrapper();
1715         }
1716         
1717         if (m_object->isTabItem())
1718             return [NSNumber numberWithInt:m_object->isSelected()];
1719         
1720         return m_object->stringValue();
1721     }
1722
1723     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1724         return [NSNumber numberWithFloat:m_object->minValueForRange()];
1725
1726     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1727         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1728
1729     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1730         return m_object->helpText();
1731
1732     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1733         return [NSNumber numberWithBool: m_object->isFocused()];
1734
1735     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1736         return [NSNumber numberWithBool: m_object->isEnabled()];
1737
1738     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1739         IntSize s = m_object->size();
1740         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1741     }
1742
1743     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1744         return [self position];
1745
1746     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1747         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1748         
1749         id remoteParent = [self remoteAccessibilityParentObject];
1750         if (remoteParent)
1751             return [remoteParent accessibilityAttributeValue:attributeName];
1752         
1753         FrameView* fv = m_object->documentFrameView();
1754         if (fv)
1755             return [fv->platformWidget() window];
1756         return nil;
1757     }
1758     
1759     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
1760         AtomicString accessKey = m_object->accessKey();
1761         if (accessKey.isNull())
1762             return nil;
1763         return accessKey;
1764     }
1765     
1766     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
1767         if (m_object->isTabList()) {
1768             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1769             m_object->tabChildren(tabsChildren);
1770             return convertToNSArray(tabsChildren);
1771         }
1772     }
1773     
1774     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
1775         // The contents of a tab list are all the children except the tabs.
1776         if (m_object->isTabList()) {
1777             AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1778             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1779             m_object->tabChildren(tabsChildren);
1780
1781             AccessibilityObject::AccessibilityChildrenVector contents;
1782             unsigned childrenSize = children.size();
1783             for (unsigned k = 0; k < childrenSize; ++k) {
1784                 if (tabsChildren.find(children[k]) == WTF::notFound)
1785                     contents.append(children[k]);
1786             }
1787             return convertToNSArray(contents);
1788         } else if (m_object->isScrollView()) {
1789             AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1790             
1791             // A scrollView's contents are everything except the scroll bars.
1792             AccessibilityObject::AccessibilityChildrenVector contents;
1793             unsigned childrenSize = children.size();
1794             for (unsigned k = 0; k < childrenSize; ++k) {
1795                 if (!children[k]->isScrollbar())
1796                     contents.append(children[k]);
1797             }
1798             return convertToNSArray(contents);            
1799         }
1800     }    
1801     
1802     if (m_object->isAccessibilityTable()) {
1803         // TODO: distinguish between visible and non-visible rows
1804         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 
1805             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1806             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
1807         }
1808         // TODO: distinguish between visible and non-visible columns
1809         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] || 
1810             [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
1811             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
1812         }
1813         
1814         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1815             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1816             m_object->selectedChildren(selectedChildrenCopy);
1817             return convertToNSArray(selectedChildrenCopy);
1818         }
1819         
1820         // HTML tables don't support these
1821         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] || 
1822             [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1823             return nil;
1824         
1825         if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
1826             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1827             static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
1828             return convertToNSArray(columnHeaders);            
1829         }
1830         
1831         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1832             AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
1833             if (headerContainer)
1834                 return headerContainer->wrapper();
1835             return nil;
1836         }
1837
1838         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
1839             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1840             static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
1841             return convertToNSArray(rowHeaders);                        
1842         }
1843         
1844         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
1845             AccessibilityObject::AccessibilityChildrenVector cells;
1846             static_cast<AccessibilityTable*>(m_object)->cells(cells);
1847             return convertToNSArray(cells);
1848         }        
1849     }
1850     
1851     if (m_object->isTableColumn()) {
1852         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1853             return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
1854         
1855         // rows attribute for a column is the list of all the elements in that column at each row
1856         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 
1857             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1858             return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
1859         }
1860         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1861             AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
1862             if (!header)
1863                 return nil;
1864             return header->wrapper();
1865         }
1866     }
1867     
1868     if (m_object->isTableCell()) {
1869         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1870             pair<int, int> rowRange;
1871             static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
1872             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1873         }  
1874         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1875             pair<int, int> columnRange;
1876             static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
1877             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1878         }  
1879     }
1880     
1881     if (m_object->isTree()) {
1882         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1883             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1884             m_object->selectedChildren(selectedChildrenCopy);
1885             return convertToNSArray(selectedChildrenCopy);
1886         }
1887         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
1888             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1889             m_object->ariaTreeRows(rowsCopy);
1890             return convertToNSArray(rowsCopy);            
1891         }
1892         
1893         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
1894         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
1895             return [NSArray array];
1896     }
1897
1898     if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
1899         if (m_object->isTreeItem()) {
1900             AccessibilityObject* parent = m_object->parentObject();
1901             for (; parent && !parent->isTree(); parent = parent->parentObject())
1902             { }
1903             
1904             if (!parent)
1905                 return nil;
1906             
1907             // Find the index of this item by iterating the parents.
1908             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1909             parent->ariaTreeRows(rowsCopy);
1910             size_t count = rowsCopy.size();
1911             for (size_t k = 0; k < count; ++k)
1912                 if (rowsCopy[k]->wrapper() == self)
1913                     return [NSNumber numberWithUnsignedInt:k];
1914             
1915             return nil;
1916         }
1917         if (m_object->isTableRow()) {
1918             if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1919                 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
1920         }
1921     }    
1922     
1923     // The rows that are considered inside this row. 
1924     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
1925         if (m_object->isTreeItem()) {
1926             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1927             m_object->ariaTreeItemDisclosedRows(rowsCopy);
1928             return convertToNSArray(rowsCopy);    
1929         } else if (m_object->isARIATreeGridRow()) {
1930             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1931             static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
1932             return convertToNSArray(rowsCopy);    
1933         }
1934     }
1935     
1936     // The row that contains this row. It should be the same as the first parent that is a treeitem.
1937     if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
1938         if (m_object->isTreeItem()) {
1939             AccessibilityObject* parent = m_object->parentObject();
1940             while (parent) {
1941                 if (parent->isTreeItem())
1942                     return parent->wrapper();
1943                 // If the parent is the tree itself, then this value == nil.
1944                 if (parent->isTree())
1945                     return nil;
1946                 parent = parent->parentObject();
1947             }
1948             return nil;
1949         } else if (m_object->isARIATreeGridRow()) {
1950             AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
1951             if (!row)
1952                 return nil;
1953             return row->wrapper();
1954         }
1955     }
1956
1957     if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute])
1958         return [NSNumber numberWithInt:m_object->hierarchicalLevel()];
1959     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1960         return [NSNumber numberWithBool:m_object->isExpanded()];
1961     
1962     if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1963         return NSAccessibilityVerticalOrientationValue;
1964
1965     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1966         return [self textMarkerRangeForSelection];
1967     
1968     if (m_object->isAccessibilityRenderObject()) {
1969         RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1970         if (!renderer)
1971             return nil;
1972         
1973         if ([attributeName isEqualToString: @"AXStartTextMarker"])
1974             return [self textMarkerForVisiblePosition:startOfDocument(renderer->document())];
1975         if ([attributeName isEqualToString: @"AXEndTextMarker"])
1976             return [self textMarkerForVisiblePosition:endOfDocument(renderer->document())];
1977
1978         if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
1979             return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1980     } else {
1981         if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) {
1982             AccessibilityObject* parent = m_object->parentObjectUnignored();
1983             if (!parent)
1984                 return [NSNumber numberWithInt:0];
1985             return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute];        
1986         }
1987     }
1988     
1989     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1990         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1991         m_object->linkedUIElements(linkedUIElements);
1992         if (linkedUIElements.size() == 0)
1993             return nil;
1994         return convertToNSArray(linkedUIElements);
1995     }
1996
1997     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1998         return [NSNumber numberWithBool:m_object->isSelected()];
1999
2000     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2001         AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
2002         if (uiElement)
2003             return [NSArray arrayWithObject:uiElement->wrapper()];
2004     }
2005
2006     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2007         AccessibilityObject* obj = m_object->titleUIElement();
2008         if (obj)
2009             return obj->wrapper();
2010         return nil;
2011     }
2012     
2013     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
2014         return m_object->valueDescription();
2015     
2016     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2017         AccessibilityOrientation elementOrientation = m_object->orientation();
2018         if (elementOrientation == AccessibilityOrientationVertical)
2019             return NSAccessibilityVerticalOrientationValue;
2020         if (elementOrientation == AccessibilityOrientationHorizontal)
2021             return NSAccessibilityHorizontalOrientationValue;
2022         return nil;
2023     }
2024     
2025     if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2026         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2027         if (scrollBar)
2028             return scrollBar->wrapper();
2029         return nil;
2030     }
2031     if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2032         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2033         if (scrollBar)
2034             return scrollBar->wrapper();
2035         return nil;
2036     }
2037     
2038     if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2039         switch (m_object->sortDirection()) {
2040         case SortDirectionAscending:
2041             return NSAccessibilityAscendingSortDirectionValue;
2042         case SortDirectionDescending:
2043             return NSAccessibilityDescendingSortDirectionValue;
2044         default:
2045             return NSAccessibilityUnknownSortDirectionValue;
2046         }
2047     }
2048     
2049     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute]) 
2050         return m_object->language();
2051     
2052     if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2053         return [NSNumber numberWithBool:m_object->isExpanded()];
2054     
2055     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2056         return [NSNumber numberWithBool:m_object->isRequired()];
2057
2058     if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2059         return m_object->invalidStatus();
2060     
2061     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2062         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2063         m_object->ariaOwnsElements(ariaOwns);
2064         return convertToNSArray(ariaOwns);
2065     }
2066     
2067     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2068         return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
2069     
2070     if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
2071         Vector<String> dropEffects;
2072         m_object->determineARIADropEffects(dropEffects);
2073         size_t length = dropEffects.size();
2074
2075         NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
2076         for (size_t i = 0; i < length; ++i)
2077             [dropEffectsArray addObject:dropEffects[i]];
2078         return dropEffectsArray;
2079     }
2080     
2081     if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2082         return m_object->placeholderValue();
2083     
2084     if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2085         return [NSNumber numberWithBool:m_object->ariaHasPopup()];
2086     
2087     // ARIA Live region attributes.
2088     if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2089         return m_object->ariaLiveRegionStatus();
2090     if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2091          return m_object->ariaLiveRegionRelevant();
2092     if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2093         return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
2094     if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
2095         return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
2096     
2097     // this is used only by DumpRenderTree for testing
2098     if ([attributeName isEqualToString:@"AXClickPoint"])
2099         return [NSValue valueWithPoint:m_object->clickPoint()];
2100     
2101     // This is used by DRT to verify CSS3 speech works.
2102     if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) {
2103         ESpeak speakProperty = m_object->speakProperty();
2104         switch (speakProperty) {
2105         case SpeakNone:
2106             return @"none";
2107         case SpeakSpellOut:
2108             return @"spell-out";
2109         case SpeakDigits:
2110             return @"digits";
2111         case SpeakLiteralPunctuation:
2112             return @"literal-punctuation";
2113         case SpeakNoPunctuation:
2114             return @"no-punctuation";
2115         default:
2116         case SpeakNormal:
2117             return @"normal";
2118         }
2119     }
2120     
2121     return nil;
2122 }
2123
2124 - (id)accessibilityFocusedUIElement
2125 {
2126     if (![self updateObjectBackingStore])
2127         return nil;
2128
2129     RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
2130
2131     if (!focusedObj)
2132         return nil;
2133     
2134     return focusedObj->wrapper();
2135 }
2136
2137 - (id)accessibilityHitTest:(NSPoint)point
2138 {
2139     if (![self updateObjectBackingStore])
2140         return nil;
2141
2142     m_object->updateChildrenIfNecessary();
2143     RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point));
2144     if (axObject)
2145         return NSAccessibilityUnignoredAncestor(axObject->wrapper());
2146     return NSAccessibilityUnignoredAncestor(self);
2147 }
2148
2149 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2150 {
2151     if (![self updateObjectBackingStore])
2152         return nil;
2153
2154     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2155         return YES;
2156
2157     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2158         return m_object->canSetFocusAttribute();
2159
2160     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2161         return m_object->canSetValueAttribute();
2162
2163     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2164         return m_object->canSetSelectedAttribute();
2165     
2166     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2167         return m_object->canSetSelectedChildrenAttribute();
2168
2169     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2170         return m_object->canSetExpandedAttribute();
2171
2172     if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2173         return YES;
2174
2175     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
2176         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
2177         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2178         return m_object->canSetTextRangeAttributes();
2179     
2180     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2181         return YES;
2182     
2183     return NO;
2184 }
2185
2186 // accessibilityShouldUseUniqueId is an AppKit method we override so that
2187 // objects will be given a unique ID, and therefore allow AppKit to know when they
2188 // become obsolete (e.g. when the user navigates to a new web page, making this one
2189 // unrendered but not deallocated because it is in the back/forward cache).
2190 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
2191 // appropriate place (e.g. dealloc) to remove these non-retained references from
2192 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
2193 //
2194 // Registering an object is also required for observing notifications. Only registered objects can be observed.
2195 - (BOOL)accessibilityIsIgnored
2196 {
2197     if (![self updateObjectBackingStore])
2198         return YES;
2199
2200     if (m_object->isAttachment())
2201         return [[self attachmentView] accessibilityIsIgnored];
2202     return m_object->accessibilityIsIgnored();
2203 }
2204
2205 - (NSArray* )accessibilityParameterizedAttributeNames
2206 {
2207     if (![self updateObjectBackingStore])
2208         return nil;
2209
2210     if (m_object->isAttachment()) 
2211         return nil;
2212
2213     static NSArray* paramAttrs = nil;
2214     static NSArray* textParamAttrs = nil;
2215     static NSArray* tableParamAttrs = nil;
2216     if (paramAttrs == nil) {
2217         paramAttrs = [[NSArray alloc] initWithObjects:
2218                       @"AXUIElementForTextMarker",
2219                       @"AXTextMarkerRangeForUIElement",
2220                       @"AXLineForTextMarker",
2221                       @"AXTextMarkerRangeForLine",
2222                       @"AXStringForTextMarkerRange",
2223                       @"AXTextMarkerForPosition",
2224                       @"AXBoundsForTextMarkerRange",
2225                       @"AXAttributedStringForTextMarkerRange",
2226                       @"AXTextMarkerRangeForUnorderedTextMarkers",
2227                       @"AXNextTextMarkerForTextMarker",
2228                       @"AXPreviousTextMarkerForTextMarker",
2229                       @"AXLeftWordTextMarkerRangeForTextMarker",
2230                       @"AXRightWordTextMarkerRangeForTextMarker",
2231                       @"AXLeftLineTextMarkerRangeForTextMarker",
2232                       @"AXRightLineTextMarkerRangeForTextMarker",
2233                       @"AXSentenceTextMarkerRangeForTextMarker",
2234                       @"AXParagraphTextMarkerRangeForTextMarker",
2235                       @"AXNextWordEndTextMarkerForTextMarker",
2236                       @"AXPreviousWordStartTextMarkerForTextMarker",
2237                       @"AXNextLineEndTextMarkerForTextMarker",
2238                       @"AXPreviousLineStartTextMarkerForTextMarker",
2239                       @"AXNextSentenceEndTextMarkerForTextMarker",
2240                       @"AXPreviousSentenceStartTextMarkerForTextMarker",
2241                       @"AXNextParagraphEndTextMarkerForTextMarker",
2242                       @"AXPreviousParagraphStartTextMarkerForTextMarker",
2243                       @"AXStyleTextMarkerRangeForTextMarker",
2244                       @"AXLengthForTextMarkerRange",
2245                       NSAccessibilityBoundsForRangeParameterizedAttribute,
2246                       NSAccessibilityStringForRangeParameterizedAttribute,
2247                       nil];
2248     }
2249
2250     if (textParamAttrs == nil) {
2251         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2252         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2253         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2254         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2255         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2256         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2257         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2258         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2259         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2260         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2261         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2262         [tempArray release];
2263     }
2264     if (tableParamAttrs == nil) {
2265         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2266         [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2267         tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2268         [tempArray release];
2269     }
2270     
2271     if (m_object->isPasswordField())
2272         return [NSArray array];
2273     
2274     if (!m_object->isAccessibilityRenderObject())
2275         return paramAttrs;
2276
2277     if (m_object->isTextControl())
2278         return textParamAttrs;
2279     
2280     if (m_object->isAccessibilityTable())
2281         return tableParamAttrs;
2282     
2283     if (m_object->isMenuRelated())
2284         return nil;
2285
2286     return paramAttrs;
2287 }
2288
2289 - (void)accessibilityPerformPressAction
2290 {
2291     if (![self updateObjectBackingStore])
2292         return;
2293
2294     if (m_object->isAttachment())
2295         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2296     else
2297         m_object->press();    
2298 }
2299
2300 - (void)accessibilityPerformIncrementAction
2301 {
2302     if (![self updateObjectBackingStore])
2303         return;
2304
2305     if (m_object->isAttachment())
2306         [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2307     else
2308         m_object->increment();    
2309 }
2310
2311 - (void)accessibilityPerformDecrementAction
2312 {
2313     if (![self updateObjectBackingStore])
2314         return;
2315
2316     if (m_object->isAttachment())
2317         [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2318     else
2319         m_object->decrement();    
2320 }
2321
2322 - (void)accessibilityPerformShowMenuAction
2323 {
2324     if (m_object->roleValue() == ComboBoxRole)
2325         m_object->setIsExpanded(true);
2326     else {
2327         // This needs to be performed in an iteration of the run loop that did not start from an AX call. 
2328         // If it's the same run loop iteration, the menu open notification won't be sent
2329         [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2330     }
2331 }
2332
2333 - (void)accessibilityShowContextMenu
2334 {    
2335     FrameView* frameView = m_object->documentFrameView();
2336     if (!frameView)
2337         return;
2338     Frame* frame = frameView->frame();
2339     if (!frame)
2340         return;
2341     Page* page = frame->page();
2342     if (!page)
2343         return;
2344
2345     // Simulate a click in the middle of the object.
2346     IntPoint clickPoint = m_object->clickPoint();
2347     
2348     PlatformMouseEvent mouseEvent(clickPoint, clickPoint, RightButton, MouseEventPressed, 1, false, false, false, false, currentTime());
2349     bool handled = frame->eventHandler()->sendContextMenuEvent(mouseEvent);
2350     if (handled)
2351         page->chrome()->showContextMenu();
2352 }
2353
2354 - (void)accessibilityPerformAction:(NSString*)action
2355 {
2356     if (![self updateObjectBackingStore])
2357         return;
2358
2359     if ([action isEqualToString:NSAccessibilityPressAction])
2360         [self accessibilityPerformPressAction];
2361     
2362     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2363         [self accessibilityPerformShowMenuAction];
2364
2365     else if ([action isEqualToString:NSAccessibilityIncrementAction])
2366         [self accessibilityPerformIncrementAction];
2367
2368     else if ([action isEqualToString:NSAccessibilityDecrementAction])
2369         [self accessibilityPerformDecrementAction];
2370 }
2371
2372 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2373 {
2374     if (![self updateObjectBackingStore])
2375         return;
2376
2377     id textMarkerRange = nil;
2378     NSNumber*               number = nil;
2379     NSString*               string = nil;
2380     NSRange                 range = {0, 0};
2381     NSArray*                array = nil;
2382     
2383     // decode the parameter
2384     if (AXObjectIsTextMarkerRange(value))
2385         textMarkerRange = value;
2386
2387     else if ([value isKindOfClass:[NSNumber self]])
2388         number = value;
2389
2390     else if ([value isKindOfClass:[NSString self]])
2391         string = value;
2392     
2393     else if ([value isKindOfClass:[NSValue self]])
2394         range = [value rangeValue];
2395     
2396     else if ([value isKindOfClass:[NSArray self]])
2397         array = value;
2398     
2399     // handle the command
2400     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2401         ASSERT(textMarkerRange);
2402         m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);        
2403     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2404         ASSERT(number);
2405         m_object->setFocused([number intValue] != 0);
2406     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2407         if (number && m_object->canSetNumericValue())
2408             m_object->setValue([number floatValue]);
2409         else if (string)
2410             m_object->setValue(string);
2411     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
2412         if (!number)
2413             return;
2414         m_object->setSelected([number boolValue]);
2415     } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2416         if (!array || m_object->roleValue() != ListBoxRole)
2417             return;
2418         AccessibilityObject::AccessibilityChildrenVector selectedChildren;
2419         convertToVector(array, selectedChildren);
2420         static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
2421     } else if (m_object->isTextControl()) {
2422         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2423             m_object->setSelectedText(string);
2424         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2425             m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2426         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2427             m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
2428         }
2429     } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2430         m_object->setIsExpanded([number boolValue]);
2431     else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2432         AccessibilityObject::AccessibilityChildrenVector selectedRows;
2433         convertToVector(array, selectedRows);
2434         if (m_object->isTree() || m_object->isAccessibilityTable())
2435             m_object->setSelectedRows(selectedRows);
2436     } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2437         m_object->setARIAGrabbed([number boolValue]);
2438 }
2439
2440 static RenderObject* rendererForView(NSView* view)
2441 {
2442     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
2443         return 0;
2444
2445     NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
2446     Frame* frame = [frameView _web_frame];
2447     if (!frame)
2448         return 0;
2449
2450     Node* node = frame->document()->ownerElement();
2451     if (!node)
2452         return 0;
2453
2454     return node->renderer();
2455 }
2456
2457 - (id)_accessibilityParentForSubview:(NSView*)subview
2458 {   
2459     RenderObject* renderer = rendererForView(subview);
2460     if (!renderer)
2461         return nil;
2462
2463     AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
2464     if (obj)
2465         return obj->parentObjectUnignored()->wrapper();
2466     return nil;
2467 }
2468
2469 - (NSString*)accessibilityActionDescription:(NSString*)action
2470 {
2471     // we have no custom actions
2472     return NSAccessibilityActionDescription(action);
2473 }
2474
2475 // The CFAttributedStringType representation of the text associated with this accessibility
2476 // object that is specified by the given range.
2477 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
2478 {
2479     PlainTextRange textRange = PlainTextRange(range.location, range.length);
2480     VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
2481     return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
2482 }
2483
2484 // The RTF representation of the text associated with this accessibility object that is
2485 // specified by the given range.
2486 - (NSData*)doAXRTFForRange:(NSRange)range
2487 {
2488     NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
2489     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
2490 }
2491
2492 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2493 {
2494     id textMarker = nil;
2495     id textMarkerRange = nil;
2496     NSNumber* number = nil;
2497     NSArray* array = nil;
2498     RefPtr<AccessibilityObject> uiElement = 0;
2499     NSPoint point = NSZeroPoint;
2500     bool pointSet = false;
2501     NSRange range = {0, 0};
2502     bool rangeSet = false;
2503     
2504     // basic parameter validation
2505     if (!m_object || !attribute || !parameter)
2506         return nil;
2507
2508     if (![self updateObjectBackingStore])
2509         return nil;
2510     
2511     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
2512     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
2513     // a parameter of the wrong type.
2514     if (AXObjectIsTextMarker(parameter))
2515         textMarker = parameter;
2516
2517     else if (AXObjectIsTextMarkerRange(parameter))
2518         textMarkerRange = parameter;
2519
2520     else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
2521         uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
2522
2523     else if ([parameter isKindOfClass:[NSNumber self]])
2524         number = parameter;
2525
2526     else if ([parameter isKindOfClass:[NSArray self]])
2527         array = parameter;
2528
2529     else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2530         pointSet = true;
2531         point = [(NSValue*)parameter pointValue];
2532
2533     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2534         rangeSet = true;
2535         range = [(NSValue*)parameter rangeValue];
2536     } else {
2537         // Attribute type is not supported. Allow super to handle.
2538         return [super accessibilityAttributeValue:attribute forParameter:parameter];
2539     }
2540     
2541     // dispatch
2542     if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
2543         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2544         AccessibilityObject* axObject = m_object->accessibilityObjectForPosition(visiblePos);
2545         if (!axObject)
2546             return nil;
2547         return axObject->wrapper();
2548     }
2549
2550     if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
2551         VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
2552         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2553     }
2554
2555     if ([attribute isEqualToString:@"AXLineForTextMarker"]) {
2556         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2557         return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
2558     }
2559
2560     if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) {
2561         VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine([number intValue]);
2562         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2563     }
2564
2565     if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) {
2566         VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2567         return m_object->stringForVisiblePositionRange(visiblePosRange);
2568     }
2569
2570     if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
2571         IntPoint webCorePoint = IntPoint(point);
2572         return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil;
2573     }
2574
2575     if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
2576         VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2577         NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
2578         return [NSValue valueWithRect:rect];
2579     }
2580     
2581     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2582         VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2583         VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2584         if (start.isNull() || end.isNull())
2585             return nil;
2586         NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
2587         return [NSValue valueWithRect:rect];
2588     }
2589     
2590     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
2591         VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2592         VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2593         if (start.isNull() || end.isNull())
2594             return nil;
2595         return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
2596     }
2597
2598     if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
2599         return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
2600
2601     if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
2602         if ([array count] < 2)
2603             return nil;
2604
2605         id textMarker1 = [array objectAtIndex:0];
2606         id textMarker2 = [array objectAtIndex:1];
2607         if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2))
2608             return nil;
2609
2610         VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:(textMarker1)];
2611         VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:(textMarker2)];
2612         VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
2613         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2614     }
2615
2616     if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
2617         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2618         return [self textMarkerForVisiblePosition:m_object->nextVisiblePosition(visiblePos)];
2619     }
2620
2621     if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
2622         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2623         return [self textMarkerForVisiblePosition:m_object->previousVisiblePosition(visiblePos)];
2624     }
2625
2626     if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
2627         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2628         VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
2629         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2630     }
2631
2632     if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
2633         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2634         VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
2635         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2636     }
2637
2638     if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
2639         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2640         VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
2641         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2642     }
2643
2644     if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"]) {
2645         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2646         VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
2647         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2648     }
2649
2650     if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
2651         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2652         VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
2653         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2654     }
2655
2656     if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
2657         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2658         VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
2659         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2660     }
2661
2662     if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
2663         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2664         return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
2665     }
2666     
2667     if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
2668         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2669         return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
2670     }
2671
2672     if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
2673         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2674         return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)];
2675     }
2676
2677     if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) {
2678         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2679         return [self textMarkerForVisiblePosition:m_object->previousLineStartPosition(visiblePos)];
2680     }
2681
2682     if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
2683         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2684         return [self textMarkerForVisiblePosition:m_object->nextSentenceEndPosition(visiblePos)];
2685     }
2686
2687     if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
2688         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2689         return [self textMarkerForVisiblePosition:m_object->previousSentenceStartPosition(visiblePos)];
2690     }
2691
2692     if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
2693         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2694         return [self textMarkerForVisiblePosition:m_object->nextParagraphEndPosition(visiblePos)];
2695     }
2696
2697     if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
2698         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2699         return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)];
2700     }
2701
2702     if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
2703         VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2704         VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
2705         return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2706     }
2707
2708     if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
2709         VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2710         int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
2711         if (length < 0)
2712             return nil;
2713         return [NSNumber numberWithInt:length];
2714     }
2715
2716     // Used only by DumpRenderTree (so far).
2717     if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) {
2718         VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2719         return [self textMarkerForVisiblePosition:visiblePosRange.start];
2720     }
2721
2722     if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) {
2723         VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2724         return [self textMarkerForVisiblePosition:visiblePosRange.end];
2725     }
2726     
2727     if (m_object->isAccessibilityTable()) {
2728         if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
2729             if (array == nil || [array count] != 2)
2730                 return nil;
2731             AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
2732             if (!cell)
2733                 return nil;
2734             
2735             return cell->wrapper();
2736         }
2737     }
2738
2739     if (m_object->isTextControl()) {
2740         if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
2741             int lineNumber = m_object->doAXLineForIndex([number intValue]);
2742             if (lineNumber < 0)
2743                 return nil;
2744             return [NSNumber numberWithUnsignedInt:lineNumber];
2745         }
2746
2747         if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
2748             PlainTextRange textRange = m_object->doAXRangeForLine([number intValue]);
2749             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2750         }
2751
2752         if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) {
2753             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2754             return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
2755         }
2756
2757         if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
2758             if (!pointSet)
2759                 return nil;
2760             IntPoint webCorePoint = IntPoint(point);
2761             PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
2762             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2763         }
2764
2765         if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
2766             PlainTextRange textRange = m_object->doAXRangeForIndex([number intValue]);
2767             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2768         }
2769
2770         if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
2771             if (!rangeSet)
2772                 return nil;
2773             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2774             NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
2775             return [NSValue valueWithRect:rect];
2776         }
2777
2778         if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2779             return rangeSet ? [self doAXRTFForRange:range] : nil;
2780
2781         if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2782             return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
2783
2784         if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
2785             PlainTextRange textRange = m_object->doAXStyleRangeForIndex([number intValue]);
2786             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2787         }
2788     }
2789
2790     // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
2791     // In that case it must be passed to super. 
2792     return [super accessibilityAttributeValue:attribute forParameter:parameter];
2793 }
2794
2795 - (BOOL)accessibilitySupportsOverriddenAttributes
2796 {
2797     return YES;
2798 }
2799
2800 - (BOOL)accessibilityShouldUseUniqueId
2801 {
2802     // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up.
2803     return YES;
2804 }
2805
2806 // API that AppKit uses for faster access
2807 - (NSUInteger)accessibilityIndexOfChild:(id)child
2808 {
2809     if (![self updateObjectBackingStore])
2810         return NSNotFound;
2811     
2812     // Tree objects return their rows as their children. We can use the original method
2813     // here, because we won't gain any speed up.
2814     if (m_object->isTree())
2815         return [super accessibilityIndexOfChild:child];
2816        
2817     const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2818        
2819     if (children.isEmpty())
2820         return [[self renderWidgetChildren] indexOfObject:child];
2821     
2822     unsigned count = children.size();
2823     for (unsigned k = 0; k < count; ++k) {
2824         AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
2825         if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child)) 
2826             return k;
2827     }
2828
2829     return NSNotFound;
2830 }
2831
2832 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
2833 {
2834     if (![self updateObjectBackingStore])
2835         return 0;
2836     
2837     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2838         // Tree items object returns a different set of children than those that are in children()
2839         // because an AXOutline (the mac role is becomes) has some odd stipulations.
2840         if (m_object->isTree() || m_object->isTreeItem())
2841             return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
2842         
2843         const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2844         if (children.isEmpty())
2845             return [[self renderWidgetChildren] count];
2846         
2847         return children.size();
2848     }
2849     
2850     return [super accessibilityArrayAttributeCount:attribute];
2851 }
2852
2853 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount 
2854 {
2855     if (![self updateObjectBackingStore])
2856         return nil;
2857     
2858     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2859         if (m_object->children().isEmpty()) {
2860             NSArray *children = [self renderWidgetChildren];
2861             if (!children) 
2862                 return nil;
2863             
2864             NSUInteger childCount = [children count];
2865             if (index >= childCount)
2866                 return nil;
2867             
2868             NSUInteger arrayLength = min(childCount - index, maxCount);
2869             return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
2870         } else if (m_object->isTree()) {
2871             // Tree objects return their rows as their children. We can use the original method in this case.
2872             return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2873         }
2874         
2875         const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2876         unsigned childCount = children.size();
2877         if (index >= childCount)
2878             return nil;
2879         
2880         unsigned available = min(childCount - index, maxCount);
2881         
2882         NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
2883         for (unsigned added = 0; added < available; ++index, ++added) {
2884             AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
2885             if (wrapper) {
2886                 // The attachment view should be returned, otherwise AX palindrome errors occur.
2887                 if (children[index]->isAttachment() && [wrapper attachmentView])
2888                     [subarray addObject:[wrapper attachmentView]];
2889                 else
2890                     [subarray addObject:wrapper];
2891             }
2892         }
2893         
2894         return subarray;
2895     }
2896     
2897     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2898 }
2899
2900 // This is set by DRT when it wants to listen for notifications.
2901 static BOOL accessibilityShouldRepostNotifications;
2902 - (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
2903 {
2904     accessibilityShouldRepostNotifications = repost;
2905 }
2906
2907 - (void)accessibilityPostedNotification:(NSString *)notificationName
2908 {
2909     if (accessibilityShouldRepostNotifications) {
2910         NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", nil];
2911         [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:nil userInfo:userInfo];
2912     }
2913 }
2914
2915 @end
2916
2917 #endif // HAVE(ACCESSIBILITY)