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