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