2 * Copyright (C) 2008, 2009 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 #if HAVE(ACCESSIBILITY)
34 #import "AXObjectCache.h"
35 #import "AccessibilityARIAGridRow.h"
36 #import "AccessibilityListBox.h"
37 #import "AccessibilityList.h"
38 #import "AccessibilityRenderObject.h"
39 #import "AccessibilityTable.h"
40 #import "AccessibilityTableCell.h"
41 #import "AccessibilityTableRow.h"
42 #import "AccessibilityTableColumn.h"
44 #import "EditorClient.h"
46 #import "HTMLAnchorElement.h"
47 #import "HTMLAreaElement.h"
48 #import "HTMLFrameOwnerElement.h"
49 #import "HTMLImageElement.h"
50 #import "HTMLInputElement.h"
51 #import "HTMLTextAreaElement.h"
52 #import "LocalizedStrings.h"
53 #import "RenderTextControl.h"
54 #import "RenderView.h"
55 #import "RenderWidget.h"
56 #import "SelectionController.h"
57 #import "SimpleFontData.h"
58 #import "TextIterator.h"
59 #import "WebCoreFrameView.h"
60 #import "WebCoreObjCExtras.h"
61 #import "WebCoreViewFactory.h"
62 #import "htmlediting.h"
63 #import "visible_units.h"
65 using namespace WebCore;
66 using namespace HTMLNames;
70 #ifndef NSAccessibilitySelectedCellsAttribute
71 #define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
74 #ifndef NSAccessibilityVisibleCellsAttribute
75 #define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
78 #ifndef NSAccessibilityRowHeaderUIElementsAttribute
79 #define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements"
82 #ifndef NSAccessibilityRowIndexRangeAttribute
83 #define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
86 #ifndef NSAccessibilityColumnIndexRangeAttribute
87 #define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
90 #ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
91 #define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
94 #ifndef NSAccessibilityCellRole
95 #define NSAccessibilityCellRole @"AXCell"
99 #ifndef NSAccessibilityContentListSubrole
100 #define NSAccessibilityContentListSubrole @"AXContentList"
103 #ifndef NSAccessibilityDefinitionListSubrole
104 #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
108 #ifndef NSAccessibilityBlockQuoteLevelAttribute
109 #define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
112 #ifndef NSAccessibilityAccessKeyAttribute
113 #define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
116 #ifndef NSAccessibilityLanguageAttribute
117 #define NSAccessibilityLanguageAttribute @"AXLanguage"
120 #ifndef NSAccessibilityRequiredAttribute
121 #define NSAccessibilityRequiredAttribute @"AXRequired"
124 #ifndef NSAccessibilityOwnsAttribute
125 #define NSAccessibilityOwnsAttribute @"AXOwns"
128 #ifndef NSAccessibilityGrabbedAttribute
129 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
132 #ifndef NSAccessibilityDropEffectsAttribute
133 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
136 #ifndef NSAccessibilityARIALiveAttribute
137 #define NSAccessibilityARIALiveAttribute @"AXARIALive"
140 #ifndef NSAccessibilityARIAAtomicAttribute
141 #define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
144 #ifndef NSAccessibilityARIARelevantAttribute
145 #define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
148 #ifndef NSAccessibilityARIABusyAttribute
149 #define NSAccessibilityARIABusyAttribute @"AXARIABusy"
152 #ifndef NSAccessibilityLoadingProgressAttribute
153 #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
156 #ifndef NSAccessibilityHasPopupAttribute
157 #define NSAccessibilityHasPopupAttribute @"AXHasPopup"
160 #ifndef NSAccessibilityPlaceholderValueAttribute
161 #define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
164 #ifdef BUILDING_ON_TIGER
165 typedef unsigned NSUInteger;
166 #define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
167 #define NSAccessibilityTimelineSubrole @"AXTimeline"
170 @interface NSObject (WebKitAccessibilityArrayCategory)
172 - (NSUInteger)accessibilityIndexOfChild:(id)child;
173 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
174 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
178 @implementation AccessibilityObjectWrapper
180 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
188 - (void)unregisterUniqueIdForUIElement
190 [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
195 // Send unregisterUniqueIdForUIElement unconditionally because if it is
196 // ever accidentally not done (via other bugs in our AX implementation) you
197 // end up with a crash like <rdar://problem/4273149>. It is safe and not
198 // expensive to send even if the object is not registered.
199 [self unregisterUniqueIdForUIElement];
203 - (BOOL)updateObjectBackingStore
205 // Calling updateBackingStore() can invalidate this element so self must be retained.
206 // If it does become invalidated, m_object will be nil.
207 [[self retain] autorelease];
212 m_object->updateBackingStore();
219 - (AccessibilityObject*)accessibilityObject
224 - (NSView*)attachmentView
226 ASSERT(m_object->isAttachment());
227 Widget* widget = m_object->widgetForAttachmentView();
230 return NSAccessibilityUnignoredDescendant(widget->platformWidget());
233 static WebCoreTextMarker* textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
237 TextMarkerData textMarkerData;
238 cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
239 if (!textMarkerData.axID)
242 return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)];
245 - (WebCoreTextMarker *)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos
247 return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos);
250 static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, WebCoreTextMarker* textMarker)
255 return VisiblePosition();
256 TextMarkerData textMarkerData;
257 if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)])
258 return VisiblePosition();
260 return cache->visiblePositionForTextMarkerData(textMarkerData);
263 - (VisiblePosition)visiblePositionForTextMarker:(WebCoreTextMarker *)textMarker
265 return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker);
268 static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache *cache, WebCoreTextMarkerRange* textMarkerRange)
270 return visiblePositionForTextMarker(cache, [[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]);
273 static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache *cache, WebCoreTextMarkerRange* textMarkerRange)
275 return visiblePositionForTextMarker(cache, [[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]);
278 static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2)
280 if (!textMarker1 || !textMarker2)
283 return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
286 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
291 dict = [NSDictionary dictionaryWithObjectsAndKeys:
292 [font fontName] , NSAccessibilityFontNameKey,
293 [font familyName] , NSAccessibilityFontFamilyKey,
294 [font displayName] , NSAccessibilityVisibleNameKey,
295 [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
298 [attrString addAttribute:attribute value:dict range:range];
300 [attrString removeAttribute:attribute range:range];
304 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
306 // get color information assuming NSDeviceRGBColorSpace
307 NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
309 rgbColor = [NSColor blackColor];
310 CGFloat components[4];
311 [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
313 // create a new CGColorRef to return
314 CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
315 CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
316 CGColorSpaceRelease(cgColorSpace);
318 // check for match with existing color
319 if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
320 CGColorRelease(cgColor);
327 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
330 CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
331 CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
333 [attrString addAttribute:attribute value:(id)cgColor range:range];
334 CGColorRelease(cgColor);
337 [attrString removeAttribute:attribute range:range];
340 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
343 [attrString addAttribute:attribute value:number range:range];
345 [attrString removeAttribute:attribute range:range];
348 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
350 RenderStyle* style = renderer->style();
352 // set basic font info
353 AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
356 AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyColor)), range);
357 AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)), range);
359 // set super/sub scripting
360 EVerticalAlign alignment = style->verticalAlign();
361 if (alignment == SUB)
362 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
363 else if (alignment == SUPER)
364 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
366 [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
369 if (style->textShadow())
370 AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
372 [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
374 // set underline and strikethrough
375 int decor = style->textDecorationsInEffect();
376 if ((decor & UNDERLINE) == 0) {
377 [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
378 [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
381 if ((decor & LINE_THROUGH) == 0) {
382 [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
383 [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
386 if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
387 // find colors using quirk mode approach (strict mode would use current
388 // color for all but the root line box, which would use getTextDecorationColors)
389 Color underline, overline, linethrough;
390 renderer->getTextDecorationColors(decor, underline, overline, linethrough);
392 if ((decor & UNDERLINE) != 0) {
393 AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
394 AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
397 if ((decor & LINE_THROUGH) != 0) {
398 AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
399 AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
404 static int blockquoteLevel(RenderObject* renderer)
410 for (Node* node = renderer->node(); node; node = node->parent()) {
411 if (node->hasTagName(blockquoteTag))
418 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
420 int quoteLevel = blockquoteLevel(renderer);
423 [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
425 [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
428 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int charLength, NSRange range)
430 // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
431 EditorClient* client = node->document()->page()->editorClient();
432 int currentPosition = 0;
433 while (charLength > 0) {
434 const UChar* charData = chars + currentPosition;
436 int misspellingLocation = -1;
437 int misspellingLength = 0;
438 client->checkSpellingOfString(charData, charLength, &misspellingLocation, &misspellingLength);
439 if (misspellingLocation == -1 || !misspellingLength)
442 NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
443 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
444 charLength -= (misspellingLocation + misspellingLength);
445 currentPosition += (misspellingLocation + misspellingLength);
449 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
454 AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent());
455 int parentHeadingLevel = parentObject->headingLevel();
457 if (parentHeadingLevel)
458 [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
460 [attrString removeAttribute:@"AXHeadingLevel" range:range];
463 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
465 if (object && object->isAccessibilityRenderObject()) {
466 // make a serializable AX object
468 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
472 Document* doc = renderer->document();
476 AXObjectCache* cache = doc->axObjectCache();
480 AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()];
482 [attrString addAttribute:attribute value:(id)axElement range:range];
483 CFRelease(axElement);
486 [attrString removeAttribute:attribute range:range];
489 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length)
491 // skip invisible text
492 if (!node->renderer())
495 // easier to calculate the range before appending the string
496 NSRange attrStringRange = NSMakeRange([attrString length], length);
498 // append the string from this node
499 [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
501 // add new attributes and remove irrelevant inherited ones
502 // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
503 // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means
504 // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
506 // remove inherited attachment from prior AXAttributedStringAppendReplaced
507 [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
508 [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
510 // set new attributes
511 AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
512 AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
513 AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
514 AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
516 // do spelling last because it tends to break up the range
517 AXAttributeStringSetSpelling(attrString, node, chars, length, attrStringRange);
520 static NSString* nsStringForReplacedNode(Node* replacedNode)
522 // we should always be given a rendered node and a replaced node, but be safe
523 // replaced nodes are either attachments (widgets) or images
524 if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
525 ASSERT_NOT_REACHED();
529 // create an AX object, but skip it if it is not supposed to be seen
530 RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
531 if (obj->accessibilityIsIgnored())
534 // use the attachmentCharacter to represent the replaced node
535 const UniChar attachmentChar = NSAttachmentCharacter;
536 return [NSString stringWithCharacters:&attachmentChar length:1];
539 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
544 // extract the start and end VisiblePosition
545 VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
546 if (startVisiblePosition.isNull())
549 VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
550 if (endVisiblePosition.isNull())
553 VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
554 // iterate over the range to build the AX attributed string
555 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
556 TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
557 while (!it.atEnd()) {
558 // locate the node and starting offset for this range
560 Node* node = it.range()->startContainer(exception);
561 ASSERT(node == it.range()->endContainer(exception));
562 int offset = it.range()->startOffset(exception);
564 // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
565 if (it.length() != 0) {
566 // Add the text of the list marker item if necessary.
567 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
568 if (!listMarkerText.isEmpty())
569 AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length());
571 AXAttributedStringAppendText(attrString, node, it.characters(), it.length());
573 Node* replacedNode = node->childNode(offset);
574 NSString *attachmentString = nsStringForReplacedNode(replacedNode);
575 if (attachmentString) {
576 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
578 // append the placeholder string
579 [[attrString mutableString] appendString:attachmentString];
581 // remove all inherited attributes
582 [attrString setAttributes:nil range:attrStringRange];
584 // add the attachment attribute
585 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
586 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
592 return [attrString autorelease];
595 static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosition startPosition, VisiblePosition endPosition)
597 WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
598 WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
599 return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
602 - (WebCoreTextMarkerRange *)textMarkerRangeFromVisiblePositions:(VisiblePosition)startPosition endPosition:(VisiblePosition)endPosition
604 return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition);
607 - (NSArray*)accessibilityActionNames
609 if (![self updateObjectBackingStore])
612 static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
613 static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
614 static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
615 static NSArray* sliderActions = [[NSArray alloc] initWithObjects: NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil];
618 if (m_object->actionElement())
619 actions = actionElementActions;
620 else if (m_object->isMenuRelated())
621 actions = menuElementActions;
622 else if (m_object->isSlider())
623 actions = sliderActions;
624 else if (m_object->isAttachment())
625 actions = [[self attachmentView] accessibilityActionNames];
627 actions = defaultElementActions;
632 - (NSArray*)additionalAccessibilityAttributeNames
637 NSMutableArray *additional = [NSMutableArray array];
638 if (m_object->supportsARIAOwns())
639 [additional addObject:NSAccessibilityOwnsAttribute];
641 if (m_object->isScrollbar())
642 [additional addObject:NSAccessibilityOrientationAttribute];
644 if (m_object->supportsARIADragging())
645 [additional addObject:NSAccessibilityGrabbedAttribute];
647 if (m_object->supportsARIADropping())
648 [additional addObject:NSAccessibilityDropEffectsAttribute];
650 if (m_object->isDataTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows())
651 [additional addObject:NSAccessibilitySelectedRowsAttribute];
653 if (m_object->supportsARIALiveRegion()) {
654 [additional addObject:NSAccessibilityARIALiveAttribute];
655 [additional addObject:NSAccessibilityARIARelevantAttribute];
658 // If an object is a child of a live region, then add these
659 if (m_object->isInsideARIALiveRegion()) {
660 [additional addObject:NSAccessibilityARIAAtomicAttribute];
661 [additional addObject:NSAccessibilityARIABusyAttribute];
664 if (m_object->ariaHasPopup())
665 [additional addObject:NSAccessibilityHasPopupAttribute];
670 - (NSArray*)accessibilityAttributeNames
672 if (![self updateObjectBackingStore])
675 if (m_object->isAttachment())
676 return [[self attachmentView] accessibilityAttributeNames];
678 static NSArray* attributes = nil;
679 static NSArray* anchorAttrs = nil;
680 static NSArray* webAreaAttrs = nil;
681 static NSArray* textAttrs = nil;
682 static NSArray* listBoxAttrs = nil;
683 static NSArray* rangeAttrs = nil;
684 static NSArray* commonMenuAttrs = nil;
685 static NSArray* menuAttrs = nil;
686 static NSArray* menuBarAttrs = nil;
687 static NSArray* menuItemAttrs = nil;
688 static NSArray* menuButtonAttrs = nil;
689 static NSArray* controlAttrs = nil;
690 static NSArray* tableAttrs = nil;
691 static NSArray* tableRowAttrs = nil;
692 static NSArray* tableColAttrs = nil;
693 static NSArray* tableCellAttrs = nil;
694 static NSArray* groupAttrs = nil;
695 static NSArray* inputImageAttrs = nil;
696 static NSArray* passwordFieldAttrs = nil;
697 static NSArray* tabListAttrs = nil;
698 static NSArray* comboBoxAttrs = nil;
699 static NSArray* outlineAttrs = nil;
700 static NSArray* outlineRowAttrs = nil;
701 static NSArray* buttonAttrs = nil;
702 NSMutableArray* tempArray;
703 if (attributes == nil) {
704 attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
705 NSAccessibilitySubroleAttribute,
706 NSAccessibilityRoleDescriptionAttribute,
707 NSAccessibilityChildrenAttribute,
708 NSAccessibilityHelpAttribute,
709 NSAccessibilityParentAttribute,
710 NSAccessibilityPositionAttribute,
711 NSAccessibilitySizeAttribute,
712 NSAccessibilityTitleAttribute,
713 NSAccessibilityDescriptionAttribute,
714 NSAccessibilityValueAttribute,
715 NSAccessibilityFocusedAttribute,
716 NSAccessibilityEnabledAttribute,
717 NSAccessibilityWindowAttribute,
718 @"AXSelectedTextMarkerRange",
719 @"AXStartTextMarker",
722 NSAccessibilityLinkedUIElementsAttribute,
723 NSAccessibilitySelectedAttribute,
724 NSAccessibilityBlockQuoteLevelAttribute,
725 NSAccessibilityTopLevelUIElementAttribute,
728 if (commonMenuAttrs == nil) {
729 commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
730 NSAccessibilityRoleDescriptionAttribute,
731 NSAccessibilityChildrenAttribute,
732 NSAccessibilityParentAttribute,
733 NSAccessibilityEnabledAttribute,
734 NSAccessibilityPositionAttribute,
735 NSAccessibilitySizeAttribute,
738 if (anchorAttrs == nil) {
739 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
740 [tempArray addObject:NSAccessibilityURLAttribute];
741 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
742 anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
745 if (webAreaAttrs == nil) {
746 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
747 [tempArray addObject:@"AXLinkUIElements"];
748 [tempArray addObject:@"AXLoaded"];
749 [tempArray addObject:@"AXLayoutCount"];
750 [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
751 [tempArray addObject:NSAccessibilityURLAttribute];
752 webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
755 if (textAttrs == nil) {
756 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
757 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
758 [tempArray addObject:NSAccessibilitySelectedTextAttribute];
759 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
760 [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
761 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
762 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
763 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
764 [tempArray addObject:NSAccessibilityRequiredAttribute];
765 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
766 textAttrs = [[NSArray alloc] initWithArray:tempArray];
769 if (listBoxAttrs == nil) {
770 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
771 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
772 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
773 [tempArray addObject:NSAccessibilityOrientationAttribute];
774 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
775 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
776 [tempArray addObject:NSAccessibilityRequiredAttribute];
777 listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
780 if (rangeAttrs == nil) {
781 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
782 [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
783 [tempArray addObject:NSAccessibilityValueAttribute];
784 [tempArray addObject:NSAccessibilityMinValueAttribute];
785 [tempArray addObject:NSAccessibilityMaxValueAttribute];
786 [tempArray addObject:NSAccessibilityOrientationAttribute];
787 [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
788 rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
791 if (menuBarAttrs == nil) {
792 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
793 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
794 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
795 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
796 menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
799 if (menuAttrs == nil) {
800 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
801 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
802 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
803 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
804 menuAttrs = [[NSArray alloc] initWithArray:tempArray];
807 if (menuItemAttrs == nil) {
808 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
809 [tempArray addObject:NSAccessibilityTitleAttribute];
810 [tempArray addObject:NSAccessibilityHelpAttribute];
811 [tempArray addObject:NSAccessibilitySelectedAttribute];
812 [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
813 [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
814 [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
815 [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
816 [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
817 [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
818 [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
819 menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
822 if (menuButtonAttrs == nil) {
823 menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
824 NSAccessibilityRoleDescriptionAttribute,
825 NSAccessibilityParentAttribute,
826 NSAccessibilityPositionAttribute,
827 NSAccessibilitySizeAttribute,
828 NSAccessibilityWindowAttribute,
829 NSAccessibilityTopLevelUIElementAttribute,
830 NSAccessibilityEnabledAttribute,
831 NSAccessibilityFocusedAttribute,
832 NSAccessibilityTitleAttribute,
833 NSAccessibilityChildrenAttribute, nil];
835 if (controlAttrs == nil) {
836 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
837 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
838 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
839 [tempArray addObject:NSAccessibilityRequiredAttribute];
840 controlAttrs = [[NSArray alloc] initWithArray:tempArray];
843 if (buttonAttrs == nil) {
844 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
845 // Buttons should not expose AXValue.
846 [tempArray removeObject:NSAccessibilityValueAttribute];
847 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
848 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
849 buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
852 if (comboBoxAttrs == nil) {
853 tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
854 [tempArray addObject:NSAccessibilityExpandedAttribute];
855 comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
858 if (tableAttrs == nil) {
859 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
860 [tempArray addObject:NSAccessibilityRowsAttribute];
861 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
862 [tempArray addObject:NSAccessibilityColumnsAttribute];
863 [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
864 [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
865 [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
866 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
867 [tempArray addObject:NSAccessibilityHeaderAttribute];
868 tableAttrs = [[NSArray alloc] initWithArray:tempArray];
871 if (tableRowAttrs == nil) {
872 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
873 [tempArray addObject:NSAccessibilityIndexAttribute];
874 tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
877 if (tableColAttrs == nil) {
878 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
879 [tempArray addObject:NSAccessibilityIndexAttribute];
880 [tempArray addObject:NSAccessibilityHeaderAttribute];
881 [tempArray addObject:NSAccessibilityRowsAttribute];
882 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
883 tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
886 if (tableCellAttrs == nil) {
887 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
888 [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
889 [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
890 tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
893 if (groupAttrs == nil) {
894 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
895 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
896 groupAttrs = [[NSArray alloc] initWithArray:tempArray];
899 if (inputImageAttrs == nil) {
900 tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
901 [tempArray addObject:NSAccessibilityURLAttribute];
902 inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
905 if (passwordFieldAttrs == nil) {
906 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
907 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
908 [tempArray addObject:NSAccessibilityRequiredAttribute];
909 passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
912 if (tabListAttrs == nil) {
913 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
914 [tempArray addObject:NSAccessibilityTabsAttribute];
915 [tempArray addObject:NSAccessibilityContentsAttribute];
916 tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
919 if (outlineAttrs == nil) {
920 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
921 [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
922 [tempArray addObject:NSAccessibilityRowsAttribute];
923 [tempArray addObject:NSAccessibilityColumnsAttribute];
924 outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
927 if (outlineRowAttrs == nil) {
928 tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
929 [tempArray addObject:NSAccessibilityDisclosingAttribute];
930 [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
931 [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
932 [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
933 outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
937 NSArray *objectAttributes = attributes;
939 if (m_object->isPasswordField())
940 objectAttributes = passwordFieldAttrs;
942 else if (m_object->isWebArea())
943 objectAttributes = webAreaAttrs;
945 else if (m_object->isTextControl())
946 objectAttributes = textAttrs;
948 else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
949 objectAttributes = anchorAttrs;
951 else if (m_object->isDataTable())
952 objectAttributes = tableAttrs;
953 else if (m_object->isTableColumn())
954 objectAttributes = tableColAttrs;
955 else if (m_object->isTableCell())
956 objectAttributes = tableCellAttrs;
957 else if (m_object->isTableRow()) {
958 // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
959 if (m_object->isARIATreeGridRow())
960 objectAttributes = outlineRowAttrs;
962 objectAttributes = tableRowAttrs;
965 else if (m_object->isTree())
966 objectAttributes = outlineAttrs;
967 else if (m_object->isTreeItem())
968 objectAttributes = outlineRowAttrs;
970 else if (m_object->isListBox() || m_object->isList())
971 objectAttributes = listBoxAttrs;
973 else if (m_object->isComboBox())
974 objectAttributes = comboBoxAttrs;
976 else if (m_object->isProgressIndicator() || m_object->isSlider())
977 objectAttributes = rangeAttrs;
979 // These are processed in order because an input image is a button, and a button is a control.
980 else if (m_object->isInputImage())
981 objectAttributes = inputImageAttrs;
982 else if (m_object->isButton())
983 objectAttributes = buttonAttrs;
984 else if (m_object->isControl())
985 objectAttributes = controlAttrs;
987 else if (m_object->isGroup() || m_object->isListItem())
988 objectAttributes = groupAttrs;
989 else if (m_object->isTabList())
990 objectAttributes = tabListAttrs;
992 else if (m_object->isMenu())
993 objectAttributes = menuAttrs;
994 else if (m_object->isMenuBar())
995 objectAttributes = menuBarAttrs;
996 else if (m_object->isMenuButton())
997 objectAttributes = menuButtonAttrs;
998 else if (m_object->isMenuItem())
999 objectAttributes = menuItemAttrs;
1001 NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1002 if ([additionalAttributes count])
1003 objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1005 return objectAttributes;
1008 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
1010 if (!textMarkerRange)
1011 return VisiblePositionRange();
1012 AXObjectCache* cache = m_object->axObjectCache();
1013 return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1016 - (NSArray*)renderWidgetChildren
1018 Widget* widget = m_object->widget();
1021 return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1024 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1026 unsigned length = [array count];
1027 vector.reserveInitialCapacity(length);
1028 for (unsigned i = 0; i < length; ++i) {
1029 AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1035 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1037 unsigned length = vector.size();
1038 NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
1039 for (unsigned i = 0; i < length; ++i) {
1040 AccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
1043 // we want to return the attachment view instead of the object representing the attachment.
1044 // otherwise, we get palindrome errors in the AX hierarchy
1045 if (vector[i]->isAttachment() && [wrapper attachmentView])
1046 [array addObject:[wrapper attachmentView]];
1048 [array addObject:wrapper];
1054 - (WebCoreTextMarkerRange*)textMarkerRangeForSelection
1056 VisibleSelection selection = m_object->selection();
1057 if (selection.isNone())
1059 return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1062 - (NSValue*)position
1064 IntRect rect = m_object->elementRect();
1066 // The Cocoa accessibility API wants the lower-left corner.
1067 NSPoint point = NSMakePoint(rect.x(), rect.bottom());
1068 FrameView* frameView = m_object->documentFrameView();
1070 NSView* view = frameView->documentView();
1071 point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
1074 return [NSValue valueWithPoint: point];
1077 typedef HashMap<int, NSString*> AccessibilityRoleMap;
1079 static const AccessibilityRoleMap& createAccessibilityRoleMap()
1082 AccessibilityRole value;
1086 static const RoleEntry roles[] = {
1087 { UnknownRole, NSAccessibilityUnknownRole },
1088 { ButtonRole, NSAccessibilityButtonRole },
1089 { RadioButtonRole, NSAccessibilityRadioButtonRole },
1090 { CheckBoxRole, NSAccessibilityCheckBoxRole },
1091 { SliderRole, NSAccessibilitySliderRole },
1092 { TabGroupRole, NSAccessibilityTabGroupRole },
1093 { TextFieldRole, NSAccessibilityTextFieldRole },
1094 { StaticTextRole, NSAccessibilityStaticTextRole },
1095 { TextAreaRole, NSAccessibilityTextAreaRole },
1096 { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1097 { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1098 { MenuButtonRole, NSAccessibilityMenuButtonRole },
1099 { TableRole, NSAccessibilityTableRole },
1100 { ApplicationRole, NSAccessibilityApplicationRole },
1101 { GroupRole, NSAccessibilityGroupRole },
1102 { RadioGroupRole, NSAccessibilityRadioGroupRole },
1103 { ListRole, NSAccessibilityListRole },
1104 { DirectoryRole, NSAccessibilityListRole },
1105 { ScrollBarRole, NSAccessibilityScrollBarRole },
1106 { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1107 { ImageRole, NSAccessibilityImageRole },
1108 { MenuBarRole, NSAccessibilityMenuBarRole },
1109 { MenuRole, NSAccessibilityMenuRole },
1110 { MenuItemRole, NSAccessibilityMenuItemRole },
1111 { ColumnRole, NSAccessibilityColumnRole },
1112 { RowRole, NSAccessibilityRowRole },
1113 { ToolbarRole, NSAccessibilityToolbarRole },
1114 { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1115 { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1116 { WindowRole, NSAccessibilityWindowRole },
1117 { DrawerRole, NSAccessibilityDrawerRole },
1118 { SystemWideRole, NSAccessibilitySystemWideRole },
1119 { OutlineRole, NSAccessibilityOutlineRole },
1120 { IncrementorRole, NSAccessibilityIncrementorRole },
1121 { BrowserRole, NSAccessibilityBrowserRole },
1122 { ComboBoxRole, NSAccessibilityComboBoxRole },
1123 { SplitGroupRole, NSAccessibilitySplitGroupRole },
1124 { SplitterRole, NSAccessibilitySplitterRole },
1125 { ColorWellRole, NSAccessibilityColorWellRole },
1126 { GrowAreaRole, NSAccessibilityGrowAreaRole },
1127 { SheetRole, NSAccessibilitySheetRole },
1128 { HelpTagRole, NSAccessibilityHelpTagRole },
1129 { MatteRole, NSAccessibilityMatteRole },
1130 { RulerRole, NSAccessibilityRulerRole },
1131 { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1132 { LinkRole, NSAccessibilityLinkRole },
1133 #ifndef BUILDING_ON_TIGER
1134 { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1135 { GridRole, NSAccessibilityGridRole },
1137 { WebCoreLinkRole, NSAccessibilityLinkRole },
1138 { ImageMapLinkRole, NSAccessibilityLinkRole },
1139 { ImageMapRole, @"AXImageMap" },
1140 { ListMarkerRole, @"AXListMarker" },
1141 { WebAreaRole, @"AXWebArea" },
1142 { HeadingRole, @"AXHeading" },
1143 { ListBoxRole, NSAccessibilityListRole },
1144 { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1145 #if ACCESSIBILITY_TABLES
1146 { CellRole, NSAccessibilityCellRole },
1148 { CellRole, NSAccessibilityGroupRole },
1150 { TableHeaderContainerRole, NSAccessibilityGroupRole },
1151 { DefinitionListDefinitionRole, NSAccessibilityGroupRole },
1152 { DefinitionListTermRole, NSAccessibilityGroupRole },
1153 { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1154 { LandmarkApplicationRole, NSAccessibilityGroupRole },
1155 { LandmarkBannerRole, NSAccessibilityGroupRole },
1156 { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1157 { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1158 { LandmarkMainRole, NSAccessibilityGroupRole },
1159 { LandmarkNavigationRole, NSAccessibilityGroupRole },
1160 { LandmarkSearchRole, NSAccessibilityGroupRole },
1161 { ApplicationAlertRole, NSAccessibilityGroupRole },
1162 { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1163 { ApplicationDialogRole, NSAccessibilityGroupRole },
1164 { ApplicationLogRole, NSAccessibilityGroupRole },
1165 { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1166 { ApplicationStatusRole, NSAccessibilityGroupRole },
1167 { ApplicationTimerRole, NSAccessibilityGroupRole },
1168 { DocumentRole, NSAccessibilityGroupRole },
1169 { DocumentArticleRole, NSAccessibilityGroupRole },
1170 { DocumentMathRole, NSAccessibilityGroupRole },
1171 { DocumentNoteRole, NSAccessibilityGroupRole },
1172 { DocumentRegionRole, NSAccessibilityGroupRole },
1173 { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1174 { TabRole, NSAccessibilityRadioButtonRole },
1175 { TabListRole, NSAccessibilityTabGroupRole },
1176 { TabPanelRole, NSAccessibilityGroupRole },
1177 { TreeRole, NSAccessibilityOutlineRole },
1178 { TreeItemRole, NSAccessibilityRowRole },
1179 { ListItemRole, NSAccessibilityGroupRole }
1181 AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1183 const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1184 for (unsigned i = 0; i < numRoles; ++i)
1185 roleMap.set(roles[i].value, roles[i].string);
1189 static NSString* roleValueToNSString(AccessibilityRole value)
1192 static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1193 return roleMap.get(value);
1198 if (m_object->isAttachment())
1199 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1200 NSString* string = roleValueToNSString(m_object->roleValue());
1203 return NSAccessibilityUnknownRole;
1206 - (NSString*)subrole
1208 if (m_object->isPasswordField())
1209 return NSAccessibilitySecureTextFieldSubrole;
1211 if (m_object->isAttachment()) {
1212 NSView* attachView = [self attachmentView];
1213 if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1214 return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1218 if (m_object->isTreeItem())
1219 return NSAccessibilityOutlineRowSubrole;
1221 if (m_object->isList()) {
1222 AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
1223 if (listObject->isUnorderedList() || listObject->isOrderedList())
1224 return NSAccessibilityContentListSubrole;
1225 if (listObject->isDefinitionList())
1226 return NSAccessibilityDefinitionListSubrole;
1229 // ARIA content subroles.
1230 switch (m_object->roleValue()) {
1231 case LandmarkApplicationRole:
1232 return @"AXLandmarkApplication";
1233 case LandmarkBannerRole:
1234 return @"AXLandmarkBanner";
1235 case LandmarkComplementaryRole:
1236 return @"AXLandmarkComplementary";
1237 case LandmarkContentInfoRole:
1238 return @"AXLandmarkContentInfo";
1239 case LandmarkMainRole:
1240 return @"AXLandmarkMain";
1241 case LandmarkNavigationRole:
1242 return @"AXLandmarkNavigation";
1243 case LandmarkSearchRole:
1244 return @"AXLandmarkSearch";
1245 case ApplicationAlertRole:
1246 return @"AXApplicationAlert";
1247 case ApplicationAlertDialogRole:
1248 return @"AXApplicationAlertDialog";
1249 case ApplicationDialogRole:
1250 return @"AXApplicationDialog";
1251 case ApplicationLogRole:
1252 return @"AXApplicationLog";
1253 case ApplicationMarqueeRole:
1254 return @"AXApplicationMarquee";
1255 case ApplicationStatusRole:
1256 return @"AXApplicationStatus";
1257 case ApplicationTimerRole:
1258 return @"AXApplicationTimer";
1260 return @"AXDocument";
1261 case DocumentArticleRole:
1262 return @"AXDocumentArticle";
1263 case DocumentMathRole:
1264 return @"AXDocumentMath";
1265 case DocumentNoteRole:
1266 return @"AXDocumentNote";
1267 case DocumentRegionRole:
1268 return @"AXDocumentRegion";
1269 case UserInterfaceTooltipRole:
1270 return @"AXUserInterfaceTooltip";
1272 return @"AXTabPanel";
1273 case DefinitionListTermRole:
1275 case DefinitionListDefinitionRole:
1276 return @"AXDefinition";
1277 // Default doesn't return anything, so roles defined below can be chosen.
1282 if (m_object->isMediaTimeline())
1283 return NSAccessibilityTimelineSubrole;
1288 - (NSString*)roleDescription
1293 // attachments have the AXImage role, but a different subrole
1294 if (m_object->isAttachment())
1295 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1297 NSString* axRole = [self role];
1299 if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1300 switch (m_object->roleValue()) {
1302 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1303 case LandmarkApplicationRole:
1304 return AXARIAContentGroupText(@"ARIALandmarkApplication");
1305 case LandmarkBannerRole:
1306 return AXARIAContentGroupText(@"ARIALandmarkBanner");
1307 case LandmarkComplementaryRole:
1308 return AXARIAContentGroupText(@"ARIALandmarkComplementary");
1309 case LandmarkContentInfoRole:
1310 return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
1311 case LandmarkMainRole:
1312 return AXARIAContentGroupText(@"ARIALandmarkMain");
1313 case LandmarkNavigationRole:
1314 return AXARIAContentGroupText(@"ARIALandmarkNavigation");
1315 case LandmarkSearchRole:
1316 return AXARIAContentGroupText(@"ARIALandmarkSearch");
1317 case ApplicationAlertRole:
1318 return AXARIAContentGroupText(@"ARIAApplicationAlert");
1319 case ApplicationAlertDialogRole:
1320 return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
1321 case ApplicationDialogRole:
1322 return AXARIAContentGroupText(@"ARIAApplicationDialog");
1323 case ApplicationLogRole:
1324 return AXARIAContentGroupText(@"ARIAApplicationLog");
1325 case ApplicationMarqueeRole:
1326 return AXARIAContentGroupText(@"ARIAApplicationMarquee");
1327 case ApplicationStatusRole:
1328 return AXARIAContentGroupText(@"ARIAApplicationStatus");
1329 case ApplicationTimerRole:
1330 return AXARIAContentGroupText(@"ARIAApplicationTimer");
1332 return AXARIAContentGroupText(@"ARIADocument");
1333 case DocumentArticleRole:
1334 return AXARIAContentGroupText(@"ARIADocumentArticle");
1335 case DocumentMathRole:
1336 return AXARIAContentGroupText(@"ARIADocumentMath");
1337 case DocumentNoteRole:
1338 return AXARIAContentGroupText(@"ARIADocumentNote");
1339 case DocumentRegionRole:
1340 return AXARIAContentGroupText(@"ARIADocumentRegion");
1341 case UserInterfaceTooltipRole:
1342 return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
1344 return AXARIAContentGroupText(@"ARIATabPanel");
1345 case DefinitionListTermRole:
1346 return AXDefinitionListTermText();
1347 case DefinitionListDefinitionRole:
1348 return AXDefinitionListDefinitionText();
1352 if ([axRole isEqualToString:@"AXWebArea"])
1353 return AXWebAreaText();
1355 if ([axRole isEqualToString:@"AXLink"])
1356 return AXLinkText();
1358 if ([axRole isEqualToString:@"AXListMarker"])
1359 return AXListMarkerText();
1361 if ([axRole isEqualToString:@"AXImageMap"])
1362 return AXImageMapText();
1364 if ([axRole isEqualToString:@"AXHeading"])
1365 return AXHeadingText();
1367 // AppKit also returns AXTab for the role description for a tab item.
1368 if (m_object->isTabItem())
1369 return NSAccessibilityRoleDescription(@"AXTab", nil);
1371 // We should try the system default role description for all other roles.
1372 // If we get the same string back, then as a last resort, return unknown.
1373 NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1374 if (![defaultRoleDescription isEqualToString:axRole])
1375 return defaultRoleDescription;
1377 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1380 // FIXME: split up this function in a better way.
1381 // suggestions: Use a hash table that maps attribute names to function calls,
1382 // or maybe pointers to member functions
1383 - (id)accessibilityAttributeValue:(NSString*)attributeName
1385 if (![self updateObjectBackingStore])
1388 if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1391 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1392 return [self subrole];
1394 if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1395 return [self roleDescription];
1397 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1398 if (m_object->isAccessibilityRenderObject()) {
1399 FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
1401 return fv->platformWidget();
1404 // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1405 if (m_object->isTreeItem()) {
1406 AccessibilityObject* parent = m_object->parentObjectUnignored();
1408 if (parent->isTree())
1409 return parent->wrapper();
1410 parent = parent->parentObjectUnignored();
1414 return m_object->parentObjectUnignored()->wrapper();
1417 if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1418 if (m_object->children().isEmpty()) {
1419 NSArray* children = [self renderWidgetChildren];
1420 if (children != nil)
1424 // The tree's (AXOutline) children are supposed to be its rows and columns.
1425 // The ARIA spec doesn't have columns, so we just need rows.
1426 if (m_object->isTree())
1427 return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1429 // A tree item should only expose its content as its children (not its rows)
1430 if (m_object->isTreeItem()) {
1431 AccessibilityObject::AccessibilityChildrenVector contentCopy;
1432 m_object->ariaTreeItemContent(contentCopy);
1433 return convertToNSArray(contentCopy);
1436 return convertToNSArray(m_object->children());
1439 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1440 if (m_object->isListBox()) {
1441 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1442 m_object->selectedChildren(selectedChildrenCopy);
1443 return convertToNSArray(selectedChildrenCopy);
1448 if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
1449 if (m_object->isListBox()) {
1450 AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
1451 m_object->visibleChildren(visibleChildrenCopy);
1452 return convertToNSArray(visibleChildrenCopy);
1454 else if (m_object->isList())
1455 return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1461 if (m_object->isWebArea()) {
1462 if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
1463 AccessibilityObject::AccessibilityChildrenVector links;
1464 static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
1465 return convertToNSArray(links);
1467 if ([attributeName isEqualToString:@"AXLoaded"])
1468 return [NSNumber numberWithBool:m_object->isLoaded()];
1469 if ([attributeName isEqualToString:@"AXLayoutCount"])
1470 return [NSNumber numberWithInt:m_object->layoutCount()];
1471 if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
1472 return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
1475 if (m_object->isTextControl()) {
1476 if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1477 int length = m_object->textLength();
1480 return [NSNumber numberWithUnsignedInt:length];
1482 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1483 String selectedText = m_object->selectedText();
1484 if (selectedText.isNull())
1486 return (NSString*)selectedText;
1488 if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1489 PlainTextRange textRange = m_object->selectedTextRange();
1490 if (textRange.isNull())
1491 return [NSValue valueWithRange:NSMakeRange(0, 0)];
1492 return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1494 // TODO: Get actual visible range. <rdar://problem/4712101>
1495 if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1496 return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1497 if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1498 // if selectionEnd > 0, then there is selected text and this question should not be answered
1499 if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
1501 int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
1504 return [NSNumber numberWithInt:lineNumber];
1508 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1509 KURL url = m_object->url();
1515 if ([attributeName isEqualToString: @"AXVisited"])
1516 return [NSNumber numberWithBool: m_object->isVisited()];
1518 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1519 if (m_object->isAttachment()) {
1520 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
1521 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1523 return m_object->title();
1526 if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1527 if (m_object->isAttachment()) {
1528 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1529 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1531 return m_object->accessibilityDescription();
1534 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1535 if (m_object->isAttachment()) {
1536 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
1537 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1539 if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar())
1540 return [NSNumber numberWithFloat:m_object->valueForRange()];
1541 if (m_object->isHeading())
1542 return [NSNumber numberWithInt:m_object->headingLevel()];
1544 if (m_object->isCheckboxOrRadio()) {
1545 switch (m_object->checkboxOrRadioValue()) {
1546 case ButtonStateOff:
1547 return [NSNumber numberWithInt:0];
1549 return [NSNumber numberWithInt:1];
1550 case ButtonStateMixed:
1551 return [NSNumber numberWithInt:2];
1555 // radio groups return the selected radio button as the AXValue
1556 if (m_object->isRadioGroup()) {
1557 AccessibilityObject* radioButton = m_object->selectedRadioButton();
1560 return radioButton->wrapper();
1563 if (m_object->isTabList()) {
1564 AccessibilityObject* tabItem = m_object->selectedTabItem();
1567 return tabItem->wrapper();
1570 if (m_object->isTabItem())
1571 return [NSNumber numberWithInt:m_object->isSelected()];
1573 return m_object->stringValue();
1576 if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1577 return [NSNumber numberWithFloat:m_object->minValueForRange()];
1579 if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1580 return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1582 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1583 return m_object->helpText();
1585 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1586 return [NSNumber numberWithBool: m_object->isFocused()];
1588 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1589 return [NSNumber numberWithBool: m_object->isEnabled()];
1591 if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1592 IntSize s = m_object->size();
1593 return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1596 if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1597 return [self position];
1599 if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1600 [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1601 FrameView* fv = m_object->documentFrameView();
1603 return [fv->platformWidget() window];
1607 if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
1608 AtomicString accessKey = m_object->accessKey();
1609 if (accessKey.isNull())
1614 if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
1615 if (m_object->isTabList()) {
1616 AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1617 m_object->tabChildren(tabsChildren);
1618 return convertToNSArray(tabsChildren);
1622 if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
1623 // The contents of a tab list are all the children except the tabs.
1624 if (m_object->isTabList()) {
1625 AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1626 AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1627 m_object->tabChildren(tabsChildren);
1629 AccessibilityObject::AccessibilityChildrenVector contents;
1630 unsigned childrenSize = children.size();
1631 for (unsigned k = 0; k < childrenSize; ++k) {
1632 if (tabsChildren.find(children[k]) == WTF::notFound)
1633 contents.append(children[k]);
1635 return convertToNSArray(contents);
1639 if (m_object->isDataTable()) {
1640 // TODO: distinguish between visible and non-visible rows
1641 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1642 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1643 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
1645 // TODO: distinguish between visible and non-visible columns
1646 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
1647 [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
1648 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
1651 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1652 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1653 m_object->selectedChildren(selectedChildrenCopy);
1654 return convertToNSArray(selectedChildrenCopy);
1657 // HTML tables don't support these
1658 if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
1659 [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1662 if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
1663 AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1664 static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
1665 return convertToNSArray(columnHeaders);
1668 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1669 AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
1670 if (headerContainer)
1671 return headerContainer->wrapper();
1675 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
1676 AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1677 static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
1678 return convertToNSArray(rowHeaders);
1681 if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
1682 AccessibilityObject::AccessibilityChildrenVector cells;
1683 static_cast<AccessibilityTable*>(m_object)->cells(cells);
1684 return convertToNSArray(cells);
1688 if (m_object->isTableColumn()) {
1689 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1690 return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
1692 // rows attribute for a column is the list of all the elements in that column at each row
1693 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1694 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1695 return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
1697 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1698 AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
1701 return header->wrapper();
1705 if (m_object->isTableCell()) {
1706 if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1707 pair<int, int> rowRange;
1708 static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
1709 return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1711 if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1712 pair<int, int> columnRange;
1713 static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
1714 return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1718 if (m_object->isTree()) {
1719 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1720 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1721 m_object->selectedChildren(selectedChildrenCopy);
1722 return convertToNSArray(selectedChildrenCopy);
1724 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
1725 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1726 m_object->ariaTreeRows(rowsCopy);
1727 return convertToNSArray(rowsCopy);
1730 // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
1731 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
1732 return [NSArray array];
1735 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
1736 if (m_object->isTreeItem()) {
1737 AccessibilityObject* parent = m_object->parentObject();
1738 for (; parent && !parent->isTree(); parent = parent->parentObject())
1744 // Find the index of this item by iterating the parents.
1745 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1746 parent->ariaTreeRows(rowsCopy);
1747 size_t count = rowsCopy.size();
1748 for (size_t k = 0; k < count; ++k)
1749 if (rowsCopy[k]->wrapper() == self)
1750 return [NSNumber numberWithUnsignedInt:k];
1754 if (m_object->isTableRow()) {
1755 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1756 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
1760 // The rows that are considered inside this row.
1761 if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
1762 if (m_object->isTreeItem()) {
1763 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1764 m_object->ariaTreeItemDisclosedRows(rowsCopy);
1765 return convertToNSArray(rowsCopy);
1766 } else if (m_object->isARIATreeGridRow()) {
1767 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1768 static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
1769 return convertToNSArray(rowsCopy);
1773 // The row that contains this row. It should be the same as the first parent that is a treeitem.
1774 if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
1775 if (m_object->isTreeItem()) {
1776 AccessibilityObject* parent = m_object->parentObject();
1778 if (parent->isTreeItem())
1779 return parent->wrapper();
1780 // If the parent is the tree itself, then this value == nil.
1781 if (parent->isTree())
1783 parent = parent->parentObject();
1786 } else if (m_object->isARIATreeGridRow()) {
1787 AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
1790 return row->wrapper();
1794 if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute])
1795 return [NSNumber numberWithInt:m_object->hierarchicalLevel()];
1796 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1797 return [NSNumber numberWithBool:m_object->isExpanded()];
1799 if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1800 return NSAccessibilityVerticalOrientationValue;
1802 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1803 return [self textMarkerRangeForSelection];
1805 if (m_object->isAccessibilityRenderObject()) {
1806 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1810 if ([attributeName isEqualToString: @"AXStartTextMarker"])
1811 return [self textMarkerForVisiblePosition:startOfDocument(renderer->document())];
1812 if ([attributeName isEqualToString: @"AXEndTextMarker"])
1813 return [self textMarkerForVisiblePosition:endOfDocument(renderer->document())];
1815 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
1816 return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1818 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) {
1819 AccessibilityObject* parent = m_object->parentObjectUnignored();
1821 return [NSNumber numberWithInt:0];
1822 return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute];
1826 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1827 AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1828 m_object->linkedUIElements(linkedUIElements);
1829 if (linkedUIElements.size() == 0)
1831 return convertToNSArray(linkedUIElements);
1834 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1835 return [NSNumber numberWithBool:m_object->isSelected()];
1837 if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
1838 AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
1840 return [NSArray arrayWithObject:uiElement->wrapper()];
1843 if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
1844 AccessibilityObject* obj = m_object->titleUIElement();
1846 return obj->wrapper();
1850 if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
1851 return m_object->valueDescription();
1853 if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
1854 AccessibilityOrientation elementOrientation = m_object->orientation();
1855 if (elementOrientation == AccessibilityOrientationVertical)
1856 return NSAccessibilityVerticalOrientationValue;
1857 if (elementOrientation == AccessibilityOrientationHorizontal)
1858 return NSAccessibilityHorizontalOrientationValue;
1862 if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
1863 return m_object->language();
1865 if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
1866 return [NSNumber numberWithBool:m_object->isExpanded()];
1868 if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
1869 return [NSNumber numberWithBool:m_object->isRequired()];
1871 if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
1872 AccessibilityObject::AccessibilityChildrenVector ariaOwns;
1873 m_object->ariaOwnsElements(ariaOwns);
1874 return convertToNSArray(ariaOwns);
1877 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
1878 return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
1880 if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
1881 Vector<String> dropEffects;
1882 m_object->determineARIADropEffects(dropEffects);
1883 size_t length = dropEffects.size();
1885 NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
1886 for (size_t i = 0; i < length; ++i)
1887 [dropEffectsArray addObject:dropEffects[i]];
1888 return dropEffectsArray;
1891 if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
1892 return m_object->placeholderValue();
1894 if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
1895 return [NSNumber numberWithBool:m_object->ariaHasPopup()];
1897 // ARIA Live region attributes.
1898 if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
1899 return m_object->ariaLiveRegionStatus();
1900 if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
1901 return m_object->ariaLiveRegionRelevant();
1902 if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
1903 return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
1904 if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
1905 return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
1907 // this is used only by DumpRenderTree for testing
1908 if ([attributeName isEqualToString:@"AXClickPoint"])
1909 return [NSValue valueWithPoint:m_object->clickPoint()];
1914 - (id)accessibilityFocusedUIElement
1916 if (![self updateObjectBackingStore])
1919 RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
1924 return focusedObj->wrapper();
1927 - (id)accessibilityHitTest:(NSPoint)point
1929 if (![self updateObjectBackingStore])
1932 RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
1934 return NSAccessibilityUnignoredAncestor(axObject->wrapper());
1935 return NSAccessibilityUnignoredAncestor(self);
1938 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
1940 if (![self updateObjectBackingStore])
1943 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1946 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1947 return m_object->canSetFocusAttribute();
1949 if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
1950 return m_object->canSetValueAttribute();
1952 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1953 return m_object->canSetSelectedAttribute();
1955 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
1956 return m_object->canSetSelectedChildrenAttribute();
1958 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1959 return m_object->canSetExpandedAttribute();
1961 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
1964 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
1965 [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
1966 [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1967 return m_object->canSetTextRangeAttributes();
1969 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
1975 // accessibilityShouldUseUniqueId is an AppKit method we override so that
1976 // objects will be given a unique ID, and therefore allow AppKit to know when they
1977 // become obsolete (e.g. when the user navigates to a new web page, making this one
1978 // unrendered but not deallocated because it is in the back/forward cache).
1979 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
1980 // appropriate place (e.g. dealloc) to remove these non-retained references from
1981 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
1983 // Registering an object is also required for observing notifications. Only registered objects can be observed.
1984 - (BOOL)accessibilityIsIgnored
1986 if (![self updateObjectBackingStore])
1989 if (m_object->isAttachment())
1990 return [[self attachmentView] accessibilityIsIgnored];
1991 return m_object->accessibilityIsIgnored();
1994 - (NSArray* )accessibilityParameterizedAttributeNames
1996 if (![self updateObjectBackingStore])
1999 if (m_object->isAttachment())
2002 static NSArray* paramAttrs = nil;
2003 static NSArray* textParamAttrs = nil;
2004 static NSArray* tableParamAttrs = nil;
2005 if (paramAttrs == nil) {
2006 paramAttrs = [[NSArray alloc] initWithObjects:
2007 @"AXUIElementForTextMarker",
2008 @"AXTextMarkerRangeForUIElement",
2009 @"AXLineForTextMarker",
2010 @"AXTextMarkerRangeForLine",
2011 @"AXStringForTextMarkerRange",
2012 @"AXTextMarkerForPosition",
2013 @"AXBoundsForTextMarkerRange",
2014 @"AXAttributedStringForTextMarkerRange",
2015 @"AXTextMarkerRangeForUnorderedTextMarkers",
2016 @"AXNextTextMarkerForTextMarker",
2017 @"AXPreviousTextMarkerForTextMarker",
2018 @"AXLeftWordTextMarkerRangeForTextMarker",
2019 @"AXRightWordTextMarkerRangeForTextMarker",
2020 @"AXLeftLineTextMarkerRangeForTextMarker",
2021 @"AXRightLineTextMarkerRangeForTextMarker",
2022 @"AXSentenceTextMarkerRangeForTextMarker",
2023 @"AXParagraphTextMarkerRangeForTextMarker",
2024 @"AXNextWordEndTextMarkerForTextMarker",
2025 @"AXPreviousWordStartTextMarkerForTextMarker",
2026 @"AXNextLineEndTextMarkerForTextMarker",
2027 @"AXPreviousLineStartTextMarkerForTextMarker",
2028 @"AXNextSentenceEndTextMarkerForTextMarker",
2029 @"AXPreviousSentenceStartTextMarkerForTextMarker",
2030 @"AXNextParagraphEndTextMarkerForTextMarker",
2031 @"AXPreviousParagraphStartTextMarkerForTextMarker",
2032 @"AXStyleTextMarkerRangeForTextMarker",
2033 @"AXLengthForTextMarkerRange",
2034 NSAccessibilityBoundsForRangeParameterizedAttribute,
2035 NSAccessibilityStringForRangeParameterizedAttribute,
2039 if (textParamAttrs == nil) {
2040 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2041 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2042 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2043 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2044 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2045 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2046 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2047 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2048 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2049 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2050 textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2051 [tempArray release];
2053 if (tableParamAttrs == nil) {
2054 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2055 [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2056 tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2057 [tempArray release];
2060 if (m_object->isPasswordField())
2061 return [NSArray array];
2063 if (!m_object->isAccessibilityRenderObject())
2066 if (m_object->isTextControl())
2067 return textParamAttrs;
2069 if (m_object->isDataTable())
2070 return tableParamAttrs;
2072 if (m_object->isMenuRelated())
2078 - (void)accessibilityPerformPressAction
2080 if (![self updateObjectBackingStore])
2083 if (m_object->isAttachment())
2084 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2089 - (void)accessibilityPerformIncrementAction
2091 if (![self updateObjectBackingStore])
2094 if (m_object->isAttachment())
2095 [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2097 m_object->increment();
2100 - (void)accessibilityPerformDecrementAction
2102 if (![self updateObjectBackingStore])
2105 if (m_object->isAttachment())
2106 [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2108 m_object->decrement();
2111 - (void)accessibilityPerformShowMenuAction
2113 if (m_object->roleValue() == ComboBoxRole)
2114 m_object->setIsExpanded(true);
2116 // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2117 // If it's the same run loop iteration, the menu open notification won't be sent
2118 [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2122 - (void)accessibilityShowContextMenu
2124 FrameView* frameView = m_object->documentFrameView();
2128 // simulate a click in the middle of the object
2129 IntPoint clickPoint = m_object->clickPoint();
2130 NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y());
2133 if (m_object->isAttachment())
2134 view = [self attachmentView];
2136 view = frameView->documentView();
2141 NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil];
2143 // Show the contextual menu for this event.
2144 NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
2145 NSMenu* menu = [view menuForEvent:event];
2148 [NSMenu popUpContextMenu:menu withEvent:event forView:view];
2151 - (void)accessibilityPerformAction:(NSString*)action
2153 if (![self updateObjectBackingStore])
2156 if ([action isEqualToString:NSAccessibilityPressAction])
2157 [self accessibilityPerformPressAction];
2159 else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2160 [self accessibilityPerformShowMenuAction];
2162 else if ([action isEqualToString:NSAccessibilityIncrementAction])
2163 [self accessibilityPerformIncrementAction];
2165 else if ([action isEqualToString:NSAccessibilityDecrementAction])
2166 [self accessibilityPerformDecrementAction];
2169 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2171 if (![self updateObjectBackingStore])
2174 WebCoreTextMarkerRange* textMarkerRange = nil;
2175 NSNumber* number = nil;
2176 NSString* string = nil;
2177 NSRange range = {0, 0};
2178 NSArray* array = nil;
2180 // decode the parameter
2181 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
2182 textMarkerRange = (WebCoreTextMarkerRange*) value;
2184 else if ([value isKindOfClass:[NSNumber self]])
2187 else if ([value isKindOfClass:[NSString self]])
2190 else if ([value isKindOfClass:[NSValue self]])
2191 range = [value rangeValue];
2193 else if ([value isKindOfClass:[NSArray self]])
2196 // handle the command
2197 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2198 ASSERT(textMarkerRange);
2199 m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
2200 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2202 m_object->setFocused([number intValue] != 0);
2203 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2206 m_object->setValue(string);
2207 } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
2210 m_object->setSelected([number boolValue]);
2211 } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2212 if (!array || m_object->roleValue() != ListBoxRole)
2214 AccessibilityObject::AccessibilityChildrenVector selectedChildren;
2215 convertToVector(array, selectedChildren);
2216 static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
2217 } else if (m_object->isTextControl()) {
2218 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2219 m_object->setSelectedText(string);
2220 } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2221 m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2222 } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2223 m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
2225 } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2226 m_object->setIsExpanded([number boolValue]);
2227 else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2228 AccessibilityObject::AccessibilityChildrenVector selectedRows;
2229 convertToVector(array, selectedRows);
2230 if (m_object->isTree() || m_object->isDataTable())
2231 m_object->setSelectedRows(selectedRows);
2232 } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2233 m_object->setARIAGrabbed([number boolValue]);
2236 static RenderObject* rendererForView(NSView* view)
2238 if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
2241 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
2242 Frame* frame = [frameView _web_frame];
2246 Node* node = frame->document()->ownerElement();
2250 return node->renderer();
2253 - (id)_accessibilityParentForSubview:(NSView*)subview
2255 RenderObject* renderer = rendererForView(subview);
2259 AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
2261 return obj->parentObjectUnignored()->wrapper();
2265 - (NSString*)accessibilityActionDescription:(NSString*)action
2267 // we have no custom actions
2268 return NSAccessibilityActionDescription(action);
2271 // The CFAttributedStringType representation of the text associated with this accessibility
2272 // object that is specified by the given range.
2273 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
2275 PlainTextRange textRange = PlainTextRange(range.location, range.length);
2276 VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
2277 return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
2280 // The RTF representation of the text associated with this accessibility object that is
2281 // specified by the given range.
2282 - (NSData*)doAXRTFForRange:(NSRange)range
2284 NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
2285 return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
2288 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2290 WebCoreTextMarker* textMarker = nil;
2291 WebCoreTextMarkerRange* textMarkerRange = nil;
2292 NSNumber* number = nil;
2293 NSArray* array = nil;
2294 RefPtr<AccessibilityObject> uiElement = 0;
2295 NSPoint point = NSZeroPoint;
2296 bool pointSet = false;
2297 NSRange range = {0, 0};
2298 bool rangeSet = false;
2300 // basic parameter validation
2301 if (!m_object || !attribute || !parameter)
2304 if (![self updateObjectBackingStore])
2307 // common parameter type check/casting. Nil checks in handlers catch wrong type case.
2308 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
2309 // a parameter of the wrong type.
2310 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
2311 textMarker = (WebCoreTextMarker*) parameter;
2313 else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
2314 textMarkerRange = (WebCoreTextMarkerRange*) parameter;
2316 else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
2317 uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
2319 else if ([parameter isKindOfClass:[NSNumber self]])
2322 else if ([parameter isKindOfClass:[NSArray self]])
2325 else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2327 point = [(NSValue*)parameter pointValue];
2329 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2331 range = [(NSValue*)parameter rangeValue];
2333 // Attribute type is not supported. Allow super to handle.
2334 return [super accessibilityAttributeValue:attribute forParameter:parameter];
2338 if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
2339 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2340 AccessibilityObject* axObject = m_object->accessibilityObjectForPosition(visiblePos);
2343 return axObject->wrapper();
2346 if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
2347 VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
2348 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2351 if ([attribute isEqualToString:@"AXLineForTextMarker"]) {
2352 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2353 return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
2356 if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) {
2357 VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine([number intValue]);
2358 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2361 if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) {
2362 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2363 return m_object->stringForVisiblePositionRange(visiblePosRange);
2366 if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
2367 IntPoint webCorePoint = IntPoint(point);
2368 return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil;
2371 if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
2372 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2373 NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
2374 return [NSValue valueWithRect:rect];
2377 if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2378 VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2379 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2380 if (start.isNull() || end.isNull())
2382 NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
2383 return [NSValue valueWithRect:rect];
2386 if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
2387 VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2388 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2389 if (start.isNull() || end.isNull())
2391 return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
2394 if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
2395 return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
2397 if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
2398 if ([array count] < 2)
2401 WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
2402 WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
2403 if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1]
2404 || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
2407 VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:(textMarker1)];
2408 VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:(textMarker2)];
2409 VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
2410 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2413 if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
2414 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2415 return [self textMarkerForVisiblePosition:m_object->nextVisiblePosition(visiblePos)];
2418 if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
2419 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2420 return [self textMarkerForVisiblePosition:m_object->previousVisiblePosition(visiblePos)];
2423 if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
2424 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2425 VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
2426 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2429 if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
2430 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2431 VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
2432 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2435 if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
2436 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2437 VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
2438 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2441 if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"]) {
2442 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2443 VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
2444 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2447 if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
2448 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2449 VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
2450 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2453 if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
2454 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2455 VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
2456 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2459 if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
2460 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2461 return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
2464 if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
2465 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2466 return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
2469 if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
2470 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2471 return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)];
2474 if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) {
2475 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2476 return [self textMarkerForVisiblePosition:m_object->previousLineStartPosition(visiblePos)];
2479 if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
2480 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2481 return [self textMarkerForVisiblePosition:m_object->nextSentenceEndPosition(visiblePos)];
2484 if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
2485 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2486 return [self textMarkerForVisiblePosition:m_object->previousSentenceStartPosition(visiblePos)];
2489 if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
2490 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2491 return [self textMarkerForVisiblePosition:m_object->nextParagraphEndPosition(visiblePos)];
2494 if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
2495 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2496 return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)];
2499 if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
2500 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2501 VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
2502 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2505 if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
2506 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2507 int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
2510 return [NSNumber numberWithInt:length];
2513 // Used only by DumpRenderTree (so far).
2514 if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) {
2515 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2516 return [self textMarkerForVisiblePosition:visiblePosRange.start];
2519 if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) {
2520 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2521 return [self textMarkerForVisiblePosition:visiblePosRange.end];
2524 if (m_object->isDataTable()) {
2525 if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
2526 if (array == nil || [array count] != 2)
2528 AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
2532 return cell->wrapper();
2536 if (m_object->isTextControl()) {
2537 if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
2538 int lineNumber = m_object->doAXLineForIndex([number intValue]);
2541 return [NSNumber numberWithUnsignedInt:lineNumber];
2544 if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
2545 PlainTextRange textRange = m_object->doAXRangeForLine([number intValue]);
2546 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2549 if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) {
2550 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2551 return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
2554 if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
2557 IntPoint webCorePoint = IntPoint(point);
2558 PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
2559 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2562 if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
2563 PlainTextRange textRange = m_object->doAXRangeForIndex([number intValue]);
2564 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2567 if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
2570 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2571 NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
2572 return [NSValue valueWithRect:rect];
2575 if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2576 return rangeSet ? [self doAXRTFForRange:range] : nil;
2578 if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2579 return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
2581 if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
2582 PlainTextRange textRange = m_object->doAXStyleRangeForIndex([number intValue]);
2583 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2587 // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
2588 // In that case it must be passed to super.
2589 return [super accessibilityAttributeValue:attribute forParameter:parameter];
2592 - (BOOL)accessibilityShouldUseUniqueId
2594 return m_object->accessibilityShouldUseUniqueId();
2597 // API that AppKit uses for faster access
2598 - (NSUInteger)accessibilityIndexOfChild:(id)child
2600 if (![self updateObjectBackingStore])
2603 // Tree objects return their rows as their children. We can use the original method
2604 // here, because we won't gain any speed up.
2605 if (m_object->isTree())
2606 return [super accessibilityIndexOfChild:child];
2608 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2610 if (children.isEmpty())
2611 return [[self renderWidgetChildren] indexOfObject:child];
2613 unsigned count = children.size();
2614 for (unsigned k = 0; k < count; ++k) {
2615 AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
2616 if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child))
2623 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
2625 if (![self updateObjectBackingStore])
2628 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2629 // Tree items object returns a different set of children than those that are in children()
2630 // because an AXOutline (the mac role is becomes) has some odd stipulations.
2631 if (m_object->isTree() || m_object->isTreeItem())
2632 return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
2634 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2635 if (children.isEmpty())
2636 return [[self renderWidgetChildren] count];
2638 return children.size();
2641 return [super accessibilityArrayAttributeCount:attribute];
2644 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
2646 if (![self updateObjectBackingStore])
2649 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2650 if (m_object->children().isEmpty()) {
2651 NSArray *children = [self renderWidgetChildren];
2655 NSUInteger childCount = [children count];
2656 if (index >= childCount)
2659 NSUInteger arrayLength = min(childCount - index, maxCount);
2660 return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
2661 } else if (m_object->isTree()) {
2662 // Tree objects return their rows as their children. We can use the original method in this case.
2663 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2666 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2667 unsigned childCount = children.size();
2668 if (index >= childCount)
2671 unsigned available = min(childCount - index, maxCount);
2673 NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
2674 for (unsigned added = 0; added < available; ++index, ++added) {
2675 AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
2677 // The attachment view should be returned, otherwise AX palindrome errors occur.
2678 if (children[index]->isAttachment() && [wrapper attachmentView])
2679 [subarray addObject:[wrapper attachmentView]];
2681 [subarray addObject:wrapper];
2688 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2691 // This is set by DRT when it wants to listen for notifications.
2692 static BOOL accessibilityShouldRepostNotifications;
2693 - (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
2695 accessibilityShouldRepostNotifications = repost;
2698 - (void)accessibilityPostedNotification:(NSString *)notificationName
2700 if (accessibilityShouldRepostNotifications) {
2701 NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", nil];
2702 [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:nil userInfo:userInfo];
2708 #endif // HAVE(ACCESSIBILITY)