WebCore:
[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 #import "AXObjectCache.h"
33 #import "AccessibilityListBox.h"
34 #import "AccessibilityRenderObject.h"
35 #import "ColorMac.h"
36 #import "Frame.h"
37 #import "HTMLAnchorElement.h"
38 #import "HTMLAreaElement.h"
39 #import "HTMLImageElement.h"
40 #import "HTMLInputElement.h"
41 #import "HTMLTextAreaElement.h"
42 #import "LocalizedStrings.h"
43 #import "RenderTextControl.h"
44 #import "RenderView.h"
45 #import "RenderWidget.h"
46 #import "SelectionController.h"
47 #import "SimpleFontData.h"
48 #import "TextIterator.h"
49 #import "WebCoreFrameView.h"
50 #import "WebCoreObjCExtras.h"
51 #import "WebCoreViewFactory.h"
52 #import "htmlediting.h"
53 #import "visible_units.h"
54
55 using namespace WebCore;
56 using namespace HTMLNames;
57
58 @implementation AccessibilityObjectWrapper
59
60 #ifndef BUILDING_ON_TIGER
61 + (void)initialize
62 {
63     WebCoreObjCFinalizeOnMainThread(self);
64 }
65 #endif
66
67 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
68 {
69     [super init];
70
71     m_object = axObject;
72     return self;
73 }
74
75 - (void)unregisterUniqueIdForUIElement
76 {
77     [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
78 }
79
80 - (void)detach
81 {
82     // Send unregisterUniqueIdForUIElement unconditionally because if it is
83     // ever accidently not done (via other bugs in our AX implementation) you
84     // end up with a crash like <rdar://problem/4273149>.  It is safe and not
85     // expensive to send even if the object is not registered.
86     [self unregisterUniqueIdForUIElement];
87     m_object = 0;
88 }
89
90 - (AccessibilityObject*)accessibilityObject
91 {
92     return m_object;
93 }
94
95 - (NSView*)attachmentView
96 {
97     ASSERT(m_object->isAttachment());
98     Widget* widget = m_object->widgetForAttachmentView();
99     if (!widget)
100         return nil;
101     return widget->getView();
102 }
103
104 static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos)
105 {
106     if (visiblePos.isNull())
107         return nil;
108
109     Position deepPos = visiblePos.deepEquivalent();
110     Node* domNode = deepPos.node();
111     ASSERT(domNode);
112     if (!domNode)
113         return nil;
114
115     if (domNode->isHTMLElement())
116         if (static_cast<HTMLElement*>(domNode)->isPasswordField())
117             return nil;
118
119     // locate the renderer, which must exist for a visible dom node
120     RenderObject* renderer = domNode->renderer();
121     ASSERT(renderer);
122
123     // find or create an accessibility object for this renderer
124     AXObjectCache* cache = renderer->document()->axObjectCache();
125     RefPtr<AccessibilityObject> obj = cache->get(renderer);
126
127     // create a text marker, adding an ID for the AccessibilityObject if needed
128     TextMarkerData textMarkerData;
129     
130     // The compiler can add padding to this struct. 
131     // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
132     bzero(&textMarkerData, sizeof(TextMarkerData));
133     textMarkerData.axID = obj.get()->axObjectID();
134     textMarkerData.node = domNode;
135     textMarkerData.offset = deepPos.offset();
136     textMarkerData.affinity = visiblePos.affinity();
137     return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)];
138 }
139
140 static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker)
141 {
142     TextMarkerData textMarkerData;
143     
144     if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)])
145         return VisiblePosition();
146
147     VisiblePosition visiblePos = VisiblePosition(textMarkerData.node, textMarkerData.offset, textMarkerData.affinity);
148     Position deepPos = visiblePos.deepEquivalent();
149     if (deepPos.isNull())
150         return VisiblePosition();
151     
152     RenderObject* renderer = deepPos.node()->renderer();
153     if (!renderer)
154         return VisiblePosition();
155     
156     AXObjectCache* cache = renderer->document()->axObjectCache();
157     if (!cache->isIDinUse(textMarkerData.axID))
158         return VisiblePosition();
159
160     if (deepPos.node() != textMarkerData.node || deepPos.offset() != textMarkerData.offset)
161         return VisiblePosition();
162     
163     return visiblePos;
164 }
165
166 static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
167 {
168     return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]);
169 }
170
171 static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
172 {
173     return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]);
174 }
175
176 static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2)
177 {
178     if (!textMarker1 || !textMarker2)
179         return nil;
180         
181     return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
182 }
183
184 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
185 {
186     NSDictionary* dict;
187     
188     if (font) {
189         dict = [NSDictionary dictionaryWithObjectsAndKeys:
190             [font fontName]                             , NSAccessibilityFontNameKey,
191             [font familyName]                           , NSAccessibilityFontFamilyKey,
192             [font displayName]                          , NSAccessibilityVisibleNameKey,
193             [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
194         nil];
195
196         [attrString addAttribute:attribute value:dict range:range];
197     } else
198         [attrString removeAttribute:attribute range:range];
199     
200 }
201
202 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
203 {
204     // get color information assuming NSDeviceRGBColorSpace 
205     NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
206     if (rgbColor == nil)
207         rgbColor = [NSColor blackColor];
208     CGFloat components[4];
209     [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
210     
211     // create a new CGColorRef to return
212     CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
213     CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
214     CGColorSpaceRelease(cgColorSpace);
215     CFMakeCollectable(cgColor);
216     
217     // check for match with existing color
218     if (existingColor && CGColorEqualToColor(cgColor, existingColor))
219         cgColor = nil;
220
221     return cgColor;
222 }
223
224 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
225 {
226     if (color) {
227         CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
228         CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
229         if (cgColor) {
230             [attrString addAttribute:attribute value:(id)cgColor range:range];
231             CGColorRelease(cgColor);
232         }
233     } else
234         [attrString removeAttribute:attribute range:range];
235 }
236
237 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
238 {
239     if (number)
240         [attrString addAttribute:attribute value:number range:range];
241     else
242         [attrString removeAttribute:attribute range:range];
243 }
244
245 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
246 {
247     RenderStyle* style = renderer->style();
248
249     // set basic font info
250     AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
251
252     // set basic colors
253     AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range);
254     AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range);
255
256     // set super/sub scripting
257     EVerticalAlign alignment = style->verticalAlign();
258     if (alignment == SUB)
259         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
260     else if (alignment == SUPER)
261         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
262     else
263         [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
264     
265     // set shadow
266     if (style->textShadow())
267         AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
268     else
269         [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
270     
271     // set underline and strikethrough
272     int decor = style->textDecorationsInEffect();
273     if ((decor & UNDERLINE) == 0) {
274         [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
275         [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
276     }
277     
278     if ((decor & LINE_THROUGH) == 0) {
279         [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
280         [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
281     }
282
283     if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
284         // find colors using quirk mode approach (strict mode would use current
285         // color for all but the root line box, which would use getTextDecorationColors)
286         Color underline, overline, linethrough;
287         renderer->getTextDecorationColors(decor, underline, overline, linethrough);
288         
289         if ((decor & UNDERLINE) != 0) {
290             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
291             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
292         }
293
294         if ((decor & LINE_THROUGH) != 0) {
295             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
296             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
297         }
298     }
299 }
300
301 static int blockquoteLevel(RenderObject* renderer)
302 {
303     int result = 0;
304     for (Node* node = renderer->element(); node; node = node->parent()) {
305         if (node->hasTagName(blockquoteTag))
306             result += 1;
307     }
308     
309     return result;
310 }
311
312 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
313 {
314     int quoteLevel = blockquoteLevel(renderer);
315     
316     if (quoteLevel)
317         [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range];
318     else
319         [attrString removeAttribute:@"AXBlockQuoteLevel" range:range];
320 }
321
322 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range)
323 {
324     Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node);
325     Vector<DocumentMarker>::iterator markerIt = markers.begin();
326
327     unsigned endOffset = (unsigned)offset + range.length;
328     for ( ; markerIt != markers.end(); markerIt++) {
329         DocumentMarker marker = *markerIt;
330         
331         if (marker.type != DocumentMarker::Spelling)
332             continue;
333         
334         if (marker.endOffset <= (unsigned)offset)
335             continue;
336         
337         if (marker.startOffset > endOffset)
338             break;
339         
340         // add misspelling attribute for the intersection of the marker and the range
341         int rStart = range.location + (marker.startOffset - offset);
342         int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset;
343         NSRange spellRange = NSMakeRange(rStart, rLength);
344         AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
345         
346         if (marker.endOffset > endOffset + 1)
347             break;
348     }
349 }
350
351 static void AXAttributeStringSetHeadingLevel(AccessibilityObject* object, NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
352 {
353     int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element());
354     
355     if (parentHeadingLevel)
356         [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
357     else
358         [attrString removeAttribute:@"AXHeadingLevel" range:range];
359 }
360
361 static AccessibilityObject* AXLinkElementForNode(Node* node)
362 {
363     RenderObject* obj = node->renderer();
364     if (!obj)
365         return 0;
366
367     RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->get(obj);
368     HTMLAnchorElement* anchor = axObj->anchorElement();
369     if (!anchor)
370         return 0;
371
372     RenderObject* anchorRenderer = anchor->renderer();
373     if (!anchorRenderer)
374         return 0;
375     
376     return anchorRenderer->document()->axObjectCache()->get(anchorRenderer);
377 }
378
379 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
380 {
381     if (object && object->isAccessibilityRenderObject()) {
382         // make a serialiazable AX object
383         
384         RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
385         if (!renderer)
386             return;
387         
388         Document* doc = renderer->document();
389         if (!doc)
390             return;
391         
392         AXObjectCache* cache = doc->axObjectCache();
393         if (!cache)
394             return;
395
396         AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()];
397         if (axElement) {
398             [attrString addAttribute:attribute value:(id)axElement range:range];
399             CFRelease(axElement);
400         }
401     } else
402         [attrString removeAttribute:attribute range:range];
403 }
404
405 static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length)
406 {
407     // skip invisible text
408     if (!node->renderer())
409         return;
410
411     // easier to calculate the range before appending the string
412     NSRange attrStringRange = NSMakeRange([attrString length], length);
413     
414     // append the string from this node
415     [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
416
417     // add new attributes and remove irrelevant inherited ones
418     // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
419     // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
420     // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
421
422     // remove inherited attachment from prior AXAttributedStringAppendReplaced
423     [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
424     
425     // set new attributes
426     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
427     AXAttributeStringSetHeadingLevel(object, attrString, node->renderer(), attrStringRange);
428     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
429     AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange);
430     
431     // do spelling last because it tends to break up the range
432     AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);
433 }
434
435 static NSString* nsStringForReplacedNode(Node* replacedNode)
436 {
437     // we should always be given a rendered node and a replaced node, but be safe
438     // replaced nodes are either attachments (widgets) or images
439     if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
440         ASSERT_NOT_REACHED();
441         return nil;
442     }
443
444     // create an AX object, but skip it if it is not supposed to be seen
445     RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
446     if (obj->accessibilityIsIgnored())
447         return nil;
448     
449     // use the attachmentCharacter to represent the replaced node
450     const UniChar attachmentChar = NSAttachmentCharacter;
451     return [NSString stringWithCharacters:&attachmentChar length:1];
452 }
453
454 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
455 {
456     // extract the start and end VisiblePosition
457     VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange);
458     if (startVisiblePosition.isNull())
459         return nil;
460
461     VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange);
462     if (endVisiblePosition.isNull())
463         return nil;
464
465     // iterate over the range to build the AX attributed string
466     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
467     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
468     while (!it.atEnd()) {
469         // locate the node and starting offset for this range
470         int exception = 0;
471         Node* node = it.range()->startContainer(exception);
472         ASSERT(node == it.range()->endContainer(exception));
473         int offset = it.range()->startOffset(exception);
474
475         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
476         if (it.length() != 0) {
477             AXAttributedStringAppendText(m_object, attrString, node, offset, it.characters(), it.length());
478         } else {
479             Node* replacedNode = node->childNode(offset);
480             NSString *attachmentString = nsStringForReplacedNode(replacedNode);
481             if (attachmentString) {
482                 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
483
484                 // append the placeholder string
485                 [[attrString mutableString] appendString:attachmentString];
486
487                 // remove all inherited attributes
488                 [attrString setAttributes:nil range:attrStringRange];
489
490                 // add the attachment attribute
491                 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
492                 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
493             }
494         }
495         it.advance();
496     }
497
498     return [attrString autorelease];
499 }
500
501 static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition)
502 {
503     WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition);
504     WebCoreTextMarker* endTextMarker   = textMarkerForVisiblePosition(endPosition);
505     return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
506 }
507
508 - (NSArray*)accessibilityActionNames
509 {
510     static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
511     static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
512     static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
513     
514     NSArray *actions;
515     if (m_object->actionElement()) 
516         actions = actionElementActions;
517     else if (m_object->isMenuRelated())
518         actions = menuElementActions;
519     else if (m_object->isAttachment())
520         actions = [[self attachmentView] accessibilityActionNames];
521     else
522         actions = defaultElementActions;
523
524     return actions;
525 }
526
527 - (NSArray*)accessibilityAttributeNames
528 {
529     if (m_object->isAttachment())
530         return [[self attachmentView] accessibilityAttributeNames];
531
532     static NSArray* attributes = nil;
533     static NSArray* anchorAttrs = nil;
534     static NSArray* webAreaAttrs = nil;
535     static NSArray* textAttrs = nil;
536     static NSArray* listBoxAttrs = nil;
537     static NSArray* rangeAttrs = nil;
538     static NSArray* commonMenuAttrs = nil;
539     static NSArray* menuAttrs = nil;
540     static NSArray* menuBarAttrs = nil;
541     static NSArray* menuItemAttrs = nil;
542     static NSArray* menuButtonAttrs = nil;
543     static NSArray* controlAttrs = nil;
544     NSMutableArray* tempArray;
545     if (attributes == nil) {
546         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
547                       NSAccessibilitySubroleAttribute,
548                       NSAccessibilityRoleDescriptionAttribute,
549                       NSAccessibilityChildrenAttribute,
550                       NSAccessibilityHelpAttribute,
551                       NSAccessibilityParentAttribute,
552                       NSAccessibilityPositionAttribute,
553                       NSAccessibilitySizeAttribute,
554                       NSAccessibilityTitleAttribute,
555                       NSAccessibilityDescriptionAttribute,
556                       NSAccessibilityValueAttribute,
557                       NSAccessibilityFocusedAttribute,
558                       NSAccessibilityEnabledAttribute,
559                       NSAccessibilityWindowAttribute,
560                       @"AXSelectedTextMarkerRange",
561                       @"AXStartTextMarker",
562                       @"AXEndTextMarker",
563                       @"AXVisited",
564                       NSAccessibilityLinkedUIElementsAttribute,
565                       NSAccessibilitySelectedAttribute,
566                       @"AXBlockQuoteLevel",
567                       nil];
568     }
569     if (commonMenuAttrs == nil) {
570         commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
571                             NSAccessibilityRoleDescriptionAttribute,
572                             NSAccessibilityChildrenAttribute,
573                             NSAccessibilityParentAttribute,
574                             NSAccessibilityEnabledAttribute,
575                             NSAccessibilityPositionAttribute,
576                             NSAccessibilitySizeAttribute,
577                             nil];
578     }
579     if (anchorAttrs == nil) {
580         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
581         [tempArray addObject:NSAccessibilityURLAttribute];
582         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
583         [tempArray release];
584     }
585     if (webAreaAttrs == nil) {
586         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
587         [tempArray addObject:@"AXLinkUIElements"];
588         [tempArray addObject:@"AXLoaded"];
589         [tempArray addObject:@"AXLayoutCount"];
590         [tempArray addObject:NSAccessibilityURLAttribute];
591         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
592         [tempArray release];
593     }
594     if (textAttrs == nil) {
595         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
596         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
597         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
598         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
599         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
600         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
601         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
602         textAttrs = [[NSArray alloc] initWithArray:tempArray];
603         [tempArray release];
604     }
605     if (listBoxAttrs == nil) {
606         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
607         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
608         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
609         [tempArray addObject:NSAccessibilityOrientationAttribute];
610         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
611         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
612         [tempArray release];
613     }
614     if (rangeAttrs == nil) {
615         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
616         [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
617         [tempArray addObject:NSAccessibilityValueAttribute];
618         [tempArray addObject:NSAccessibilityMinValueAttribute];
619         [tempArray addObject:NSAccessibilityMaxValueAttribute];
620         rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
621         [tempArray release];
622     }
623     if (menuBarAttrs == nil) {
624         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
625         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
626         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
627         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
628         menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
629         [tempArray release];
630     }
631     if (menuAttrs == nil) {
632         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
633         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
634         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
635         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
636         menuAttrs = [[NSArray alloc] initWithArray:tempArray];
637         [tempArray release];
638     }
639     if (menuItemAttrs == nil) {
640         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
641         [tempArray addObject:NSAccessibilityTitleAttribute];
642         [tempArray addObject:NSAccessibilityHelpAttribute];
643         [tempArray addObject:NSAccessibilitySelectedAttribute];
644         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
645         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
646         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
647         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
648         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
649         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
650         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
651         menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
652         [tempArray release];
653     }
654     if (menuButtonAttrs == nil) {
655         menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
656             NSAccessibilityRoleDescriptionAttribute,
657             NSAccessibilityParentAttribute,
658             NSAccessibilityPositionAttribute,
659             NSAccessibilitySizeAttribute,
660             NSAccessibilityWindowAttribute,
661             NSAccessibilityTopLevelUIElementAttribute,
662             NSAccessibilityEnabledAttribute,
663             NSAccessibilityFocusedAttribute,
664             NSAccessibilityTitleAttribute,
665             NSAccessibilityChildrenAttribute, nil];
666     }
667     if (controlAttrs == nil) {
668         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
669         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
670         controlAttrs = [[NSArray alloc] initWithArray:tempArray];
671         [tempArray release];
672     }
673
674     if (m_object->isPasswordField())
675         return attributes;
676
677     if (m_object->isWebArea())
678         return webAreaAttrs;
679     
680     if (m_object->isTextControl())
681         return textAttrs;
682
683     if (m_object->isAnchor() || m_object->isImage())
684         return anchorAttrs;
685
686     if (m_object->isListBox())
687         return listBoxAttrs;
688
689     if (m_object->isProgressIndicator() || m_object->isSlider())
690         return rangeAttrs;
691
692     if (m_object->isControl())
693         return controlAttrs;
694     
695     if (m_object->isMenu())
696         return menuAttrs;
697     if (m_object->isMenuBar())
698         return menuBarAttrs;
699     if (m_object->isMenuButton())
700         return menuButtonAttrs;
701     if (m_object->isMenuItem())
702         return menuItemAttrs;
703
704     return attributes;
705 }
706
707 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
708 {
709     return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange));
710 }
711
712 - (NSArray*)renderWidgetChildren
713 {
714     Widget* widget = m_object->widget();
715     if (!widget)
716         return nil;
717     return [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
718 }
719
720 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
721 {
722     unsigned length = [array count];
723     vector.reserveCapacity(length);
724     for (unsigned i = 0; i < length; ++i) {
725         AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
726         if (obj)
727             vector.append(obj);
728     }
729 }
730
731 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
732 {
733     unsigned length = vector.size();
734     NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
735     for (unsigned i = 0; i < length; ++i)
736         [array addObject:vector[i]->wrapper()];
737     return array;
738 }
739
740 - (WebCoreTextMarkerRange*)textMarkerRangeForSelection
741 {
742     Selection selection = m_object->selection();
743     if (selection.isNone())
744         return nil;
745     return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd());
746 }
747
748 - (NSValue*)position
749 {
750     IntRect rect = m_object->elementRect();
751     
752     // The Cocoa accessibility API wants the lower-left corner.
753     NSPoint point = NSMakePoint(rect.x(), rect.bottom());
754     FrameView* frameView = m_object->documentFrameView();
755     if (frameView) {
756         NSView* view = frameView->documentView();
757         point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
758     }
759
760     return [NSValue valueWithPoint: point];
761 }
762
763 typedef HashMap<int, NSString*> AccessibilityRoleMap;
764
765 static const AccessibilityRoleMap& createAccessibilityRoleMap()
766 {
767     struct RoleEntry {
768         AccessibilityRole value;
769         NSString* string;
770     };
771     
772     static const RoleEntry roles[] = {
773         { UnknownRole, NSAccessibilityUnknownRole },
774         { ButtonRole, NSAccessibilityButtonRole },
775         { RadioButtonRole, NSAccessibilityRadioButtonRole },
776         { CheckBoxRole, NSAccessibilityCheckBoxRole },
777         { SliderRole, NSAccessibilitySliderRole },
778         { TabGroupRole, NSAccessibilityTabGroupRole },
779         { TextFieldRole, NSAccessibilityTextFieldRole },
780         { StaticTextRole, NSAccessibilityStaticTextRole },
781         { TextAreaRole, NSAccessibilityTextAreaRole },
782         { ScrollAreaRole, NSAccessibilityScrollAreaRole },
783         { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
784         { MenuButtonRole, NSAccessibilityMenuButtonRole },
785         { TableRole, NSAccessibilityTableRole },
786         { ApplicationRole, NSAccessibilityApplicationRole },
787         { GroupRole, NSAccessibilityGroupRole },
788         { RadioGroupRole, NSAccessibilityRadioGroupRole },
789         { ListRole, NSAccessibilityListRole },
790         { ScrollBarRole, NSAccessibilityScrollBarRole },
791         { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
792         { ImageRole, NSAccessibilityImageRole },
793         { MenuBarRole, NSAccessibilityMenuBarRole },
794         { MenuRole, NSAccessibilityMenuRole },
795         { MenuItemRole, NSAccessibilityMenuItemRole },
796         { ColumnRole, NSAccessibilityColumnRole },
797         { RowRole, NSAccessibilityRowRole },
798         { ToolbarRole, NSAccessibilityToolbarRole },
799         { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
800         { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
801         { WindowRole, NSAccessibilityWindowRole },
802         { DrawerRole, NSAccessibilityDrawerRole },
803         { SystemWideRole, NSAccessibilitySystemWideRole },
804         { OutlineRole, NSAccessibilityOutlineRole },
805         { IncrementorRole, NSAccessibilityIncrementorRole },
806         { BrowserRole, NSAccessibilityBrowserRole },
807         { ComboBoxRole, NSAccessibilityComboBoxRole },
808         { SplitGroupRole, NSAccessibilitySplitGroupRole },
809         { SplitterRole, NSAccessibilitySplitterRole },
810         { ColorWellRole, NSAccessibilityColorWellRole },
811         { GrowAreaRole, NSAccessibilityGrowAreaRole },
812         { SheetRole, NSAccessibilitySheetRole },
813         { HelpTagRole, NSAccessibilityHelpTagRole },
814         { MatteRole, NSAccessibilityMatteRole }, 
815         { RulerRole, NSAccessibilityRulerRole },
816         { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
817         { LinkRole, NSAccessibilityLinkRole },
818 #ifndef BUILDING_ON_TIGER        
819         { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
820         { GridRole, NSAccessibilityGridRole },
821 #endif
822         { WebCoreLinkRole, @"AXLink" }, // why isn't this just NSAccessibilityLinkRole ?
823         { ImageMapRole, @"AXImageMap" },
824         { ListMarkerRole, @"AXListMarker" },
825         { WebAreaRole, @"AXWebArea" },
826         { HeadingRole, @"AXHeading" },
827         { ListBoxRole, NSAccessibilityListRole },
828         { ListBoxOptionRole, NSAccessibilityStaticTextRole }
829     };
830     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
831     
832     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
833     for (unsigned i = 0; i < numRoles; ++i)
834         roleMap.set(roles[i].value, roles[i].string);
835     return roleMap;
836 }
837
838 static NSString* roleValueToNSString(AccessibilityRole value)
839 {
840     ASSERT(value);
841     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
842     return roleMap.get(value);
843 }
844
845 - (NSString*)role
846 {
847     if (m_object->isAttachment())
848         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
849     NSString* string = roleValueToNSString(m_object->roleValue());
850     if (string != nil)
851         return string;
852     return NSAccessibilityUnknownRole;
853 }
854
855 - (NSString*)subrole
856 {
857     if (m_object->isPasswordField())
858         return NSAccessibilitySecureTextFieldSubrole;
859     
860     if (m_object->isAttachment()) {
861         NSView* attachView = [self attachmentView];
862         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
863             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
864         }
865     }
866
867     return nil;
868 }
869
870 - (NSString*)roleDescription
871 {
872     if (!m_object)
873         return nil;
874
875     // attachments have the AXImage role, but a different subrole
876     if (m_object->isAttachment())
877         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
878     
879     // FIXME 3447564: It would be better to call some AppKit API to get these strings
880     // (which would be the best way to localize them)
881     
882     NSString* axRole = [self role];
883     if ([axRole isEqualToString:NSAccessibilityButtonRole])
884         return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, [self subrole]);
885     
886     if ([axRole isEqualToString:NSAccessibilityPopUpButtonRole])
887         return NSAccessibilityRoleDescription(NSAccessibilityPopUpButtonRole, [self subrole]);
888
889     if ([axRole isEqualToString:NSAccessibilityStaticTextRole])
890         return NSAccessibilityRoleDescription(NSAccessibilityStaticTextRole, [self subrole]);
891
892     if ([axRole isEqualToString:NSAccessibilityImageRole])
893         return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]);
894     
895     if ([axRole isEqualToString:NSAccessibilityGroupRole])
896         return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
897     
898     if ([axRole isEqualToString:NSAccessibilityCheckBoxRole])
899         return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]);
900
901     if ([axRole isEqualToString:NSAccessibilityRadioButtonRole])
902         return NSAccessibilityRoleDescription(NSAccessibilityRadioButtonRole, [self subrole]);
903
904     if ([axRole isEqualToString:NSAccessibilityTextFieldRole])
905         return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, [self subrole]);
906
907     if ([axRole isEqualToString:NSAccessibilityTextAreaRole])
908         return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, [self subrole]);
909
910     if ([axRole isEqualToString:NSAccessibilityListRole])
911         return NSAccessibilityRoleDescription(NSAccessibilityListRole, [self subrole]);
912     
913     if ([axRole isEqualToString:@"AXWebArea"])
914         return AXWebAreaText();
915     
916     if ([axRole isEqualToString:@"AXLink"])
917         return AXLinkText();
918     
919     if ([axRole isEqualToString:@"AXListMarker"])
920         return AXListMarkerText();
921     
922     if ([axRole isEqualToString:@"AXImageMap"])
923         return AXImageMapText();
924
925     if ([axRole isEqualToString:@"AXHeading"])
926         return AXHeadingText();
927         
928     if ([axRole isEqualToString:(NSString*)kAXMenuBarItemRole] ||
929         [axRole isEqualToString:NSAccessibilityMenuRole])
930         return nil;
931
932     if ([axRole isEqualToString:NSAccessibilityMenuButtonRole])
933         return NSAccessibilityRoleDescription(NSAccessibilityMenuButtonRole, [self subrole]);
934     
935     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
936 }
937
938 // FIXME: split up this function in a better way.  
939 // suggestions: Use a hash table that maps attribute names to function calls,
940 // or maybe pointers to member functions
941 - (id)accessibilityAttributeValue:(NSString*)attributeName
942 {
943     if (!m_object)
944         return nil;
945
946     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
947         return [self role];
948
949     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
950         return [self subrole];
951
952     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
953         return [self roleDescription];
954
955     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
956         if (m_object->isAccessibilityRenderObject()) {
957             FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
958             if (fv)
959                 return fv->getView();
960         }
961         
962         return m_object->parentObjectUnignored()->wrapper();
963     }
964
965     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
966         if (m_object->children().isEmpty()) {
967             NSArray* children = [self renderWidgetChildren];
968             if (children != nil)
969                 return children;
970         }
971         return convertToNSArray(m_object->children());
972     }
973     
974     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute] && m_object->isListBox()) {
975         AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
976         m_object->selectedChildren(selectedChildrenCopy);
977         return convertToNSArray(selectedChildrenCopy);
978     }
979     
980     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute] && m_object->isListBox()) {
981         AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
982         m_object->visibleChildren(visibleChildrenCopy);
983         return convertToNSArray(visibleChildrenCopy);
984     }
985     
986     
987     if (m_object->isWebArea()) {
988         if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
989             AccessibilityObject::AccessibilityChildrenVector links;
990             m_object->getDocumentLinks(links);
991             return convertToNSArray(links);
992         }
993         if ([attributeName isEqualToString: @"AXLoaded"])
994             return [NSNumber numberWithBool: m_object->isLoaded()];
995         if ([attributeName isEqualToString: @"AXLayoutCount"])
996             return [NSNumber numberWithInt: m_object->layoutCount()];
997     }
998     
999     if (m_object->isTextControl()) {
1000         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1001             int length = m_object->textLength();
1002             if (length < 0)
1003                 return nil;
1004             return [NSNumber numberWithUnsignedInt:length];
1005         }
1006         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1007             String selectedText = m_object->selectedText();
1008             if (selectedText.isNull())
1009                 return nil;
1010             return (NSString*)selectedText;
1011         }
1012         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1013             PlainTextRange textRange = m_object->selectedTextRange();
1014             if (textRange.isNull())
1015                 return nil;
1016             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1017         }
1018         // TODO: Get actual visible range. <rdar://problem/4712101>
1019         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1020             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1021         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1022             if (m_object->isPasswordField() || m_object->selectionStart() != m_object->selectionEnd())
1023                 return nil;
1024             return [NSNumber numberWithInt:m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true))];
1025         }
1026     }
1027     
1028     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1029         KURL url = m_object->url();
1030         if (url.isNull())
1031             return nil;
1032         return (NSURL*)url;
1033     }
1034
1035     if ([attributeName isEqualToString: @"AXVisited"])
1036         return [NSNumber numberWithBool: m_object->isVisited()];
1037     
1038     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1039         if (m_object->isAttachment()) {
1040             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 
1041                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1042         }
1043         return m_object->title();
1044     }
1045     
1046     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1047         if (m_object->isAttachment()) {
1048             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1049                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1050         }
1051         return m_object->accessibilityDescription();
1052     }
1053     
1054     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1055         if (m_object->isAttachment()) {
1056             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 
1057                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1058         }
1059         if (m_object->isProgressIndicator() || m_object->isSlider())
1060             return [NSNumber numberWithFloat:m_object->valueForRange()];
1061         if (m_object->hasIntValue())
1062             return [NSNumber numberWithInt:m_object->intValue()];
1063         return m_object->stringValue();
1064     }
1065
1066     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1067         return [NSNumber numberWithFloat:m_object->minValueForRange()];
1068
1069     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1070         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1071
1072     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1073         return m_object->helpText();
1074
1075     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1076         return [NSNumber numberWithBool: m_object->isFocused()];
1077
1078     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1079         return [NSNumber numberWithBool: m_object->isEnabled()];
1080
1081     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1082         IntSize s = m_object->size();
1083         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1084     }
1085
1086     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1087         return [self position];
1088
1089     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1090         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1091         FrameView* fv = m_object->documentFrameView();
1092         if (fv)
1093             return [fv->getView() window];
1094         return nil;
1095     }
1096     
1097     if (m_object->isListBox() && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1098         return NSAccessibilityVerticalOrientationValue;
1099
1100     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1101         return [self textMarkerRangeForSelection];
1102     
1103     if (m_object->isAccessibilityRenderObject()) {
1104         RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1105         if (!renderer)
1106             return nil;
1107         
1108         if ([attributeName isEqualToString: @"AXStartTextMarker"])
1109             return textMarkerForVisiblePosition(startOfDocument(renderer->document()));
1110         if ([attributeName isEqualToString: @"AXEndTextMarker"])
1111             return textMarkerForVisiblePosition(endOfDocument(renderer->document()));
1112
1113         if ([attributeName isEqualToString: @"AXBlockQuoteLevel"])
1114             return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1115     }
1116     
1117     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1118         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1119         m_object->linkedUIElements(linkedUIElements);
1120         if (linkedUIElements.size() == 0)
1121             return nil;
1122         return convertToNSArray(linkedUIElements);
1123     }
1124
1125     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1126         return [NSNumber numberWithBool:m_object->isSelected()];
1127
1128     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
1129         AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
1130         if (uiElement)
1131             return [NSArray arrayWithObject:uiElement->wrapper()];
1132     }
1133
1134     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
1135         AccessibilityObject* obj = m_object->titleUIElement();
1136         if (obj)
1137             return obj->wrapper();
1138         return nil;
1139     }
1140     
1141     return nil;
1142 }
1143
1144 - (id)accessibilityFocusedUIElement
1145 {
1146     RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
1147
1148     if (!focusedObj)
1149         return nil;
1150     
1151     return focusedObj->wrapper();
1152 }
1153
1154 - (id)accessibilityHitTest:(NSPoint)point
1155 {
1156     RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
1157     if (axObject)
1158         return NSAccessibilityUnignoredAncestor(axObject->wrapper());
1159     return NSAccessibilityUnignoredAncestor(self);
1160 }
1161
1162 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
1163 {
1164     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1165         return YES;
1166
1167     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1168         return m_object->canSetFocusAttribute();
1169
1170     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1171         return m_object->canSetValueAttribute();
1172
1173     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1174         return m_object->canSetSelectedAttribute();
1175     
1176     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
1177         return m_object->canSetSelectedChildrenAttribute();
1178
1179     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
1180         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
1181         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1182         return m_object->canSetTextRangeAttributes();
1183     
1184     return NO;
1185 }
1186
1187 // accessibilityShouldUseUniqueId is an AppKit method we override so that
1188 // objects will be given a unique ID, and therefore allow AppKit to know when they
1189 // become obsolete (e.g. when the user navigates to a new web page, making this one
1190 // unrendered but not deallocated because it is in the back/forward cache).
1191 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
1192 // appropriate place (e.g. dealloc) to remove these non-retained references from
1193 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
1194 //
1195 // Registering an object is also required for observing notifications. Only registered objects can be observed.
1196 - (BOOL)accessibilityIsIgnored
1197 {
1198     if (m_object->isAttachment())
1199         return [[self attachmentView] accessibilityIsIgnored];
1200     return m_object->accessibilityIsIgnored();
1201 }
1202
1203 - (NSArray* )accessibilityParameterizedAttributeNames
1204 {
1205     if (m_object->isAttachment()) 
1206         return nil;
1207
1208     static NSArray* paramAttrs = nil;
1209     static NSArray* textParamAttrs = nil;
1210     if (paramAttrs == nil) {
1211         paramAttrs = [[NSArray alloc] initWithObjects:
1212                       @"AXUIElementForTextMarker",
1213                       @"AXTextMarkerRangeForUIElement",
1214                       @"AXLineForTextMarker",
1215                       @"AXTextMarkerRangeForLine",
1216                       @"AXStringForTextMarkerRange",
1217                       @"AXTextMarkerForPosition",
1218                       @"AXBoundsForTextMarkerRange",
1219                       @"AXAttributedStringForTextMarkerRange",
1220                       @"AXTextMarkerRangeForUnorderedTextMarkers",
1221                       @"AXNextTextMarkerForTextMarker",
1222                       @"AXPreviousTextMarkerForTextMarker",
1223                       @"AXLeftWordTextMarkerRangeForTextMarker",
1224                       @"AXRightWordTextMarkerRangeForTextMarker",
1225                       @"AXLeftLineTextMarkerRangeForTextMarker",
1226                       @"AXRightLineTextMarkerRangeForTextMarker",
1227                       @"AXSentenceTextMarkerRangeForTextMarker",
1228                       @"AXParagraphTextMarkerRangeForTextMarker",
1229                       @"AXNextWordEndTextMarkerForTextMarker",
1230                       @"AXPreviousWordStartTextMarkerForTextMarker",
1231                       @"AXNextLineEndTextMarkerForTextMarker",
1232                       @"AXPreviousLineStartTextMarkerForTextMarker",
1233                       @"AXNextSentenceEndTextMarkerForTextMarker",
1234                       @"AXPreviousSentenceStartTextMarkerForTextMarker",
1235                       @"AXNextParagraphEndTextMarkerForTextMarker",
1236                       @"AXPreviousParagraphStartTextMarkerForTextMarker",
1237                       @"AXStyleTextMarkerRangeForTextMarker",
1238                       @"AXLengthForTextMarkerRange",
1239                       nil];
1240     }
1241
1242     if (textParamAttrs == nil) {
1243         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
1244         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
1245         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
1246         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
1247         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
1248         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
1249         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
1250         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
1251         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
1252         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
1253         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
1254         [tempArray release];
1255     }
1256     
1257     if (m_object->isPasswordField())
1258         return [NSArray array];
1259     
1260     if (!m_object->isAccessibilityRenderObject())
1261         return paramAttrs;
1262
1263     if (m_object->isTextControl())
1264         return textParamAttrs;
1265         
1266     if (m_object->isMenuRelated())
1267         return nil;
1268
1269     return paramAttrs;
1270 }
1271
1272 - (void)accessibilityPerformPressAction
1273 {
1274     if (m_object->isAttachment())
1275         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
1276     
1277     m_object->press();    
1278 }
1279
1280 - (void)accessibilityPerformShowMenuAction
1281 {
1282     // This needs to be performed in an iteration of the run loop that did not start from an AX call. 
1283     // If it's the same run loop iteration, the menu open notification won't be sent
1284     [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
1285     
1286 }
1287
1288 - (void)accessibilityShowContextMenu
1289 {    
1290     FrameView* frameView = m_object->documentFrameView();
1291     if (!frameView)
1292         return;
1293
1294     // simulate a click in the middle of the object
1295     IntPoint clickPoint = m_object->clickPoint();
1296     NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y());
1297     
1298     NSView* view = frameView->documentView();
1299     NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil];
1300     
1301     // Simulate a context menu event with a right click. This has to be sent through the window, because AppKit is responsible
1302     // for eventually showing the context menu, even though WebCore creates the context menu
1303     NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
1304     [[view window] sendEvent:event];
1305 }
1306
1307 - (void)accessibilityPerformAction:(NSString*)action
1308 {
1309     if ([action isEqualToString:NSAccessibilityPressAction])
1310         [self accessibilityPerformPressAction];
1311     
1312     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
1313         [self accessibilityPerformShowMenuAction];
1314 }
1315
1316 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
1317 {
1318     WebCoreTextMarkerRange* textMarkerRange = nil;
1319     NSNumber*               number = nil;
1320     NSString*               string = nil;
1321     NSRange                 range = {0, 0};
1322     NSArray*                array = nil;
1323     
1324     // decode the parameter
1325     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
1326         textMarkerRange = (WebCoreTextMarkerRange*) value;
1327
1328     else if ([value isKindOfClass:[NSNumber self]])
1329         number = value;
1330
1331     else if ([value isKindOfClass:[NSString self]])
1332         string = value;
1333     
1334     else if ([value isKindOfClass:[NSValue self]])
1335         range = [value rangeValue];
1336     
1337     else if ([value isKindOfClass:[NSArray self]])
1338         array = value;
1339     
1340     // handle the command
1341     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
1342         ASSERT(textMarkerRange);
1343         m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);        
1344     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
1345         ASSERT(number);
1346         m_object->setFocused([number intValue] != 0);
1347     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1348         if (!string)
1349             return;
1350         m_object->setValue(string);
1351     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
1352         if (!number)
1353             return;
1354         m_object->setSelected([number boolValue]);
1355     } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1356         if (!array || m_object->roleValue() != ListBoxRole)
1357             return;
1358         AccessibilityObject::AccessibilityChildrenVector selectedChildren;
1359         convertToVector(array, selectedChildren);
1360         static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
1361     } else if (m_object->isTextControl()) {
1362         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1363             m_object->setSelectedText(string);
1364         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1365             m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
1366         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
1367             m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
1368         }
1369     }
1370 }
1371
1372 static RenderObject* rendererForView(NSView* view)
1373 {
1374     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1375         return 0;
1376
1377     NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
1378     Frame* frame = [frameView _web_frame];
1379     if (!frame)
1380         return 0;
1381
1382     Node* node = frame->document()->ownerElement();
1383     if (!node)
1384         return 0;
1385
1386     return node->renderer();
1387 }
1388
1389 - (id)_accessibilityParentForSubview:(NSView*)subview
1390 {   
1391     RenderObject* renderer = rendererForView(subview);
1392     if (!renderer)
1393         return nil;
1394
1395     AccessibilityObject* obj = renderer->document()->axObjectCache()->get(renderer);
1396     if (obj)
1397         return obj->parentObjectUnignored()->wrapper();
1398     return nil;
1399 }
1400
1401 - (NSString*)accessibilityActionDescription:(NSString*)action
1402 {
1403     // we have no custom actions
1404     return NSAccessibilityActionDescription(action);
1405 }
1406
1407 // The CFAttributedStringType representation of the text associated with this accessibility
1408 // object that is specified by the given range.
1409 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
1410 {
1411     PlainTextRange textRange = PlainTextRange(range.location, range.length);
1412     VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
1413     return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)];
1414 }
1415
1416 // The RTF representation of the text associated with this accessibility object that is
1417 // specified by the given range.
1418 - (NSData*)doAXRTFForRange:(NSRange)range
1419 {
1420     NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
1421     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
1422 }
1423
1424 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
1425 {
1426     WebCoreTextMarker* textMarker = nil;
1427     WebCoreTextMarkerRange* textMarkerRange = nil;
1428     NSNumber* number = nil;
1429     NSArray* array = nil;
1430     RefPtr<AccessibilityObject> uiElement = 0;
1431     NSPoint point = NSZeroPoint;
1432     bool pointSet = false;
1433     NSRange range = {0, 0};
1434     bool rangeSet = false;
1435     
1436     // basic parameter validation
1437     if (!m_object || !attribute || !parameter)
1438         return nil;
1439
1440     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
1441     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
1442     // a parameter of the wrong type.
1443     if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
1444         textMarker = (WebCoreTextMarker*) parameter;
1445
1446     else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
1447         textMarkerRange = (WebCoreTextMarkerRange*) parameter;
1448
1449     else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
1450         uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
1451
1452     else if ([parameter isKindOfClass:[NSNumber self]])
1453         number = parameter;
1454
1455     else if ([parameter isKindOfClass:[NSArray self]])
1456         array = parameter;
1457
1458     else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
1459         pointSet = true;
1460         point = [(NSValue*)parameter pointValue];
1461
1462     } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
1463         rangeSet = true;
1464         range = [(NSValue*)parameter rangeValue];
1465
1466     } else {
1467         // got a parameter of a type we never use
1468         // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally
1469         // while using accesstool (e.g.), forcing you to start over
1470         return nil;
1471     }
1472     
1473     // Convert values to WebCore types
1474     // FIXME: prepping all of these values as WebCore types is unnecessary in many 
1475     // cases. Re-organization of this function or performing the conversion on a 
1476     // need basis are possible improvements. 
1477     VisiblePosition visiblePos;
1478     if (textMarker)
1479         visiblePos = visiblePositionForTextMarker(textMarker);
1480     int intNumber = [number intValue];
1481     VisiblePositionRange visiblePosRange;
1482     if (textMarkerRange)
1483         visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
1484     IntPoint webCorePoint = IntPoint(point);
1485     PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
1486
1487     // dispatch
1488     if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
1489         return m_object->accessibilityObjectForPosition(visiblePos)->wrapper();
1490
1491     if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) {
1492         VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
1493         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1494     }
1495
1496     if ([attribute isEqualToString: @"AXLineForTextMarker"])
1497         return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
1498
1499     if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) {
1500         VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber);
1501         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1502     }
1503
1504     if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
1505         return m_object->stringForVisiblePositionRange(visiblePosRange);
1506
1507     if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
1508         return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil;
1509
1510     if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) {
1511         NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
1512         return [NSValue valueWithRect:rect];
1513     }
1514
1515     if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
1516         return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
1517
1518     if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) {
1519         if ([array count] < 2)
1520             return nil;
1521
1522         WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
1523         WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
1524         if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1] 
1525             || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
1526             return nil;
1527
1528         VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1);
1529         VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2);
1530         VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
1531         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1532     }
1533
1534     if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
1535         return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos));
1536
1537     if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
1538         return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos));
1539
1540     if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) {
1541         VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
1542         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1543     }
1544
1545     if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) {
1546         VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
1547         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1548     }
1549
1550     if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) {
1551         VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
1552         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1553     }
1554
1555     if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) {
1556         VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
1557         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1558     }
1559
1560     if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) {
1561         VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
1562         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1563     }
1564
1565     if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) {
1566         VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
1567         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1568     }
1569
1570     if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
1571         return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos));
1572
1573     if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
1574         return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos));
1575
1576     if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
1577         return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos));
1578
1579     if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
1580         return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos));
1581
1582     if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
1583         return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos));
1584
1585     if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
1586         return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos));
1587
1588     if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
1589         return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos));
1590
1591     if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
1592         return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos));
1593
1594     if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) {
1595         VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
1596         return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1597     }
1598
1599     if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) {
1600         int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
1601         if (length < 0)
1602             return nil;
1603         return [NSNumber numberWithInt:length];
1604     }
1605
1606     if (m_object->isTextControl()) {
1607         if ([attribute isEqualToString: (NSString*)kAXLineForIndexParameterizedAttribute])
1608             return [NSNumber numberWithUnsignedInt: m_object->doAXLineForIndex(intNumber)];
1609
1610         if ([attribute isEqualToString: (NSString*)kAXRangeForLineParameterizedAttribute]) {
1611             PlainTextRange textRange = m_object->doAXRangeForLine(intNumber);
1612             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1613         }
1614
1615         if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
1616             return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
1617
1618         if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
1619             if (!pointSet)
1620                 return nil;
1621             PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
1622             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1623         }
1624
1625         if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
1626             PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber);
1627             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1628         }
1629
1630         if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
1631             if (!rangeSet)
1632                 return nil;
1633             NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
1634             return [NSValue valueWithRect:rect];
1635         }
1636
1637         if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
1638             return rangeSet ? [self doAXRTFForRange:range] : nil;
1639
1640         if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
1641             return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
1642
1643         if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
1644             PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber);
1645             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1646         }
1647     }
1648
1649     return nil;
1650 }
1651
1652 - (BOOL)accessibilityShouldUseUniqueId
1653 {
1654     return m_object->accessibilityShouldUseUniqueId();
1655 }
1656
1657 @end