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