2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #import "AccessibilityObjectWrapper.h"
32 #import "AXObjectCache.h"
33 #import "AccessibilityListBox.h"
34 #import "AccessibilityRenderObject.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"
55 using namespace WebCore;
56 using namespace HTMLNames;
58 @implementation AccessibilityObjectWrapper
60 #ifndef BUILDING_ON_TIGER
63 WebCoreObjCFinalizeOnMainThread(self);
67 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
75 - (void)unregisterUniqueIdForUIElement
77 [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
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];
90 - (AccessibilityObject*)accessibilityObject
95 - (NSView*)attachmentView
97 ASSERT(m_object->isAttachment());
98 Widget* widget = m_object->widgetForAttachmentView();
101 return widget->getView();
104 static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos)
106 if (visiblePos.isNull())
109 Position deepPos = visiblePos.deepEquivalent();
110 Node* domNode = deepPos.node();
115 if (domNode->isHTMLElement())
116 if (static_cast<HTMLElement*>(domNode)->isPasswordField())
119 // locate the renderer, which must exist for a visible dom node
120 RenderObject* renderer = domNode->renderer();
123 // find or create an accessibility object for this renderer
124 AXObjectCache* cache = renderer->document()->axObjectCache();
125 RefPtr<AccessibilityObject> obj = cache->get(renderer);
127 // create a text marker, adding an ID for the AccessibilityObject if needed
128 TextMarkerData textMarkerData;
129 textMarkerData.axID = obj.get()->axObjectID();
130 textMarkerData.node = domNode;
131 textMarkerData.offset = deepPos.offset();
132 textMarkerData.affinity = visiblePos.affinity();
133 return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)];
136 static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker)
138 TextMarkerData textMarkerData;
140 if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)])
141 return VisiblePosition();
143 VisiblePosition visiblePos = VisiblePosition(textMarkerData.node, textMarkerData.offset, textMarkerData.affinity);
144 Position deepPos = visiblePos.deepEquivalent();
145 AXObjectCache* cache = deepPos.node()->renderer()->document()->axObjectCache();
146 if (!cache->isIDinUse(textMarkerData.axID))
147 return VisiblePosition();
149 if (deepPos.node() != textMarkerData.node || deepPos.offset() != textMarkerData.offset)
150 return VisiblePosition();
155 static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
157 return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]);
160 static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
162 return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]);
165 static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2)
167 return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
170 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
175 dict = [NSDictionary dictionaryWithObjectsAndKeys:
176 [font fontName] , NSAccessibilityFontNameKey,
177 [font familyName] , NSAccessibilityFontFamilyKey,
178 [font displayName] , NSAccessibilityVisibleNameKey,
179 [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
182 [attrString addAttribute:attribute value:dict range:range];
184 [attrString removeAttribute:attribute range:range];
188 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
190 // get color information assuming NSDeviceRGBColorSpace
191 NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
193 rgbColor = [NSColor blackColor];
194 CGFloat components[4];
195 [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
197 // create a new CGColorRef to return
198 CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
199 CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
200 CGColorSpaceRelease(cgColorSpace);
201 CFMakeCollectable(cgColor);
203 // check for match with existing color
204 if (existingColor && CGColorEqualToColor(cgColor, existingColor))
210 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
213 CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
214 CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
216 [attrString addAttribute:attribute value:(id)cgColor range:range];
217 CGColorRelease(cgColor);
220 [attrString removeAttribute:attribute range:range];
223 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
226 [attrString addAttribute:attribute value:number range:range];
228 [attrString removeAttribute:attribute range:range];
231 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
233 RenderStyle* style = renderer->style();
235 // set basic font info
236 AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
239 AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range);
240 AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range);
242 // set super/sub scripting
243 EVerticalAlign alignment = style->verticalAlign();
244 if (alignment == SUB)
245 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
246 else if (alignment == SUPER)
247 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
249 [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
252 if (style->textShadow())
253 AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
255 [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
257 // set underline and strikethrough
258 int decor = style->textDecorationsInEffect();
259 if ((decor & UNDERLINE) == 0) {
260 [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
261 [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
264 if ((decor & LINE_THROUGH) == 0) {
265 [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
266 [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
269 if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
270 // find colors using quirk mode approach (strict mode would use current
271 // color for all but the root line box, which would use getTextDecorationColors)
272 Color underline, overline, linethrough;
273 renderer->getTextDecorationColors(decor, underline, overline, linethrough);
275 if ((decor & UNDERLINE) != 0) {
276 AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
277 AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
280 if ((decor & LINE_THROUGH) != 0) {
281 AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
282 AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
287 static int blockquoteLevel(RenderObject* renderer)
290 for (Node* node = renderer->element(); node; node = node->parent()) {
291 if (node->hasTagName(blockquoteTag))
298 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
300 int quoteLevel = blockquoteLevel(renderer);
303 [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range];
305 [attrString removeAttribute:@"AXBlockQuoteLevel" range:range];
308 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range)
310 Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node);
311 Vector<DocumentMarker>::iterator markerIt = markers.begin();
313 unsigned endOffset = (unsigned)offset + range.length;
314 for ( ; markerIt != markers.end(); markerIt++) {
315 DocumentMarker marker = *markerIt;
317 if (marker.type != DocumentMarker::Spelling)
320 if (marker.endOffset <= (unsigned)offset)
323 if (marker.startOffset > endOffset)
326 // add misspelling attribute for the intersection of the marker and the range
327 int rStart = range.location + (marker.startOffset - offset);
328 int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset;
329 NSRange spellRange = NSMakeRange(rStart, rLength);
330 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
332 if (marker.endOffset > endOffset + 1)
337 static void AXAttributeStringSetHeadingLevel(AccessibilityObject* object, NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
339 int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element());
341 if (parentHeadingLevel)
342 [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
344 [attrString removeAttribute:@"AXHeadingLevel" range:range];
347 static AccessibilityObject* AXLinkElementForNode(Node* node)
349 RenderObject* obj = node->renderer();
353 RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->get(obj);
354 HTMLAnchorElement* anchor = axObj->anchorElement();
358 RenderObject* anchorRenderer = anchor->renderer();
362 return anchorRenderer->document()->axObjectCache()->get(anchorRenderer);
365 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
367 if (object && object->isAccessibilityRenderObject()) {
368 // make a serialiazable AX object
370 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
374 Document* doc = renderer->document();
378 AXObjectCache* cache = doc->axObjectCache();
382 AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()];
384 [attrString addAttribute:attribute value:(id)axElement range:range];
385 CFRelease(axElement);
388 [attrString removeAttribute:attribute range:range];
391 static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length)
393 // skip invisible text
394 if (!node->renderer())
397 // easier to calculate the range before appending the string
398 NSRange attrStringRange = NSMakeRange([attrString length], length);
400 // append the string from this node
401 [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
403 // add new attributes and remove irrelevant inherited ones
404 // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
405 // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means
406 // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
408 // remove inherited attachment from prior AXAttributedStringAppendReplaced
409 [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
411 // set new attributes
412 AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
413 AXAttributeStringSetHeadingLevel(object, attrString, node->renderer(), attrStringRange);
414 AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
415 AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange);
417 // do spelling last because it tends to break up the range
418 AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);
421 static NSString* nsStringForReplacedNode(Node* replacedNode)
423 // we should always be given a rendered node and a replaced node, but be safe
424 // replaced nodes are either attachments (widgets) or images
425 if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
426 ASSERT_NOT_REACHED();
430 // create an AX object, but skip it if it is not supposed to be seen
431 RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
432 if (obj->accessibilityIsIgnored())
435 // use the attachmentCharacter to represent the replaced node
436 const UniChar attachmentChar = NSAttachmentCharacter;
437 return [NSString stringWithCharacters:&attachmentChar length:1];
440 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
442 // extract the start and end VisiblePosition
443 VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange);
444 if (startVisiblePosition.isNull())
447 VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange);
448 if (endVisiblePosition.isNull())
451 // iterate over the range to build the AX attributed string
452 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
453 TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
454 while (!it.atEnd()) {
455 // locate the node and starting offset for this range
457 Node* node = it.range()->startContainer(exception);
458 ASSERT(node == it.range()->endContainer(exception));
459 int offset = it.range()->startOffset(exception);
461 // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
462 if (it.length() != 0) {
463 AXAttributedStringAppendText(m_object, attrString, node, offset, it.characters(), it.length());
465 Node* replacedNode = node->childNode(offset);
466 NSString *attachmentString = nsStringForReplacedNode(replacedNode);
467 if (attachmentString) {
468 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
470 // append the placeholder string
471 [[attrString mutableString] appendString:attachmentString];
473 // remove all inherited attributes
474 [attrString setAttributes:nil range:attrStringRange];
476 // add the attachment attribute
477 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
478 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
484 return [attrString autorelease];
487 static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition)
489 WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition);
490 WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(endPosition);
491 return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
494 - (NSArray*)accessibilityActionNames
496 static NSArray* actions = nil;
498 if (actions == nil) {
499 if (m_object->actionElement())
500 actions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, nil];
501 else if (m_object->isAttachment())
502 actions = [[[self attachmentView] accessibilityActionNames] retain];
508 - (NSArray*)accessibilityAttributeNames
510 if (m_object->isAttachment())
511 return [[self attachmentView] accessibilityAttributeNames];
513 static NSArray* attributes = nil;
514 static NSArray* anchorAttrs = nil;
515 static NSArray* webAreaAttrs = nil;
516 static NSArray* textAttrs = nil;
517 static NSArray* listBoxAttrs = nil;
518 NSMutableArray* tempArray;
519 if (attributes == nil) {
520 attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
521 NSAccessibilitySubroleAttribute,
522 NSAccessibilityRoleDescriptionAttribute,
523 NSAccessibilityChildrenAttribute,
524 NSAccessibilityHelpAttribute,
525 NSAccessibilityParentAttribute,
526 NSAccessibilityPositionAttribute,
527 NSAccessibilitySizeAttribute,
528 NSAccessibilityTitleAttribute,
529 NSAccessibilityDescriptionAttribute,
530 NSAccessibilityValueAttribute,
531 NSAccessibilityFocusedAttribute,
532 NSAccessibilityEnabledAttribute,
533 NSAccessibilityWindowAttribute,
534 @"AXSelectedTextMarkerRange",
535 @"AXStartTextMarker",
538 NSAccessibilityLinkedUIElementsAttribute,
539 NSAccessibilitySelectedAttribute,
542 if (anchorAttrs == nil) {
543 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
544 [tempArray addObject:NSAccessibilityURLAttribute];
545 anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
548 if (webAreaAttrs == nil) {
549 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
550 [tempArray addObject:@"AXLinkUIElements"];
551 [tempArray addObject:@"AXLoaded"];
552 [tempArray addObject:@"AXLayoutCount"];
553 [tempArray addObject:NSAccessibilityURLAttribute];
554 webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
557 if (textAttrs == nil) {
558 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
559 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
560 [tempArray addObject:NSAccessibilitySelectedTextAttribute];
561 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
562 [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
563 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
564 textAttrs = [[NSArray alloc] initWithArray:tempArray];
567 if (listBoxAttrs == nil) {
568 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
569 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
570 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
571 [tempArray addObject:NSAccessibilityOrientationAttribute];
572 listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
576 if (m_object->isPasswordField())
579 if (m_object->isWebArea())
582 if (m_object->isTextControl())
585 if (m_object->isAnchor() || m_object->isImage())
588 if (m_object->isListBox())
594 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
596 return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange));
599 - (NSArray*)renderWidgetChildren
601 Widget* widget = m_object->widget();
604 return [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
607 static NSMutableArray* convertToNSArray(const Vector<RefPtr<AccessibilityObject> >& vector)
609 unsigned length = vector.size();
610 NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
611 for (unsigned i = 0; i < length; ++i)
612 [array addObject:vector[i]->wrapper()];
616 - (WebCoreTextMarkerRange*)textMarkerRangeForSelection
618 Selection selection = m_object->selection();
619 if (selection.isNone())
621 return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd());
626 IntRect rect = m_object->elementRect();
628 // The Cocoa accessibility API wants the lower-left corner.
629 NSPoint point = NSMakePoint(rect.x(), rect.bottom());
630 FrameView* frameView = m_object->documentFrameView();
632 NSView* view = frameView->documentView();
633 point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
636 return [NSValue valueWithPoint: point];
639 typedef HashMap<int, NSString*> AccessibilityRoleMap;
641 static const AccessibilityRoleMap& createAccessibilityRoleMap()
644 AccessibilityRole value;
648 static const RoleEntry roles[] = {
649 { UnknownRole, NSAccessibilityUnknownRole },
650 { ButtonRole, NSAccessibilityButtonRole },
651 { RadioButtonRole, NSAccessibilityRadioButtonRole },
652 { CheckBoxRole, NSAccessibilityCheckBoxRole },
653 { SliderRole, NSAccessibilitySliderRole },
654 { TabGroupRole, NSAccessibilityTabGroupRole },
655 { TextFieldRole, NSAccessibilityTextFieldRole },
656 { StaticTextRole, NSAccessibilityStaticTextRole },
657 { TextAreaRole, NSAccessibilityTextAreaRole },
658 { ScrollAreaRole, NSAccessibilityScrollAreaRole },
659 { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
660 { MenuButtonRole, NSAccessibilityMenuButtonRole },
661 { TableRole, NSAccessibilityTableRole },
662 { ApplicationRole, NSAccessibilityApplicationRole },
663 { GroupRole, NSAccessibilityGroupRole },
664 { RadioGroupRole, NSAccessibilityRadioGroupRole },
665 { ListRole, NSAccessibilityListRole },
666 { ScrollBarRole, NSAccessibilityScrollBarRole },
667 { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
668 { ImageRole, NSAccessibilityImageRole },
669 { MenuBarRole, NSAccessibilityMenuBarRole },
670 { MenuRole, NSAccessibilityMenuRole },
671 { MenuItemRole, NSAccessibilityMenuItemRole },
672 { ColumnRole, NSAccessibilityColumnRole },
673 { RowRole, NSAccessibilityRowRole },
674 { ToolbarRole, NSAccessibilityToolbarRole },
675 { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
676 { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
677 { WindowRole, NSAccessibilityWindowRole },
678 { DrawerRole, NSAccessibilityDrawerRole },
679 { SystemWideRole, NSAccessibilitySystemWideRole },
680 { OutlineRole, NSAccessibilityOutlineRole },
681 { IncrementorRole, NSAccessibilityIncrementorRole },
682 { BrowserRole, NSAccessibilityBrowserRole },
683 { ComboBoxRole, NSAccessibilityComboBoxRole },
684 { SplitGroupRole, NSAccessibilitySplitGroupRole },
685 { SplitterRole, NSAccessibilitySplitterRole },
686 { ColorWellRole, NSAccessibilityColorWellRole },
687 { GrowAreaRole, NSAccessibilityGrowAreaRole },
688 { SheetRole, NSAccessibilitySheetRole },
689 { HelpTagRole, NSAccessibilityHelpTagRole },
690 { MatteRole, NSAccessibilityMatteRole },
691 { RulerRole, NSAccessibilityRulerRole },
692 { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
693 { LinkRole, NSAccessibilityLinkRole },
694 #ifndef BUILDING_ON_TIGER
695 { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
696 { GridRole, NSAccessibilityGridRole },
698 { WebCoreLinkRole, @"AXLink" }, // why isn't this just NSAccessibilityLinkRole ?
699 { ImageMapRole, @"AXImageMap" },
700 { ListMarkerRole, @"AXListMarker" },
701 { WebAreaRole, @"AXWebArea" },
702 { HeadingRole, @"AXHeading" },
703 { ListBoxRole, NSAccessibilityListRole },
704 { ListBoxOptionRole, NSAccessibilityStaticTextRole }
706 AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
708 const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
709 for (unsigned i = 0; i < numRoles; ++i)
710 roleMap.set(roles[i].value, roles[i].string);
714 static NSString* roleValueToNSString(AccessibilityRole value)
717 static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
718 return roleMap.get(value);
723 if (m_object->isAttachment())
724 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
725 NSString* string = roleValueToNSString(m_object->roleValue());
728 return NSAccessibilityUnknownRole;
733 if (m_object->isPasswordField())
734 return NSAccessibilitySecureTextFieldSubrole;
736 if (m_object->isAttachment()) {
737 NSView* attachView = [self attachmentView];
738 if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
739 return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
746 - (NSString*)roleDescription
751 // attachments have the AXImage role, but a different subrole
752 if (m_object->isAttachment())
753 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
755 // FIXME 3447564: It would be better to call some AppKit API to get these strings
756 // (which would be the best way to localize them)
758 NSString* axRole = [self role];
759 if ([axRole isEqualToString:NSAccessibilityButtonRole])
760 return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, [self subrole]);
762 if ([axRole isEqualToString:NSAccessibilityPopUpButtonRole])
763 return NSAccessibilityRoleDescription(NSAccessibilityPopUpButtonRole, [self subrole]);
765 if ([axRole isEqualToString:NSAccessibilityStaticTextRole])
766 return NSAccessibilityRoleDescription(NSAccessibilityStaticTextRole, [self subrole]);
768 if ([axRole isEqualToString:NSAccessibilityImageRole])
769 return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]);
771 if ([axRole isEqualToString:NSAccessibilityGroupRole])
772 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
774 if ([axRole isEqualToString:NSAccessibilityCheckBoxRole])
775 return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]);
777 if ([axRole isEqualToString:NSAccessibilityRadioButtonRole])
778 return NSAccessibilityRoleDescription(NSAccessibilityRadioButtonRole, [self subrole]);
780 if ([axRole isEqualToString:NSAccessibilityTextFieldRole])
781 return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, [self subrole]);
783 if ([axRole isEqualToString:NSAccessibilityTextAreaRole])
784 return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, [self subrole]);
786 if ([axRole isEqualToString:NSAccessibilityListRole])
787 return NSAccessibilityRoleDescription(NSAccessibilityListRole, [self subrole]);
789 if ([axRole isEqualToString:@"AXWebArea"])
790 return AXWebAreaText();
792 if ([axRole isEqualToString:@"AXLink"])
795 if ([axRole isEqualToString:@"AXListMarker"])
796 return AXListMarkerText();
798 if ([axRole isEqualToString:@"AXImageMap"])
799 return AXImageMapText();
801 if ([axRole isEqualToString:@"AXHeading"])
802 return AXHeadingText();
804 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
807 // FIXME: split up this function in a better way.
808 // suggestions: Use a hash table that maps attribute names to function calls,
809 // or maybe pointers to member functions
810 - (id)accessibilityAttributeValue:(NSString*)attributeName
815 if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
818 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
819 return [self subrole];
821 if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
822 return [self roleDescription];
824 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
825 if (m_object->isAccessibilityRenderObject()) {
826 FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
828 return fv->getView();
831 return m_object->parentObjectUnignored()->wrapper();
834 if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
835 if (m_object->children().isEmpty()) {
836 NSArray* children = [self renderWidgetChildren];
840 return convertToNSArray(m_object->children());
843 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute] && m_object->isListBox())
844 return convertToNSArray(static_cast<AccessibilityListBox*>(m_object)->selectedChildren());
846 if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute] && m_object->isListBox())
847 return convertToNSArray(static_cast<AccessibilityListBox*>(m_object)->visibleChildren());
850 if (m_object->isWebArea()) {
851 if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
852 Vector<RefPtr<AccessibilityObject> > links;
853 m_object->getDocumentLinks(links);
854 return convertToNSArray(links);
856 if ([attributeName isEqualToString: @"AXLoaded"])
857 return [NSNumber numberWithBool: m_object->isLoaded()];
858 if ([attributeName isEqualToString: @"AXLayoutCount"])
859 return [NSNumber numberWithInt: m_object->layoutCount()];
862 if (m_object->isTextControl()) {
863 if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
864 int length = m_object->textLength();
867 return [NSNumber numberWithUnsignedInt:length];
869 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
870 String selectedText = m_object->selectedText();
871 if (selectedText.isNull())
873 return (NSString*)selectedText;
875 if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
876 PlainTextRange textRange = m_object->selectedTextRange();
877 if (textRange.isNull())
879 return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
881 // TODO: Get actual visible range. <rdar://problem/4712101>
882 if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
883 return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
884 if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
885 if (m_object->isPasswordField() || m_object->selectionStart() != m_object->selectionEnd())
887 return [NSNumber numberWithInt:m_object->doAXLineForTextMarker(m_object->textMarkerForIndex(m_object->selectionStart(), true))];
891 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
892 KURL url = m_object->url();
898 if ([attributeName isEqualToString: @"AXVisited"])
899 return [NSNumber numberWithBool: m_object->isVisited()];
901 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
902 if (m_object->isAttachment()) {
903 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
904 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
906 return m_object->title();
909 if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
910 if (m_object->isAttachment()) {
911 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
912 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
914 return m_object->accessibilityDescription();
917 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
918 if (m_object->isAttachment()) {
919 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
920 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
922 if (m_object->hasIntValue())
923 return [NSNumber numberWithInt:m_object->intValue()];
924 return m_object->stringValue();
927 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
928 return m_object->helpText();
930 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
931 return [NSNumber numberWithBool: m_object->isFocused()];
933 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
934 return [NSNumber numberWithBool: m_object->isEnabled()];
936 if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
937 IntSize s = m_object->size();
938 return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
941 if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
942 return [self position];
944 if ([attributeName isEqualToString: NSAccessibilityWindowAttribute]) {
945 FrameView* fv = m_object->documentFrameView();
947 return [fv->getView() window];
951 if (m_object->isListBox() && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
952 return NSAccessibilityVerticalOrientationValue;
954 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
955 return [self textMarkerRangeForSelection];
957 if (m_object->isAccessibilityRenderObject()) {
958 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
962 if ([attributeName isEqualToString: @"AXStartTextMarker"])
963 return textMarkerForVisiblePosition(startOfDocument(renderer->document()));
964 if ([attributeName isEqualToString: @"AXEndTextMarker"])
965 return textMarkerForVisiblePosition(endOfDocument(renderer->document()));
968 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
969 AccessibilityObject* obj = m_object->linkedUIElement();
971 return (id) obj->wrapper();
975 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
976 return [NSNumber numberWithBool:m_object->isSelected()];
981 - (id)accessibilityFocusedUIElement
983 RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
988 return focusedObj->wrapper();
991 - (id)accessibilityHitTest:(NSPoint)point
993 RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
995 return NSAccessibilityUnignoredAncestor(axObject->wrapper());
996 return NSAccessibilityUnignoredAncestor(self);
999 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
1001 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1004 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1005 return m_object->canSetFocusAttribute();
1007 if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1008 return m_object->canSetValueAttribute();
1010 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
1011 [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
1012 [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1013 return m_object->canSetTextRangeAttributes();
1018 // accessibilityShouldUseUniqueId is an AppKit method we override so that
1019 // objects will be given a unique ID, and therefore allow AppKit to know when they
1020 // become obsolete (e.g. when the user navigates to a new web page, making this one
1021 // unrendered but not deallocated because it is in the back/forward cache).
1022 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
1023 // appropriate place (e.g. dealloc) to remove these non-retained references from
1024 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
1026 // Registering an object is also required for observing notifications. Only registered objects can be observed.
1027 - (BOOL)accessibilityIsIgnored
1029 if (m_object->isAttachment())
1030 return [[self attachmentView] accessibilityIsIgnored];
1031 return m_object->accessibilityIsIgnored();
1034 - (NSArray* )accessibilityParameterizedAttributeNames
1036 if (m_object->isAttachment())
1039 static NSArray* paramAttrs = nil;
1040 static NSArray* textParamAttrs = nil;
1041 if (paramAttrs == nil) {
1042 paramAttrs = [[NSArray alloc] initWithObjects:
1043 @"AXUIElementForTextMarker",
1044 @"AXTextMarkerRangeForUIElement",
1045 @"AXLineForTextMarker",
1046 @"AXTextMarkerRangeForLine",
1047 @"AXStringForTextMarkerRange",
1048 @"AXTextMarkerForPosition",
1049 @"AXBoundsForTextMarkerRange",
1050 @"AXAttributedStringForTextMarkerRange",
1051 @"AXTextMarkerRangeForUnorderedTextMarkers",
1052 @"AXNextTextMarkerForTextMarker",
1053 @"AXPreviousTextMarkerForTextMarker",
1054 @"AXLeftWordTextMarkerRangeForTextMarker",
1055 @"AXRightWordTextMarkerRangeForTextMarker",
1056 @"AXLeftLineTextMarkerRangeForTextMarker",
1057 @"AXRightLineTextMarkerRangeForTextMarker",
1058 @"AXSentenceTextMarkerRangeForTextMarker",
1059 @"AXParagraphTextMarkerRangeForTextMarker",
1060 @"AXNextWordEndTextMarkerForTextMarker",
1061 @"AXPreviousWordStartTextMarkerForTextMarker",
1062 @"AXNextLineEndTextMarkerForTextMarker",
1063 @"AXPreviousLineStartTextMarkerForTextMarker",
1064 @"AXNextSentenceEndTextMarkerForTextMarker",
1065 @"AXPreviousSentenceStartTextMarkerForTextMarker",
1066 @"AXNextParagraphEndTextMarkerForTextMarker",
1067 @"AXPreviousParagraphStartTextMarkerForTextMarker",
1068 @"AXStyleTextMarkerRangeForTextMarker",
1069 @"AXLengthForTextMarkerRange",
1073 if (textParamAttrs == nil) {
1074 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
1075 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
1076 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
1077 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
1078 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
1079 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
1080 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
1081 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
1082 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
1083 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
1084 textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
1085 [tempArray release];
1088 if (m_object->isPasswordField())
1089 return [NSArray array];
1091 if (!m_object->isAccessibilityRenderObject())
1094 if (m_object->isTextControl())
1095 return textParamAttrs;
1100 - (void)accessibilityPerformAction:(NSString*)action
1102 if (![action isEqualToString:NSAccessibilityPressAction])
1105 if (m_object->isAttachment())
1106 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
1111 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
1113 WebCoreTextMarkerRange* textMarkerRange = nil;
1114 NSNumber* number = nil;
1115 NSString* string = nil;
1116 NSRange range = {0, 0};
1118 // decode the parameter
1119 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
1120 textMarkerRange = (WebCoreTextMarkerRange*) value;
1122 else if ([value isKindOfClass:[NSNumber self]])
1125 else if ([value isKindOfClass:[NSString self]])
1128 else if ([value isKindOfClass:[NSValue self]])
1129 range = [value rangeValue];
1131 // handle the command
1132 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
1133 ASSERT(textMarkerRange);
1134 m_object->doSetAXSelectedTextMarkerRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
1135 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
1137 m_object->setFocused([number intValue] != 0);
1138 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1141 m_object->setValue(string);
1142 } else if (m_object->isTextControl()) {
1143 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1144 m_object->setSelectedText(string);
1145 } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1146 m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
1147 } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
1148 m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
1153 static RenderObject* rendererForView(NSView* view)
1155 if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1158 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
1159 Frame* frame = [frameView _web_frame];
1163 Node* node = frame->document()->ownerElement();
1167 return node->renderer();
1170 - (id)_accessibilityParentForSubview:(NSView*)subview
1172 RenderObject* renderer = rendererForView(subview);
1176 AccessibilityObject* obj = renderer->document()->axObjectCache()->get(renderer);
1178 return obj->parentObjectUnignored()->wrapper();
1182 - (NSString*)accessibilityActionDescription:(NSString*)action
1184 // we have no custom actions
1185 return NSAccessibilityActionDescription(action);
1188 // The CFAttributedStringType representation of the text associated with this accessibility
1189 // object that is specified by the given range.
1190 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
1192 PlainTextRange textRange = PlainTextRange(range.location, range.length);
1193 VisiblePositionRange visiblePosRange = m_object->textMarkerRangeForRange(textRange);
1194 return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)];
1197 // The RTF representation of the text associated with this accessibility object that is
1198 // specified by the given range.
1199 - (NSData*)doAXRTFForRange:(NSRange)range
1201 NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
1202 return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
1205 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
1207 WebCoreTextMarker* textMarker = nil;
1208 WebCoreTextMarkerRange* textMarkerRange = nil;
1209 NSNumber* number = nil;
1210 NSArray* array = nil;
1211 RefPtr<AccessibilityObject> uiElement = 0;
1212 NSPoint point = NSZeroPoint;
1213 bool pointSet = false;
1214 NSRange range = {0, 0};
1215 bool rangeSet = false;
1217 // basic parameter validation
1218 if (!m_object || !attribute || !parameter)
1221 // common parameter type check/casting. Nil checks in handlers catch wrong type case.
1222 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
1223 // a parameter of the wrong type.
1224 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
1225 textMarker = (WebCoreTextMarker*) parameter;
1227 else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
1228 textMarkerRange = (WebCoreTextMarkerRange*) parameter;
1230 else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
1231 uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
1233 else if ([parameter isKindOfClass:[NSNumber self]])
1236 else if ([parameter isKindOfClass:[NSArray self]])
1239 else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
1241 point = [(NSValue*)parameter pointValue];
1243 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
1245 range = [(NSValue*)parameter rangeValue];
1248 // got a parameter of a type we never use
1249 // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally
1250 // while using accesstool (e.g.), forcing you to start over
1254 // Convert values to WebCore types
1255 // FIXME: prepping all of these values as WebCore types is unnecessary in many
1256 // cases. Re-organization of this function or performing the conversion on a
1257 // need basis are possible improvements.
1258 VisiblePosition visiblePos;
1260 visiblePos = visiblePositionForTextMarker(textMarker);
1261 int intNumber = [number intValue];
1262 VisiblePositionRange visiblePosRange;
1263 if (textMarkerRange)
1264 visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
1265 IntPoint webCorePoint = IntPoint(point);
1266 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
1269 if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
1270 return m_object->doAXUIElementForTextMarker(visiblePos)->wrapper();
1272 if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) {
1273 VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
1274 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1277 if ([attribute isEqualToString: @"AXLineForTextMarker"])
1278 return [NSNumber numberWithUnsignedInt:m_object->doAXLineForTextMarker(visiblePos)];
1280 if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) {
1281 VisiblePositionRange vpRange = m_object->doAXTextMarkerRangeForLine(intNumber);
1282 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1285 if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
1286 return m_object->doAXStringForTextMarkerRange(visiblePosRange);
1288 if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
1289 return pointSet ? textMarkerForVisiblePosition(m_object->doAXTextMarkerForPosition(webCorePoint)) : nil;
1291 if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) {
1292 NSRect rect = m_object->doAXBoundsForTextMarkerRange(visiblePosRange);
1293 return [NSValue valueWithRect:rect];
1296 if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
1297 return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
1299 if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) {
1300 if ([array count] < 2)
1303 WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
1304 WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
1305 if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1]
1306 || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
1309 VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1);
1310 VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2);
1311 VisiblePositionRange vpRange = m_object->doAXTextMarkerRangeForUnorderedTextMarkers(visiblePos1, visiblePos2);
1312 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1315 if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
1316 return textMarkerForVisiblePosition(m_object->doAXNextTextMarkerForTextMarker(visiblePos));
1318 if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
1319 return textMarkerForVisiblePosition(m_object->doAXPreviousTextMarkerForTextMarker(visiblePos));
1321 if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) {
1322 VisiblePositionRange vpRange = m_object->doAXLeftWordTextMarkerRangeForTextMarker(visiblePos);
1323 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1326 if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) {
1327 VisiblePositionRange vpRange = m_object->doAXRightWordTextMarkerRangeForTextMarker(visiblePos);
1328 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1331 if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) {
1332 VisiblePositionRange vpRange = m_object->doAXLeftLineTextMarkerRangeForTextMarker(visiblePos);
1333 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1336 if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) {
1337 VisiblePositionRange vpRange = m_object->doAXRightLineTextMarkerRangeForTextMarker(visiblePos);
1338 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1341 if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) {
1342 VisiblePositionRange vpRange = m_object->doAXSentenceTextMarkerRangeForTextMarker(visiblePos);
1343 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1346 if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) {
1347 VisiblePositionRange vpRange = m_object->doAXParagraphTextMarkerRangeForTextMarker(visiblePos);
1348 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1351 if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
1352 return textMarkerForVisiblePosition(m_object->doAXNextWordEndTextMarkerForTextMarker(visiblePos));
1354 if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
1355 return textMarkerForVisiblePosition(m_object->doAXPreviousWordStartTextMarkerForTextMarker(visiblePos));
1357 if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
1358 return textMarkerForVisiblePosition(m_object->doAXNextLineEndTextMarkerForTextMarker(visiblePos));
1360 if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
1361 return textMarkerForVisiblePosition(m_object->doAXPreviousLineStartTextMarkerForTextMarker(visiblePos));
1363 if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
1364 return textMarkerForVisiblePosition(m_object->doAXNextSentenceEndTextMarkerForTextMarker(visiblePos));
1366 if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
1367 return textMarkerForVisiblePosition(m_object->doAXPreviousSentenceStartTextMarkerForTextMarker(visiblePos));
1369 if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
1370 return textMarkerForVisiblePosition(m_object->doAXNextParagraphEndTextMarkerForTextMarker(visiblePos));
1372 if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
1373 return textMarkerForVisiblePosition(m_object->doAXPreviousParagraphStartTextMarkerForTextMarker(visiblePos));
1375 if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) {
1376 VisiblePositionRange vpRange = m_object->doAXStyleTextMarkerRangeForTextMarker(visiblePos);
1377 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
1380 if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) {
1381 int length = m_object->doAXLengthForTextMarkerRange(visiblePosRange);
1384 return [NSNumber numberWithInt:length];
1387 if (m_object->isTextControl()) {
1388 if ([attribute isEqualToString: (NSString*)kAXLineForIndexParameterizedAttribute])
1389 return [NSNumber numberWithUnsignedInt: m_object->doAXLineForIndex(intNumber)];
1391 if ([attribute isEqualToString: (NSString*)kAXRangeForLineParameterizedAttribute]) {
1392 PlainTextRange textRange = m_object->doAXRangeForLine(intNumber);
1393 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1396 if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
1397 return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
1399 if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
1402 PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
1403 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1406 if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
1407 PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber);
1408 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1411 if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
1414 NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
1415 return [NSValue valueWithRect:rect];
1418 if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
1419 return rangeSet ? [self doAXRTFForRange:range] : nil;
1421 if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
1422 return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
1424 if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
1425 PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber);
1426 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
1433 - (BOOL)accessibilityShouldUseUniqueId
1435 return m_object->accessibilityShouldUseUniqueId();