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