2 * Copyright (C) 2008, 2009, 2010, 2011 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 "AccessibilityScrollView.h"
40 #import "AccessibilityTable.h"
41 #import "AccessibilityTableCell.h"
42 #import "AccessibilityTableRow.h"
43 #import "AccessibilityTableColumn.h"
47 #import "FrameLoaderClient.h"
48 #import "HTMLAnchorElement.h"
49 #import "HTMLAreaElement.h"
50 #import "HTMLFrameOwnerElement.h"
51 #import "HTMLImageElement.h"
52 #import "HTMLInputElement.h"
53 #import "HTMLTextAreaElement.h"
54 #import "LocalizedStrings.h"
55 #import "RenderTextControl.h"
56 #import "RenderView.h"
57 #import "RenderWidget.h"
58 #import "ScrollView.h"
59 #import "SelectionController.h"
60 #import "SimpleFontData.h"
61 #import "TextCheckerClient.h"
62 #import "TextIterator.h"
63 #import "WebCoreFrameView.h"
64 #import "WebCoreObjCExtras.h"
65 #import "WebCoreSystemInterface.h"
66 #import "htmlediting.h"
67 #import "visible_units.h"
69 using namespace WebCore;
70 using namespace HTMLNames;
74 #ifndef NSAccessibilitySelectedCellsAttribute
75 #define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
78 #ifndef NSAccessibilityVisibleCellsAttribute
79 #define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
82 #ifndef NSAccessibilityRowHeaderUIElementsAttribute
83 #define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements"
86 #ifndef NSAccessibilityRowIndexRangeAttribute
87 #define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
90 #ifndef NSAccessibilityColumnIndexRangeAttribute
91 #define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
94 #ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
95 #define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
98 #ifndef NSAccessibilityCellRole
99 #define NSAccessibilityCellRole @"AXCell"
103 #ifndef NSAccessibilityContentListSubrole
104 #define NSAccessibilityContentListSubrole @"AXContentList"
107 #ifndef NSAccessibilityDefinitionListSubrole
108 #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
112 #ifndef NSAccessibilityBlockQuoteLevelAttribute
113 #define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
116 #ifndef NSAccessibilityAccessKeyAttribute
117 #define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
120 #ifndef NSAccessibilityLanguageAttribute
121 #define NSAccessibilityLanguageAttribute @"AXLanguage"
124 #ifndef NSAccessibilityRequiredAttribute
125 #define NSAccessibilityRequiredAttribute @"AXRequired"
128 #ifndef NSAccessibilityInvalidAttribute
129 #define NSAccessibilityInvalidAttribute @"AXInvalid"
132 #ifndef NSAccessibilityOwnsAttribute
133 #define NSAccessibilityOwnsAttribute @"AXOwns"
136 #ifndef NSAccessibilityGrabbedAttribute
137 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
140 #ifndef NSAccessibilityDropEffectsAttribute
141 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
144 #ifndef NSAccessibilityARIALiveAttribute
145 #define NSAccessibilityARIALiveAttribute @"AXARIALive"
148 #ifndef NSAccessibilityARIAAtomicAttribute
149 #define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
152 #ifndef NSAccessibilityARIARelevantAttribute
153 #define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
156 #ifndef NSAccessibilityARIABusyAttribute
157 #define NSAccessibilityARIABusyAttribute @"AXARIABusy"
160 #ifndef NSAccessibilityLoadingProgressAttribute
161 #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
164 #ifndef NSAccessibilityHasPopupAttribute
165 #define NSAccessibilityHasPopupAttribute @"AXHasPopup"
168 #ifndef NSAccessibilityPlaceholderValueAttribute
169 #define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
172 #ifdef BUILDING_ON_TIGER
173 typedef unsigned NSUInteger;
174 #define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
175 #define NSAccessibilityTimelineSubrole @"AXTimeline"
178 @interface NSObject (WebKitAccessibilityArrayCategory)
180 - (NSUInteger)accessibilityIndexOfChild:(id)child;
181 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
182 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
186 @implementation AccessibilityObjectWrapper
188 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
196 - (void)unregisterUniqueIdForUIElement
198 wkUnregisterUniqueIdForElement(self);
203 // Send unregisterUniqueIdForUIElement unconditionally because if it is
204 // ever accidentally not done (via other bugs in our AX implementation) you
205 // end up with a crash like <rdar://problem/4273149>. It is safe and not
206 // expensive to send even if the object is not registered.
207 [self unregisterUniqueIdForUIElement];
211 - (BOOL)updateObjectBackingStore
213 // Calling updateBackingStore() can invalidate this element so self must be retained.
214 // If it does become invalidated, m_object will be nil.
215 [[self retain] autorelease];
220 m_object->updateBackingStore();
227 - (AccessibilityObject*)accessibilityObject
232 - (NSView*)attachmentView
234 ASSERT(m_object->isAttachment());
235 Widget* widget = m_object->widgetForAttachmentView();
238 return NSAccessibilityUnignoredDescendant(widget->platformWidget());
241 #pragma mark SystemInterface wrappers
243 static inline id CFAutoreleaseHelper(CFTypeRef obj)
246 CFMakeCollectable(obj);
247 [(id)obj autorelease];
251 static inline BOOL AXObjectIsTextMarker(id obj)
253 return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerTypeID();
256 static inline BOOL AXObjectIsTextMarkerRange(id obj)
258 return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerRangeTypeID();
261 static id AXTextMarkerRange(id startMarker, id endMarker)
263 ASSERT(startMarker != nil);
264 ASSERT(endMarker != nil);
265 ASSERT(CFGetTypeID(startMarker) == wkGetAXTextMarkerTypeID());
266 ASSERT(CFGetTypeID(endMarker) == wkGetAXTextMarkerTypeID());
267 return CFAutoreleaseHelper(wkCreateAXTextMarkerRange((CFTypeRef)startMarker, (CFTypeRef)endMarker));
270 static id AXTextMarkerRangeStart(id range)
272 ASSERT(range != nil);
273 ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
274 return CFAutoreleaseHelper(wkCopyAXTextMarkerRangeStart(range));
277 static id AXTextMarkerRangeEnd(id range)
279 ASSERT(range != nil);
280 ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
281 return CFAutoreleaseHelper(wkCopyAXTextMarkerRangeEnd(range));
284 #pragma mark Text Marker helpers
286 static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
290 TextMarkerData textMarkerData;
291 cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
292 if (!textMarkerData.axID)
295 return CFAutoreleaseHelper(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
298 - (id)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos
300 return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos);
303 static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, CFTypeRef textMarker)
308 return VisiblePosition();
309 TextMarkerData textMarkerData;
310 if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
311 return VisiblePosition();
313 return cache->visiblePositionForTextMarkerData(textMarkerData);
316 - (VisiblePosition)visiblePositionForTextMarker:(id)textMarker
318 return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker);
321 static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
323 return visiblePositionForTextMarker(cache, AXTextMarkerRangeStart(textMarkerRange));
326 static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
328 return visiblePositionForTextMarker(cache, AXTextMarkerRangeEnd(textMarkerRange));
331 static id textMarkerRangeFromMarkers(id textMarker1, id textMarker2)
333 if (!textMarker1 || !textMarker2)
336 return AXTextMarkerRange(textMarker1, textMarker2);
339 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
344 dict = [NSDictionary dictionaryWithObjectsAndKeys:
345 [font fontName] , NSAccessibilityFontNameKey,
346 [font familyName] , NSAccessibilityFontFamilyKey,
347 [font displayName] , NSAccessibilityVisibleNameKey,
348 [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
351 [attrString addAttribute:attribute value:dict range:range];
353 [attrString removeAttribute:attribute range:range];
357 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
359 // get color information assuming NSDeviceRGBColorSpace
360 NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
362 rgbColor = [NSColor blackColor];
363 CGFloat components[4];
364 [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
366 // create a new CGColorRef to return
367 CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
368 CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
369 CGColorSpaceRelease(cgColorSpace);
371 // check for match with existing color
372 if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
373 CGColorRelease(cgColor);
380 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
383 CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
384 CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
386 [attrString addAttribute:attribute value:(id)cgColor range:range];
387 CGColorRelease(cgColor);
390 [attrString removeAttribute:attribute range:range];
393 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
396 [attrString addAttribute:attribute value:number range:range];
398 [attrString removeAttribute:attribute range:range];
401 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
403 RenderStyle* style = renderer->style();
405 // set basic font info
406 AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
409 AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyColor)), range);
410 AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)), range);
412 // set super/sub scripting
413 EVerticalAlign alignment = style->verticalAlign();
414 if (alignment == SUB)
415 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
416 else if (alignment == SUPER)
417 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
419 [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
422 if (style->textShadow())
423 AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
425 [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
427 // set underline and strikethrough
428 int decor = style->textDecorationsInEffect();
429 if ((decor & UNDERLINE) == 0) {
430 [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
431 [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
434 if ((decor & LINE_THROUGH) == 0) {
435 [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
436 [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
439 if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
440 // find colors using quirk mode approach (strict mode would use current
441 // color for all but the root line box, which would use getTextDecorationColors)
442 Color underline, overline, linethrough;
443 renderer->getTextDecorationColors(decor, underline, overline, linethrough);
445 if ((decor & UNDERLINE) != 0) {
446 AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
447 AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
450 if ((decor & LINE_THROUGH) != 0) {
451 AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
452 AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
457 static int blockquoteLevel(RenderObject* renderer)
463 for (Node* node = renderer->node(); node; node = node->parentNode()) {
464 if (node->hasTagName(blockquoteTag))
471 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
473 int quoteLevel = blockquoteLevel(renderer);
476 [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
478 [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
481 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int charLength, NSRange range)
483 // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
484 int currentPosition = 0;
485 while (charLength > 0) {
486 const UChar* charData = chars + currentPosition;
487 TextCheckerClient* checker = node->document()->frame()->editor()->textChecker();
489 int misspellingLocation = -1;
490 int misspellingLength = 0;
491 checker->checkSpellingOfString(charData, charLength, &misspellingLocation, &misspellingLength);
492 if (misspellingLocation == -1 || !misspellingLength)
495 NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
496 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
497 charLength -= (misspellingLocation + misspellingLength);
498 currentPosition += (misspellingLocation + misspellingLength);
502 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
507 AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent());
508 int parentHeadingLevel = parentObject->headingLevel();
510 if (parentHeadingLevel)
511 [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
513 [attrString removeAttribute:@"AXHeadingLevel" range:range];
516 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
518 if (object && object->isAccessibilityRenderObject()) {
519 // make a serializable AX object
521 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
525 Document* doc = renderer->document();
529 AXObjectCache* cache = doc->axObjectCache();
533 AXUIElementRef axElement = wkCreateAXUIElementRef(object->wrapper());
535 [attrString addAttribute:attribute value:(id)axElement range:range];
536 CFRelease(axElement);
539 [attrString removeAttribute:attribute range:range];
542 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length)
544 // skip invisible text
545 if (!node->renderer())
548 // easier to calculate the range before appending the string
549 NSRange attrStringRange = NSMakeRange([attrString length], length);
551 // append the string from this node
552 [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
554 // add new attributes and remove irrelevant inherited ones
555 // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
556 // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means
557 // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
559 // remove inherited attachment from prior AXAttributedStringAppendReplaced
560 [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
561 [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
563 // set new attributes
564 AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
565 AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
566 AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
567 AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
569 // do spelling last because it tends to break up the range
570 AXAttributeStringSetSpelling(attrString, node, chars, length, attrStringRange);
573 static NSString* nsStringForReplacedNode(Node* replacedNode)
575 // we should always be given a rendered node and a replaced node, but be safe
576 // replaced nodes are either attachments (widgets) or images
577 if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
578 ASSERT_NOT_REACHED();
582 // create an AX object, but skip it if it is not supposed to be seen
583 RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
584 if (obj->accessibilityIsIgnored())
587 // use the attachmentCharacter to represent the replaced node
588 const UniChar attachmentChar = NSAttachmentCharacter;
589 return [NSString stringWithCharacters:&attachmentChar length:1];
592 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(id)textMarkerRange
597 // extract the start and end VisiblePosition
598 VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
599 if (startVisiblePosition.isNull())
602 VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
603 if (endVisiblePosition.isNull())
606 VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
607 // iterate over the range to build the AX attributed string
608 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
609 TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
610 while (!it.atEnd()) {
611 // locate the node and starting offset for this range
613 Node* node = it.range()->startContainer(exception);
614 ASSERT(node == it.range()->endContainer(exception));
615 int offset = it.range()->startOffset(exception);
617 // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
618 if (it.length() != 0) {
619 // Add the text of the list marker item if necessary.
620 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
621 if (!listMarkerText.isEmpty())
622 AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length());
624 AXAttributedStringAppendText(attrString, node, it.characters(), it.length());
626 Node* replacedNode = node->childNode(offset);
627 NSString *attachmentString = nsStringForReplacedNode(replacedNode);
628 if (attachmentString) {
629 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
631 // append the placeholder string
632 [[attrString mutableString] appendString:attachmentString];
634 // remove all inherited attributes
635 [attrString setAttributes:nil range:attrStringRange];
637 // add the attachment attribute
638 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
639 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
645 return [attrString autorelease];
648 static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosition startPosition, VisiblePosition endPosition)
650 id startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
651 id endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
652 return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
655 - (id)textMarkerRangeFromVisiblePositions:(VisiblePosition)startPosition endPosition:(VisiblePosition)endPosition
657 return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition);
660 - (NSArray*)accessibilityActionNames
662 if (![self updateObjectBackingStore])
665 static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
666 static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
667 static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
668 static NSArray* sliderActions = [[NSArray alloc] initWithObjects: NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil];
671 if (m_object->actionElement())
672 actions = actionElementActions;
673 else if (m_object->isMenuRelated())
674 actions = menuElementActions;
675 else if (m_object->isSlider())
676 actions = sliderActions;
677 else if (m_object->isAttachment())
678 actions = [[self attachmentView] accessibilityActionNames];
680 actions = defaultElementActions;
685 - (NSArray*)additionalAccessibilityAttributeNames
690 NSMutableArray *additional = [NSMutableArray array];
691 if (m_object->supportsARIAOwns())
692 [additional addObject:NSAccessibilityOwnsAttribute];
694 if (m_object->supportsARIAExpanded())
695 [additional addObject:NSAccessibilityExpandedAttribute];
697 if (m_object->isScrollbar())
698 [additional addObject:NSAccessibilityOrientationAttribute];
700 if (m_object->supportsARIADragging())
701 [additional addObject:NSAccessibilityGrabbedAttribute];
703 if (m_object->supportsARIADropping())
704 [additional addObject:NSAccessibilityDropEffectsAttribute];
706 if (m_object->isAccessibilityTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows())
707 [additional addObject:NSAccessibilitySelectedRowsAttribute];
709 if (m_object->supportsARIALiveRegion()) {
710 [additional addObject:NSAccessibilityARIALiveAttribute];
711 [additional addObject:NSAccessibilityARIARelevantAttribute];
714 if (m_object->sortDirection() != SortDirectionNone)
715 [additional addObject:NSAccessibilitySortDirectionAttribute];
717 // If an object is a child of a live region, then add these
718 if (m_object->isInsideARIALiveRegion()) {
719 [additional addObject:NSAccessibilityARIAAtomicAttribute];
720 [additional addObject:NSAccessibilityARIABusyAttribute];
723 if (m_object->ariaHasPopup())
724 [additional addObject:NSAccessibilityHasPopupAttribute];
729 - (NSArray*)accessibilityAttributeNames
731 if (![self updateObjectBackingStore])
734 if (m_object->isAttachment())
735 return [[self attachmentView] accessibilityAttributeNames];
737 static NSArray* attributes = nil;
738 static NSArray* anchorAttrs = nil;
739 static NSArray* webAreaAttrs = nil;
740 static NSArray* textAttrs = nil;
741 static NSArray* listAttrs = nil;
742 static NSArray* listBoxAttrs = nil;
743 static NSArray* rangeAttrs = nil;
744 static NSArray* commonMenuAttrs = nil;
745 static NSArray* menuAttrs = nil;
746 static NSArray* menuBarAttrs = nil;
747 static NSArray* menuItemAttrs = nil;
748 static NSArray* menuButtonAttrs = nil;
749 static NSArray* controlAttrs = nil;
750 static NSArray* tableAttrs = nil;
751 static NSArray* tableRowAttrs = nil;
752 static NSArray* tableColAttrs = nil;
753 static NSArray* tableCellAttrs = nil;
754 static NSArray* groupAttrs = nil;
755 static NSArray* inputImageAttrs = nil;
756 static NSArray* passwordFieldAttrs = nil;
757 static NSArray* tabListAttrs = nil;
758 static NSArray* comboBoxAttrs = nil;
759 static NSArray* outlineAttrs = nil;
760 static NSArray* outlineRowAttrs = nil;
761 static NSArray* buttonAttrs = nil;
762 static NSArray* scrollViewAttrs = nil;
763 NSMutableArray* tempArray;
764 if (attributes == nil) {
765 attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
766 NSAccessibilitySubroleAttribute,
767 NSAccessibilityRoleDescriptionAttribute,
768 NSAccessibilityChildrenAttribute,
769 NSAccessibilityHelpAttribute,
770 NSAccessibilityParentAttribute,
771 NSAccessibilityPositionAttribute,
772 NSAccessibilitySizeAttribute,
773 NSAccessibilityTitleAttribute,
774 NSAccessibilityDescriptionAttribute,
775 NSAccessibilityValueAttribute,
776 NSAccessibilityFocusedAttribute,
777 NSAccessibilityEnabledAttribute,
778 NSAccessibilityWindowAttribute,
779 @"AXSelectedTextMarkerRange",
780 @"AXStartTextMarker",
783 NSAccessibilityLinkedUIElementsAttribute,
784 NSAccessibilitySelectedAttribute,
785 NSAccessibilityBlockQuoteLevelAttribute,
786 NSAccessibilityTopLevelUIElementAttribute,
789 if (commonMenuAttrs == nil) {
790 commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
791 NSAccessibilityRoleDescriptionAttribute,
792 NSAccessibilityChildrenAttribute,
793 NSAccessibilityParentAttribute,
794 NSAccessibilityEnabledAttribute,
795 NSAccessibilityPositionAttribute,
796 NSAccessibilitySizeAttribute,
799 if (anchorAttrs == nil) {
800 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
801 [tempArray addObject:NSAccessibilityURLAttribute];
802 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
803 anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
806 if (webAreaAttrs == nil) {
807 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
808 [tempArray addObject:@"AXLinkUIElements"];
809 [tempArray addObject:@"AXLoaded"];
810 [tempArray addObject:@"AXLayoutCount"];
811 [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
812 [tempArray addObject:NSAccessibilityURLAttribute];
813 webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
816 if (textAttrs == nil) {
817 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
818 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
819 [tempArray addObject:NSAccessibilitySelectedTextAttribute];
820 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
821 [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
822 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
823 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
824 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
825 [tempArray addObject:NSAccessibilityRequiredAttribute];
826 [tempArray addObject:NSAccessibilityInvalidAttribute];
827 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
828 textAttrs = [[NSArray alloc] initWithArray:tempArray];
831 if (listAttrs == nil) {
832 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
833 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
834 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
835 [tempArray addObject:NSAccessibilityOrientationAttribute];
836 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
837 listAttrs = [[NSArray alloc] initWithArray:tempArray];
840 if (listBoxAttrs == nil) {
841 tempArray = [[NSMutableArray alloc] initWithArray:listAttrs];
842 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
843 [tempArray addObject:NSAccessibilityRequiredAttribute];
844 [tempArray addObject:NSAccessibilityInvalidAttribute];
845 listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
848 if (rangeAttrs == nil) {
849 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
850 [tempArray addObject:NSAccessibilityMinValueAttribute];
851 [tempArray addObject:NSAccessibilityMaxValueAttribute];
852 [tempArray addObject:NSAccessibilityOrientationAttribute];
853 [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
854 rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
857 if (menuBarAttrs == nil) {
858 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
859 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
860 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
861 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
862 menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
865 if (menuAttrs == nil) {
866 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
867 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
868 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
869 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
870 menuAttrs = [[NSArray alloc] initWithArray:tempArray];
873 if (menuItemAttrs == nil) {
874 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
875 [tempArray addObject:NSAccessibilityTitleAttribute];
876 [tempArray addObject:NSAccessibilityHelpAttribute];
877 [tempArray addObject:NSAccessibilitySelectedAttribute];
878 [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
879 [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
880 [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
881 [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
882 [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
883 [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
884 [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
885 menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
888 if (menuButtonAttrs == nil) {
889 menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
890 NSAccessibilityRoleDescriptionAttribute,
891 NSAccessibilityParentAttribute,
892 NSAccessibilityPositionAttribute,
893 NSAccessibilitySizeAttribute,
894 NSAccessibilityWindowAttribute,
895 NSAccessibilityEnabledAttribute,
896 NSAccessibilityFocusedAttribute,
897 NSAccessibilityTitleAttribute,
898 NSAccessibilityChildrenAttribute, nil];
900 if (controlAttrs == nil) {
901 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
902 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
903 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
904 [tempArray addObject:NSAccessibilityRequiredAttribute];
905 [tempArray addObject:NSAccessibilityInvalidAttribute];
906 controlAttrs = [[NSArray alloc] initWithArray:tempArray];
909 if (buttonAttrs == nil) {
910 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
911 // Buttons should not expose AXValue.
912 [tempArray removeObject:NSAccessibilityValueAttribute];
913 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
914 [tempArray addObject:NSAccessibilityAccessKeyAttribute];
915 buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
918 if (comboBoxAttrs == nil) {
919 tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
920 [tempArray addObject:NSAccessibilityExpandedAttribute];
921 comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
924 if (tableAttrs == nil) {
925 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
926 [tempArray addObject:NSAccessibilityRowsAttribute];
927 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
928 [tempArray addObject:NSAccessibilityColumnsAttribute];
929 [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
930 [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
931 [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
932 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
933 [tempArray addObject:NSAccessibilityHeaderAttribute];
934 tableAttrs = [[NSArray alloc] initWithArray:tempArray];
937 if (tableRowAttrs == nil) {
938 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
939 [tempArray addObject:NSAccessibilityIndexAttribute];
940 tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
943 if (tableColAttrs == nil) {
944 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
945 [tempArray addObject:NSAccessibilityIndexAttribute];
946 [tempArray addObject:NSAccessibilityHeaderAttribute];
947 [tempArray addObject:NSAccessibilityRowsAttribute];
948 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
949 tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
952 if (tableCellAttrs == nil) {
953 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
954 [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
955 [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
956 tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
959 if (groupAttrs == nil) {
960 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
961 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
962 groupAttrs = [[NSArray alloc] initWithArray:tempArray];
965 if (inputImageAttrs == nil) {
966 tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
967 [tempArray addObject:NSAccessibilityURLAttribute];
968 inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
971 if (passwordFieldAttrs == nil) {
972 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
973 [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
974 [tempArray addObject:NSAccessibilityRequiredAttribute];
975 [tempArray addObject:NSAccessibilityInvalidAttribute];
976 passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
979 if (tabListAttrs == nil) {
980 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
981 [tempArray addObject:NSAccessibilityTabsAttribute];
982 [tempArray addObject:NSAccessibilityContentsAttribute];
983 tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
986 if (outlineAttrs == nil) {
987 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
988 [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
989 [tempArray addObject:NSAccessibilityRowsAttribute];
990 [tempArray addObject:NSAccessibilityColumnsAttribute];
991 outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
994 if (outlineRowAttrs == nil) {
995 tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
996 [tempArray addObject:NSAccessibilityDisclosingAttribute];
997 [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
998 [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
999 [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1000 outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1001 [tempArray release];
1003 if (scrollViewAttrs == nil) {
1004 tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1005 [tempArray addObject:NSAccessibilityContentsAttribute];
1006 [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1007 [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1008 scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray];
1009 [tempArray release];
1012 NSArray *objectAttributes = attributes;
1014 if (m_object->isPasswordField())
1015 objectAttributes = passwordFieldAttrs;
1017 else if (m_object->isWebArea())
1018 objectAttributes = webAreaAttrs;
1020 else if (m_object->isTextControl())
1021 objectAttributes = textAttrs;
1023 else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
1024 objectAttributes = anchorAttrs;
1026 else if (m_object->isAccessibilityTable())
1027 objectAttributes = tableAttrs;
1028 else if (m_object->isTableColumn())
1029 objectAttributes = tableColAttrs;
1030 else if (m_object->isTableCell())
1031 objectAttributes = tableCellAttrs;
1032 else if (m_object->isTableRow()) {
1033 // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1034 if (m_object->isARIATreeGridRow())
1035 objectAttributes = outlineRowAttrs;
1037 objectAttributes = tableRowAttrs;
1040 else if (m_object->isTree())
1041 objectAttributes = outlineAttrs;
1042 else if (m_object->isTreeItem())
1043 objectAttributes = outlineRowAttrs;
1045 else if (m_object->isListBox())
1046 objectAttributes = listBoxAttrs;
1047 else if (m_object->isList())
1048 objectAttributes = listAttrs;
1050 else if (m_object->isComboBox())
1051 objectAttributes = comboBoxAttrs;
1053 else if (m_object->isProgressIndicator() || m_object->isSlider())
1054 objectAttributes = rangeAttrs;
1056 // These are processed in order because an input image is a button, and a button is a control.
1057 else if (m_object->isInputImage())
1058 objectAttributes = inputImageAttrs;
1059 else if (m_object->isButton())
1060 objectAttributes = buttonAttrs;
1061 else if (m_object->isControl())
1062 objectAttributes = controlAttrs;
1064 else if (m_object->isGroup() || m_object->isListItem())
1065 objectAttributes = groupAttrs;
1066 else if (m_object->isTabList())
1067 objectAttributes = tabListAttrs;
1068 else if (m_object->isScrollView())
1069 objectAttributes = scrollViewAttrs;
1071 else if (m_object->isMenu())
1072 objectAttributes = menuAttrs;
1073 else if (m_object->isMenuBar())
1074 objectAttributes = menuBarAttrs;
1075 else if (m_object->isMenuButton())
1076 objectAttributes = menuButtonAttrs;
1077 else if (m_object->isMenuItem())
1078 objectAttributes = menuItemAttrs;
1080 NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1081 if ([additionalAttributes count])
1082 objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1084 return objectAttributes;
1087 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange
1089 if (!textMarkerRange)
1090 return VisiblePositionRange();
1091 AXObjectCache* cache = m_object->axObjectCache();
1092 return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1095 - (NSArray*)renderWidgetChildren
1097 Widget* widget = m_object->widget();
1100 return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1103 - (id)remoteAccessibilityParentObject
1105 if (!m_object || !m_object->document())
1108 return m_object->document()->frame()->loader()->client()->accessibilityRemoteObject();
1111 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1113 unsigned length = [array count];
1114 vector.reserveInitialCapacity(length);
1115 for (unsigned i = 0; i < length; ++i) {
1116 AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1122 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1124 unsigned length = vector.size();
1125 NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
1126 for (unsigned i = 0; i < length; ++i) {
1127 AccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
1130 // we want to return the attachment view instead of the object representing the attachment.
1131 // otherwise, we get palindrome errors in the AX hierarchy
1132 if (vector[i]->isAttachment() && [wrapper attachmentView])
1133 [array addObject:[wrapper attachmentView]];
1135 [array addObject:wrapper];
1141 - (id)textMarkerRangeForSelection
1143 VisibleSelection selection = m_object->selection();
1144 if (selection.isNone())
1146 return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1149 - (NSValue*)position
1151 IntRect rect = m_object->elementRect();
1154 FrameView* frameView = m_object->documentFrameView();
1155 id remoteParent = [self remoteAccessibilityParentObject];
1157 point = NSMakePoint(rect.x(), rect.y());
1159 NSPoint remotePosition = [[remoteParent accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue];
1160 NSSize remoteSize = [[remoteParent accessibilityAttributeValue:NSAccessibilitySizeAttribute] sizeValue];
1162 // Get the y position of the WKView (we have to screen-flip and go from bottom left to top left).
1163 CGFloat screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
1164 remotePosition.y = (screenHeight - remotePosition.y) - remoteSize.height;
1166 NSPoint scrollPosition = NSMakePoint(0, 0);
1167 if (frameView && !m_object->isScrollbar() && !m_object->isScrollView()) {
1168 IntPoint frameScrollPos = frameView->scrollPosition();
1169 scrollPosition = NSMakePoint(frameScrollPos.x(), frameScrollPos.y());
1172 point.x += remotePosition.x - scrollPosition.x;
1173 // Set the new position, which means getting bottom y, and then flipping to screen coordinates.
1174 point.y = screenHeight - (point.y + remotePosition.y + rect.height() - scrollPosition.y);
1176 // The Cocoa accessibility API wants the lower-left corner.
1177 point = NSMakePoint(rect.x(), rect.maxY());
1180 NSView* view = frameView->documentView();
1181 point = [[view window] convertBaseToScreen:[view convertPoint: point toView:nil]];
1185 return [NSValue valueWithPoint:point];
1188 typedef HashMap<int, NSString*> AccessibilityRoleMap;
1190 static const AccessibilityRoleMap& createAccessibilityRoleMap()
1193 AccessibilityRole value;
1197 static const RoleEntry roles[] = {
1198 { UnknownRole, NSAccessibilityUnknownRole },
1199 { ButtonRole, NSAccessibilityButtonRole },
1200 { RadioButtonRole, NSAccessibilityRadioButtonRole },
1201 { CheckBoxRole, NSAccessibilityCheckBoxRole },
1202 { SliderRole, NSAccessibilitySliderRole },
1203 { TabGroupRole, NSAccessibilityTabGroupRole },
1204 { TextFieldRole, NSAccessibilityTextFieldRole },
1205 { StaticTextRole, NSAccessibilityStaticTextRole },
1206 { TextAreaRole, NSAccessibilityTextAreaRole },
1207 { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1208 { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1209 { MenuButtonRole, NSAccessibilityMenuButtonRole },
1210 { TableRole, NSAccessibilityTableRole },
1211 { ApplicationRole, NSAccessibilityApplicationRole },
1212 { GroupRole, NSAccessibilityGroupRole },
1213 { RadioGroupRole, NSAccessibilityRadioGroupRole },
1214 { ListRole, NSAccessibilityListRole },
1215 { DirectoryRole, NSAccessibilityListRole },
1216 { ScrollBarRole, NSAccessibilityScrollBarRole },
1217 { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1218 { ImageRole, NSAccessibilityImageRole },
1219 { MenuBarRole, NSAccessibilityMenuBarRole },
1220 { MenuRole, NSAccessibilityMenuRole },
1221 { MenuItemRole, NSAccessibilityMenuItemRole },
1222 { ColumnRole, NSAccessibilityColumnRole },
1223 { RowRole, NSAccessibilityRowRole },
1224 { ToolbarRole, NSAccessibilityToolbarRole },
1225 { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1226 { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1227 { WindowRole, NSAccessibilityWindowRole },
1228 { DrawerRole, NSAccessibilityDrawerRole },
1229 { SystemWideRole, NSAccessibilitySystemWideRole },
1230 { OutlineRole, NSAccessibilityOutlineRole },
1231 { IncrementorRole, NSAccessibilityIncrementorRole },
1232 { BrowserRole, NSAccessibilityBrowserRole },
1233 { ComboBoxRole, NSAccessibilityComboBoxRole },
1234 { SplitGroupRole, NSAccessibilitySplitGroupRole },
1235 { SplitterRole, NSAccessibilitySplitterRole },
1236 { ColorWellRole, NSAccessibilityColorWellRole },
1237 { GrowAreaRole, NSAccessibilityGrowAreaRole },
1238 { SheetRole, NSAccessibilitySheetRole },
1239 { HelpTagRole, NSAccessibilityHelpTagRole },
1240 { MatteRole, NSAccessibilityMatteRole },
1241 { RulerRole, NSAccessibilityRulerRole },
1242 { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1243 { LinkRole, NSAccessibilityLinkRole },
1244 #ifndef BUILDING_ON_TIGER
1245 { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1246 { GridRole, NSAccessibilityGridRole },
1248 { WebCoreLinkRole, NSAccessibilityLinkRole },
1249 { ImageMapLinkRole, NSAccessibilityLinkRole },
1250 { ImageMapRole, @"AXImageMap" },
1251 { ListMarkerRole, @"AXListMarker" },
1252 { WebAreaRole, @"AXWebArea" },
1253 { HeadingRole, @"AXHeading" },
1254 { ListBoxRole, NSAccessibilityListRole },
1255 { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1256 #if ACCESSIBILITY_TABLES
1257 { CellRole, NSAccessibilityCellRole },
1259 { CellRole, NSAccessibilityGroupRole },
1261 { TableHeaderContainerRole, NSAccessibilityGroupRole },
1262 { DefinitionListDefinitionRole, NSAccessibilityGroupRole },
1263 { DefinitionListTermRole, NSAccessibilityGroupRole },
1264 { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1265 { LandmarkApplicationRole, NSAccessibilityGroupRole },
1266 { LandmarkBannerRole, NSAccessibilityGroupRole },
1267 { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1268 { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1269 { LandmarkMainRole, NSAccessibilityGroupRole },
1270 { LandmarkNavigationRole, NSAccessibilityGroupRole },
1271 { LandmarkSearchRole, NSAccessibilityGroupRole },
1272 { ApplicationAlertRole, NSAccessibilityGroupRole },
1273 { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1274 { ApplicationDialogRole, NSAccessibilityGroupRole },
1275 { ApplicationLogRole, NSAccessibilityGroupRole },
1276 { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1277 { ApplicationStatusRole, NSAccessibilityGroupRole },
1278 { ApplicationTimerRole, NSAccessibilityGroupRole },
1279 { DocumentRole, NSAccessibilityGroupRole },
1280 { DocumentArticleRole, NSAccessibilityGroupRole },
1281 { DocumentMathRole, NSAccessibilityGroupRole },
1282 { DocumentNoteRole, NSAccessibilityGroupRole },
1283 { DocumentRegionRole, NSAccessibilityGroupRole },
1284 { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1285 { TabRole, NSAccessibilityRadioButtonRole },
1286 { TabListRole, NSAccessibilityTabGroupRole },
1287 { TabPanelRole, NSAccessibilityGroupRole },
1288 { TreeRole, NSAccessibilityOutlineRole },
1289 { TreeItemRole, NSAccessibilityRowRole },
1290 { ListItemRole, NSAccessibilityGroupRole },
1291 { ParagraphRole, NSAccessibilityGroupRole },
1292 { LabelRole, NSAccessibilityGroupRole },
1293 { DivRole, NSAccessibilityGroupRole },
1294 { FormRole, NSAccessibilityGroupRole }
1296 AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1298 const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1299 for (unsigned i = 0; i < numRoles; ++i)
1300 roleMap.set(roles[i].value, roles[i].string);
1304 static NSString* roleValueToNSString(AccessibilityRole value)
1307 static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1308 return roleMap.get(value);
1313 if (m_object->isAttachment())
1314 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1315 NSString* string = roleValueToNSString(m_object->roleValue());
1318 return NSAccessibilityUnknownRole;
1321 - (NSString*)subrole
1323 if (m_object->isPasswordField())
1324 return NSAccessibilitySecureTextFieldSubrole;
1326 if (m_object->isAttachment()) {
1327 NSView* attachView = [self attachmentView];
1328 if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1329 return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1333 if (m_object->isTreeItem())
1334 return NSAccessibilityOutlineRowSubrole;
1336 if (m_object->isList()) {
1337 AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
1338 if (listObject->isUnorderedList() || listObject->isOrderedList())
1339 return NSAccessibilityContentListSubrole;
1340 if (listObject->isDefinitionList())
1341 return NSAccessibilityDefinitionListSubrole;
1344 // ARIA content subroles.
1345 switch (m_object->roleValue()) {
1346 case LandmarkApplicationRole:
1347 return @"AXLandmarkApplication";
1348 case LandmarkBannerRole:
1349 return @"AXLandmarkBanner";
1350 case LandmarkComplementaryRole:
1351 return @"AXLandmarkComplementary";
1352 case LandmarkContentInfoRole:
1353 return @"AXLandmarkContentInfo";
1354 case LandmarkMainRole:
1355 return @"AXLandmarkMain";
1356 case LandmarkNavigationRole:
1357 return @"AXLandmarkNavigation";
1358 case LandmarkSearchRole:
1359 return @"AXLandmarkSearch";
1360 case ApplicationAlertRole:
1361 return @"AXApplicationAlert";
1362 case ApplicationAlertDialogRole:
1363 return @"AXApplicationAlertDialog";
1364 case ApplicationDialogRole:
1365 return @"AXApplicationDialog";
1366 case ApplicationLogRole:
1367 return @"AXApplicationLog";
1368 case ApplicationMarqueeRole:
1369 return @"AXApplicationMarquee";
1370 case ApplicationStatusRole:
1371 return @"AXApplicationStatus";
1372 case ApplicationTimerRole:
1373 return @"AXApplicationTimer";
1375 return @"AXDocument";
1376 case DocumentArticleRole:
1377 return @"AXDocumentArticle";
1378 case DocumentMathRole:
1379 return @"AXDocumentMath";
1380 case DocumentNoteRole:
1381 return @"AXDocumentNote";
1382 case DocumentRegionRole:
1383 return @"AXDocumentRegion";
1384 case UserInterfaceTooltipRole:
1385 return @"AXUserInterfaceTooltip";
1387 return @"AXTabPanel";
1388 case DefinitionListTermRole:
1390 case DefinitionListDefinitionRole:
1391 return @"AXDefinition";
1392 // Default doesn't return anything, so roles defined below can be chosen.
1397 if (m_object->isMediaTimeline())
1398 return NSAccessibilityTimelineSubrole;
1403 - (NSString*)roleDescription
1408 // attachments have the AXImage role, but a different subrole
1409 if (m_object->isAttachment())
1410 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1412 NSString* axRole = [self role];
1414 if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1415 switch (m_object->roleValue()) {
1417 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1418 case LandmarkApplicationRole:
1419 return AXARIAContentGroupText(@"ARIALandmarkApplication");
1420 case LandmarkBannerRole:
1421 return AXARIAContentGroupText(@"ARIALandmarkBanner");
1422 case LandmarkComplementaryRole:
1423 return AXARIAContentGroupText(@"ARIALandmarkComplementary");
1424 case LandmarkContentInfoRole:
1425 return AXARIAContentGroupText(@"ARIALandmarkContentInfo");
1426 case LandmarkMainRole:
1427 return AXARIAContentGroupText(@"ARIALandmarkMain");
1428 case LandmarkNavigationRole:
1429 return AXARIAContentGroupText(@"ARIALandmarkNavigation");
1430 case LandmarkSearchRole:
1431 return AXARIAContentGroupText(@"ARIALandmarkSearch");
1432 case ApplicationAlertRole:
1433 return AXARIAContentGroupText(@"ARIAApplicationAlert");
1434 case ApplicationAlertDialogRole:
1435 return AXARIAContentGroupText(@"ARIAApplicationAlertDialog");
1436 case ApplicationDialogRole:
1437 return AXARIAContentGroupText(@"ARIAApplicationDialog");
1438 case ApplicationLogRole:
1439 return AXARIAContentGroupText(@"ARIAApplicationLog");
1440 case ApplicationMarqueeRole:
1441 return AXARIAContentGroupText(@"ARIAApplicationMarquee");
1442 case ApplicationStatusRole:
1443 return AXARIAContentGroupText(@"ARIAApplicationStatus");
1444 case ApplicationTimerRole:
1445 return AXARIAContentGroupText(@"ARIAApplicationTimer");
1447 return AXARIAContentGroupText(@"ARIADocument");
1448 case DocumentArticleRole:
1449 return AXARIAContentGroupText(@"ARIADocumentArticle");
1450 case DocumentMathRole:
1451 return AXARIAContentGroupText(@"ARIADocumentMath");
1452 case DocumentNoteRole:
1453 return AXARIAContentGroupText(@"ARIADocumentNote");
1454 case DocumentRegionRole:
1455 return AXARIAContentGroupText(@"ARIADocumentRegion");
1456 case UserInterfaceTooltipRole:
1457 return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip");
1459 return AXARIAContentGroupText(@"ARIATabPanel");
1460 case DefinitionListTermRole:
1461 return AXDefinitionListTermText();
1462 case DefinitionListDefinitionRole:
1463 return AXDefinitionListDefinitionText();
1467 if ([axRole isEqualToString:@"AXWebArea"])
1468 return AXWebAreaText();
1470 if ([axRole isEqualToString:@"AXLink"])
1471 return AXLinkText();
1473 if ([axRole isEqualToString:@"AXListMarker"])
1474 return AXListMarkerText();
1476 if ([axRole isEqualToString:@"AXImageMap"])
1477 return AXImageMapText();
1479 if ([axRole isEqualToString:@"AXHeading"])
1480 return AXHeadingText();
1482 // AppKit also returns AXTab for the role description for a tab item.
1483 if (m_object->isTabItem())
1484 return NSAccessibilityRoleDescription(@"AXTab", nil);
1486 // We should try the system default role description for all other roles.
1487 // If we get the same string back, then as a last resort, return unknown.
1488 NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1489 if (![defaultRoleDescription isEqualToString:axRole])
1490 return defaultRoleDescription;
1492 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1495 - (id)scrollViewParent
1497 if (!m_object || !m_object->isAccessibilityScrollView())
1500 // If this scroll view provides it's parent object (because it's a sub-frame), then
1501 // we should not find the remoteAccessibilityParent.
1502 if (m_object->parentObject())
1505 AccessibilityScrollView* scrollView = toAccessibilityScrollView(m_object);
1506 ScrollView* scroll = scrollView->scrollView();
1510 if (scroll->platformWidget())
1511 return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
1513 return [self remoteAccessibilityParentObject];
1516 // FIXME: split up this function in a better way.
1517 // suggestions: Use a hash table that maps attribute names to function calls,
1518 // or maybe pointers to member functions
1519 - (id)accessibilityAttributeValue:(NSString*)attributeName
1521 if (![self updateObjectBackingStore])
1524 if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1527 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1528 return [self subrole];
1530 if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1531 return [self roleDescription];
1533 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1535 // This will return the parent of the AXWebArea, if this is a web area.
1536 id scrollViewParent = [self scrollViewParent];
1537 if (scrollViewParent)
1538 return scrollViewParent;
1540 // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1541 if (m_object->isTreeItem()) {
1542 AccessibilityObject* parent = m_object->parentObjectUnignored();
1544 if (parent->isTree())
1545 return parent->wrapper();
1546 parent = parent->parentObjectUnignored();
1550 AccessibilityObject* parent = m_object->parentObjectUnignored();
1554 // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
1555 // should be reported directly as such.
1556 if (m_object->isWebArea() && parent->isAttachment())
1557 return [parent->wrapper() attachmentView];
1559 return parent->wrapper();
1562 if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
1563 if (m_object->children().isEmpty()) {
1564 NSArray* children = [self renderWidgetChildren];
1565 if (children != nil)
1569 // The tree's (AXOutline) children are supposed to be its rows and columns.
1570 // The ARIA spec doesn't have columns, so we just need rows.
1571 if (m_object->isTree())
1572 return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1574 // A tree item should only expose its content as its children (not its rows)
1575 if (m_object->isTreeItem()) {
1576 AccessibilityObject::AccessibilityChildrenVector contentCopy;
1577 m_object->ariaTreeItemContent(contentCopy);
1578 return convertToNSArray(contentCopy);
1581 return convertToNSArray(m_object->children());
1584 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1585 if (m_object->isListBox()) {
1586 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1587 m_object->selectedChildren(selectedChildrenCopy);
1588 return convertToNSArray(selectedChildrenCopy);
1593 if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
1594 if (m_object->isListBox()) {
1595 AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
1596 m_object->visibleChildren(visibleChildrenCopy);
1597 return convertToNSArray(visibleChildrenCopy);
1599 else if (m_object->isList())
1600 return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1606 if (m_object->isWebArea()) {
1607 if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
1608 AccessibilityObject::AccessibilityChildrenVector links;
1609 static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
1610 return convertToNSArray(links);
1612 if ([attributeName isEqualToString:@"AXLoaded"])
1613 return [NSNumber numberWithBool:m_object->isLoaded()];
1614 if ([attributeName isEqualToString:@"AXLayoutCount"])
1615 return [NSNumber numberWithInt:m_object->layoutCount()];
1616 if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
1617 return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
1620 if (m_object->isTextControl()) {
1621 if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
1622 int length = m_object->textLength();
1625 return [NSNumber numberWithUnsignedInt:length];
1627 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
1628 String selectedText = m_object->selectedText();
1629 if (selectedText.isNull())
1631 return (NSString*)selectedText;
1633 if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
1634 PlainTextRange textRange = m_object->selectedTextRange();
1635 if (textRange.isNull())
1636 return [NSValue valueWithRange:NSMakeRange(0, 0)];
1637 return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
1639 // TODO: Get actual visible range. <rdar://problem/4712101>
1640 if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
1641 return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
1642 if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
1643 // if selectionEnd > 0, then there is selected text and this question should not be answered
1644 if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
1646 int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
1649 return [NSNumber numberWithInt:lineNumber];
1653 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1654 KURL url = m_object->url();
1660 if ([attributeName isEqualToString: @"AXVisited"])
1661 return [NSNumber numberWithBool: m_object->isVisited()];
1663 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1664 if (m_object->isAttachment()) {
1665 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
1666 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1668 return m_object->title();
1671 if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
1672 if (m_object->isAttachment()) {
1673 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1674 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1676 return m_object->accessibilityDescription();
1679 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
1680 if (m_object->isAttachment()) {
1681 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
1682 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
1684 if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar())
1685 return [NSNumber numberWithFloat:m_object->valueForRange()];
1686 if (m_object->roleValue() == SliderThumbRole)
1687 return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
1688 if (m_object->isHeading())
1689 return [NSNumber numberWithInt:m_object->headingLevel()];
1691 if (m_object->isCheckboxOrRadio()) {
1692 switch (m_object->checkboxOrRadioValue()) {
1693 case ButtonStateOff:
1694 return [NSNumber numberWithInt:0];
1696 return [NSNumber numberWithInt:1];
1697 case ButtonStateMixed:
1698 return [NSNumber numberWithInt:2];
1702 // radio groups return the selected radio button as the AXValue
1703 if (m_object->isRadioGroup()) {
1704 AccessibilityObject* radioButton = m_object->selectedRadioButton();
1707 return radioButton->wrapper();
1710 if (m_object->isTabList()) {
1711 AccessibilityObject* tabItem = m_object->selectedTabItem();
1714 return tabItem->wrapper();
1717 if (m_object->isTabItem())
1718 return [NSNumber numberWithInt:m_object->isSelected()];
1720 return m_object->stringValue();
1723 if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
1724 return [NSNumber numberWithFloat:m_object->minValueForRange()];
1726 if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
1727 return [NSNumber numberWithFloat:m_object->maxValueForRange()];
1729 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1730 return m_object->helpText();
1732 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
1733 return [NSNumber numberWithBool: m_object->isFocused()];
1735 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1736 return [NSNumber numberWithBool: m_object->isEnabled()];
1738 if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
1739 IntSize s = m_object->size();
1740 return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
1743 if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
1744 return [self position];
1746 if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
1747 [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
1749 id remoteParent = [self remoteAccessibilityParentObject];
1751 return [remoteParent accessibilityAttributeValue:attributeName];
1753 FrameView* fv = m_object->documentFrameView();
1755 return [fv->platformWidget() window];
1759 if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
1760 AtomicString accessKey = m_object->accessKey();
1761 if (accessKey.isNull())
1766 if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
1767 if (m_object->isTabList()) {
1768 AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1769 m_object->tabChildren(tabsChildren);
1770 return convertToNSArray(tabsChildren);
1774 if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
1775 // The contents of a tab list are all the children except the tabs.
1776 if (m_object->isTabList()) {
1777 AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1778 AccessibilityObject::AccessibilityChildrenVector tabsChildren;
1779 m_object->tabChildren(tabsChildren);
1781 AccessibilityObject::AccessibilityChildrenVector contents;
1782 unsigned childrenSize = children.size();
1783 for (unsigned k = 0; k < childrenSize; ++k) {
1784 if (tabsChildren.find(children[k]) == WTF::notFound)
1785 contents.append(children[k]);
1787 return convertToNSArray(contents);
1788 } else if (m_object->isScrollView()) {
1789 AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1791 // A scrollView's contents are everything except the scroll bars.
1792 AccessibilityObject::AccessibilityChildrenVector contents;
1793 unsigned childrenSize = children.size();
1794 for (unsigned k = 0; k < childrenSize; ++k) {
1795 if (!children[k]->isScrollbar())
1796 contents.append(children[k]);
1798 return convertToNSArray(contents);
1802 if (m_object->isAccessibilityTable()) {
1803 // TODO: distinguish between visible and non-visible rows
1804 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1805 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1806 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
1808 // TODO: distinguish between visible and non-visible columns
1809 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
1810 [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
1811 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
1814 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1815 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1816 m_object->selectedChildren(selectedChildrenCopy);
1817 return convertToNSArray(selectedChildrenCopy);
1820 // HTML tables don't support these
1821 if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
1822 [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1825 if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
1826 AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1827 static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
1828 return convertToNSArray(columnHeaders);
1831 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1832 AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
1833 if (headerContainer)
1834 return headerContainer->wrapper();
1838 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
1839 AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1840 static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
1841 return convertToNSArray(rowHeaders);
1844 if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
1845 AccessibilityObject::AccessibilityChildrenVector cells;
1846 static_cast<AccessibilityTable*>(m_object)->cells(cells);
1847 return convertToNSArray(cells);
1851 if (m_object->isTableColumn()) {
1852 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1853 return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
1855 // rows attribute for a column is the list of all the elements in that column at each row
1856 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
1857 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
1858 return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
1860 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1861 AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
1864 return header->wrapper();
1868 if (m_object->isTableCell()) {
1869 if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1870 pair<int, int> rowRange;
1871 static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
1872 return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1874 if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1875 pair<int, int> columnRange;
1876 static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
1877 return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1881 if (m_object->isTree()) {
1882 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1883 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1884 m_object->selectedChildren(selectedChildrenCopy);
1885 return convertToNSArray(selectedChildrenCopy);
1887 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
1888 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1889 m_object->ariaTreeRows(rowsCopy);
1890 return convertToNSArray(rowsCopy);
1893 // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
1894 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
1895 return [NSArray array];
1898 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
1899 if (m_object->isTreeItem()) {
1900 AccessibilityObject* parent = m_object->parentObject();
1901 for (; parent && !parent->isTree(); parent = parent->parentObject())
1907 // Find the index of this item by iterating the parents.
1908 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1909 parent->ariaTreeRows(rowsCopy);
1910 size_t count = rowsCopy.size();
1911 for (size_t k = 0; k < count; ++k)
1912 if (rowsCopy[k]->wrapper() == self)
1913 return [NSNumber numberWithUnsignedInt:k];
1917 if (m_object->isTableRow()) {
1918 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1919 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
1923 // The rows that are considered inside this row.
1924 if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
1925 if (m_object->isTreeItem()) {
1926 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1927 m_object->ariaTreeItemDisclosedRows(rowsCopy);
1928 return convertToNSArray(rowsCopy);
1929 } else if (m_object->isARIATreeGridRow()) {
1930 AccessibilityObject::AccessibilityChildrenVector rowsCopy;
1931 static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
1932 return convertToNSArray(rowsCopy);
1936 // The row that contains this row. It should be the same as the first parent that is a treeitem.
1937 if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
1938 if (m_object->isTreeItem()) {
1939 AccessibilityObject* parent = m_object->parentObject();
1941 if (parent->isTreeItem())
1942 return parent->wrapper();
1943 // If the parent is the tree itself, then this value == nil.
1944 if (parent->isTree())
1946 parent = parent->parentObject();
1949 } else if (m_object->isARIATreeGridRow()) {
1950 AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
1953 return row->wrapper();
1957 if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute])
1958 return [NSNumber numberWithInt:m_object->hierarchicalLevel()];
1959 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1960 return [NSNumber numberWithBool:m_object->isExpanded()];
1962 if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
1963 return NSAccessibilityVerticalOrientationValue;
1965 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
1966 return [self textMarkerRangeForSelection];
1968 if (m_object->isAccessibilityRenderObject()) {
1969 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
1973 if ([attributeName isEqualToString: @"AXStartTextMarker"])
1974 return [self textMarkerForVisiblePosition:startOfDocument(renderer->document())];
1975 if ([attributeName isEqualToString: @"AXEndTextMarker"])
1976 return [self textMarkerForVisiblePosition:endOfDocument(renderer->document())];
1978 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
1979 return [NSNumber numberWithInt:blockquoteLevel(renderer)];
1981 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) {
1982 AccessibilityObject* parent = m_object->parentObjectUnignored();
1984 return [NSNumber numberWithInt:0];
1985 return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute];
1989 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
1990 AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
1991 m_object->linkedUIElements(linkedUIElements);
1992 if (linkedUIElements.size() == 0)
1994 return convertToNSArray(linkedUIElements);
1997 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1998 return [NSNumber numberWithBool:m_object->isSelected()];
2000 if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2001 AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
2003 return [NSArray arrayWithObject:uiElement->wrapper()];
2006 if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2007 AccessibilityObject* obj = m_object->titleUIElement();
2009 return obj->wrapper();
2013 if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
2014 return m_object->valueDescription();
2016 if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2017 AccessibilityOrientation elementOrientation = m_object->orientation();
2018 if (elementOrientation == AccessibilityOrientationVertical)
2019 return NSAccessibilityVerticalOrientationValue;
2020 if (elementOrientation == AccessibilityOrientationHorizontal)
2021 return NSAccessibilityHorizontalOrientationValue;
2025 if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2026 AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2028 return scrollBar->wrapper();
2031 if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2032 AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2034 return scrollBar->wrapper();
2038 if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2039 switch (m_object->sortDirection()) {
2040 case SortDirectionAscending:
2041 return NSAccessibilityAscendingSortDirectionValue;
2042 case SortDirectionDescending:
2043 return NSAccessibilityDescendingSortDirectionValue;
2045 return NSAccessibilityUnknownSortDirectionValue;
2049 if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2050 return m_object->language();
2052 if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2053 return [NSNumber numberWithBool:m_object->isExpanded()];
2055 if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2056 return [NSNumber numberWithBool:m_object->isRequired()];
2058 if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2059 return m_object->invalidStatus();
2061 if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2062 AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2063 m_object->ariaOwnsElements(ariaOwns);
2064 return convertToNSArray(ariaOwns);
2067 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2068 return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
2070 if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
2071 Vector<String> dropEffects;
2072 m_object->determineARIADropEffects(dropEffects);
2073 size_t length = dropEffects.size();
2075 NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
2076 for (size_t i = 0; i < length; ++i)
2077 [dropEffectsArray addObject:dropEffects[i]];
2078 return dropEffectsArray;
2081 if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2082 return m_object->placeholderValue();
2084 if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2085 return [NSNumber numberWithBool:m_object->ariaHasPopup()];
2087 // ARIA Live region attributes.
2088 if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2089 return m_object->ariaLiveRegionStatus();
2090 if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2091 return m_object->ariaLiveRegionRelevant();
2092 if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2093 return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
2094 if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
2095 return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
2097 // this is used only by DumpRenderTree for testing
2098 if ([attributeName isEqualToString:@"AXClickPoint"])
2099 return [NSValue valueWithPoint:m_object->clickPoint()];
2101 // This is used by DRT to verify CSS3 speech works.
2102 if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) {
2103 ESpeak speakProperty = m_object->speakProperty();
2104 switch (speakProperty) {
2108 return @"spell-out";
2111 case SpeakLiteralPunctuation:
2112 return @"literal-punctuation";
2113 case SpeakNoPunctuation:
2114 return @"no-punctuation";
2124 - (id)accessibilityFocusedUIElement
2126 if (![self updateObjectBackingStore])
2129 RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
2134 return focusedObj->wrapper();
2137 - (id)accessibilityHitTest:(NSPoint)point
2139 if (![self updateObjectBackingStore])
2142 m_object->updateChildrenIfNecessary();
2143 RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point));
2145 return NSAccessibilityUnignoredAncestor(axObject->wrapper());
2146 return NSAccessibilityUnignoredAncestor(self);
2149 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2151 if (![self updateObjectBackingStore])
2154 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2157 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2158 return m_object->canSetFocusAttribute();
2160 if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2161 return m_object->canSetValueAttribute();
2163 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2164 return m_object->canSetSelectedAttribute();
2166 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2167 return m_object->canSetSelectedChildrenAttribute();
2169 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2170 return m_object->canSetExpandedAttribute();
2172 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2175 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
2176 [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
2177 [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2178 return m_object->canSetTextRangeAttributes();
2180 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2186 // accessibilityShouldUseUniqueId is an AppKit method we override so that
2187 // objects will be given a unique ID, and therefore allow AppKit to know when they
2188 // become obsolete (e.g. when the user navigates to a new web page, making this one
2189 // unrendered but not deallocated because it is in the back/forward cache).
2190 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
2191 // appropriate place (e.g. dealloc) to remove these non-retained references from
2192 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
2194 // Registering an object is also required for observing notifications. Only registered objects can be observed.
2195 - (BOOL)accessibilityIsIgnored
2197 if (![self updateObjectBackingStore])
2200 if (m_object->isAttachment())
2201 return [[self attachmentView] accessibilityIsIgnored];
2202 return m_object->accessibilityIsIgnored();
2205 - (NSArray* )accessibilityParameterizedAttributeNames
2207 if (![self updateObjectBackingStore])
2210 if (m_object->isAttachment())
2213 static NSArray* paramAttrs = nil;
2214 static NSArray* textParamAttrs = nil;
2215 static NSArray* tableParamAttrs = nil;
2216 if (paramAttrs == nil) {
2217 paramAttrs = [[NSArray alloc] initWithObjects:
2218 @"AXUIElementForTextMarker",
2219 @"AXTextMarkerRangeForUIElement",
2220 @"AXLineForTextMarker",
2221 @"AXTextMarkerRangeForLine",
2222 @"AXStringForTextMarkerRange",
2223 @"AXTextMarkerForPosition",
2224 @"AXBoundsForTextMarkerRange",
2225 @"AXAttributedStringForTextMarkerRange",
2226 @"AXTextMarkerRangeForUnorderedTextMarkers",
2227 @"AXNextTextMarkerForTextMarker",
2228 @"AXPreviousTextMarkerForTextMarker",
2229 @"AXLeftWordTextMarkerRangeForTextMarker",
2230 @"AXRightWordTextMarkerRangeForTextMarker",
2231 @"AXLeftLineTextMarkerRangeForTextMarker",
2232 @"AXRightLineTextMarkerRangeForTextMarker",
2233 @"AXSentenceTextMarkerRangeForTextMarker",
2234 @"AXParagraphTextMarkerRangeForTextMarker",
2235 @"AXNextWordEndTextMarkerForTextMarker",
2236 @"AXPreviousWordStartTextMarkerForTextMarker",
2237 @"AXNextLineEndTextMarkerForTextMarker",
2238 @"AXPreviousLineStartTextMarkerForTextMarker",
2239 @"AXNextSentenceEndTextMarkerForTextMarker",
2240 @"AXPreviousSentenceStartTextMarkerForTextMarker",
2241 @"AXNextParagraphEndTextMarkerForTextMarker",
2242 @"AXPreviousParagraphStartTextMarkerForTextMarker",
2243 @"AXStyleTextMarkerRangeForTextMarker",
2244 @"AXLengthForTextMarkerRange",
2245 NSAccessibilityBoundsForRangeParameterizedAttribute,
2246 NSAccessibilityStringForRangeParameterizedAttribute,
2250 if (textParamAttrs == nil) {
2251 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2252 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2253 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2254 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2255 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2256 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2257 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2258 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2259 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2260 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2261 textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2262 [tempArray release];
2264 if (tableParamAttrs == nil) {
2265 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2266 [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2267 tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2268 [tempArray release];
2271 if (m_object->isPasswordField())
2272 return [NSArray array];
2274 if (!m_object->isAccessibilityRenderObject())
2277 if (m_object->isTextControl())
2278 return textParamAttrs;
2280 if (m_object->isAccessibilityTable())
2281 return tableParamAttrs;
2283 if (m_object->isMenuRelated())
2289 - (void)accessibilityPerformPressAction
2291 if (![self updateObjectBackingStore])
2294 if (m_object->isAttachment())
2295 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2300 - (void)accessibilityPerformIncrementAction
2302 if (![self updateObjectBackingStore])
2305 if (m_object->isAttachment())
2306 [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2308 m_object->increment();
2311 - (void)accessibilityPerformDecrementAction
2313 if (![self updateObjectBackingStore])
2316 if (m_object->isAttachment())
2317 [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2319 m_object->decrement();
2322 - (void)accessibilityPerformShowMenuAction
2324 if (m_object->roleValue() == ComboBoxRole)
2325 m_object->setIsExpanded(true);
2327 // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2328 // If it's the same run loop iteration, the menu open notification won't be sent
2329 [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2333 - (void)accessibilityShowContextMenu
2335 FrameView* frameView = m_object->documentFrameView();
2338 Frame* frame = frameView->frame();
2341 Page* page = frame->page();
2345 // Simulate a click in the middle of the object.
2346 IntPoint clickPoint = m_object->clickPoint();
2348 PlatformMouseEvent mouseEvent(clickPoint, clickPoint, RightButton, MouseEventPressed, 1, false, false, false, false, currentTime());
2349 bool handled = frame->eventHandler()->sendContextMenuEvent(mouseEvent);
2351 page->chrome()->showContextMenu();
2354 - (void)accessibilityPerformAction:(NSString*)action
2356 if (![self updateObjectBackingStore])
2359 if ([action isEqualToString:NSAccessibilityPressAction])
2360 [self accessibilityPerformPressAction];
2362 else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2363 [self accessibilityPerformShowMenuAction];
2365 else if ([action isEqualToString:NSAccessibilityIncrementAction])
2366 [self accessibilityPerformIncrementAction];
2368 else if ([action isEqualToString:NSAccessibilityDecrementAction])
2369 [self accessibilityPerformDecrementAction];
2372 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2374 if (![self updateObjectBackingStore])
2377 id textMarkerRange = nil;
2378 NSNumber* number = nil;
2379 NSString* string = nil;
2380 NSRange range = {0, 0};
2381 NSArray* array = nil;
2383 // decode the parameter
2384 if (AXObjectIsTextMarkerRange(value))
2385 textMarkerRange = value;
2387 else if ([value isKindOfClass:[NSNumber self]])
2390 else if ([value isKindOfClass:[NSString self]])
2393 else if ([value isKindOfClass:[NSValue self]])
2394 range = [value rangeValue];
2396 else if ([value isKindOfClass:[NSArray self]])
2399 // handle the command
2400 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2401 ASSERT(textMarkerRange);
2402 m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
2403 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2405 m_object->setFocused([number intValue] != 0);
2406 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2407 if (number && m_object->canSetNumericValue())
2408 m_object->setValue([number floatValue]);
2410 m_object->setValue(string);
2411 } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
2414 m_object->setSelected([number boolValue]);
2415 } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2416 if (!array || m_object->roleValue() != ListBoxRole)
2418 AccessibilityObject::AccessibilityChildrenVector selectedChildren;
2419 convertToVector(array, selectedChildren);
2420 static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
2421 } else if (m_object->isTextControl()) {
2422 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2423 m_object->setSelectedText(string);
2424 } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2425 m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2426 } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2427 m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
2429 } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2430 m_object->setIsExpanded([number boolValue]);
2431 else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2432 AccessibilityObject::AccessibilityChildrenVector selectedRows;
2433 convertToVector(array, selectedRows);
2434 if (m_object->isTree() || m_object->isAccessibilityTable())
2435 m_object->setSelectedRows(selectedRows);
2436 } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2437 m_object->setARIAGrabbed([number boolValue]);
2440 static RenderObject* rendererForView(NSView* view)
2442 if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
2445 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
2446 Frame* frame = [frameView _web_frame];
2450 Node* node = frame->document()->ownerElement();
2454 return node->renderer();
2457 - (id)_accessibilityParentForSubview:(NSView*)subview
2459 RenderObject* renderer = rendererForView(subview);
2463 AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
2465 return obj->parentObjectUnignored()->wrapper();
2469 - (NSString*)accessibilityActionDescription:(NSString*)action
2471 // we have no custom actions
2472 return NSAccessibilityActionDescription(action);
2475 // The CFAttributedStringType representation of the text associated with this accessibility
2476 // object that is specified by the given range.
2477 - (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
2479 PlainTextRange textRange = PlainTextRange(range.location, range.length);
2480 VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
2481 return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
2484 // The RTF representation of the text associated with this accessibility object that is
2485 // specified by the given range.
2486 - (NSData*)doAXRTFForRange:(NSRange)range
2488 NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
2489 return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
2492 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2494 id textMarker = nil;
2495 id textMarkerRange = nil;
2496 NSNumber* number = nil;
2497 NSArray* array = nil;
2498 RefPtr<AccessibilityObject> uiElement = 0;
2499 NSPoint point = NSZeroPoint;
2500 bool pointSet = false;
2501 NSRange range = {0, 0};
2502 bool rangeSet = false;
2504 // basic parameter validation
2505 if (!m_object || !attribute || !parameter)
2508 if (![self updateObjectBackingStore])
2511 // common parameter type check/casting. Nil checks in handlers catch wrong type case.
2512 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
2513 // a parameter of the wrong type.
2514 if (AXObjectIsTextMarker(parameter))
2515 textMarker = parameter;
2517 else if (AXObjectIsTextMarkerRange(parameter))
2518 textMarkerRange = parameter;
2520 else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
2521 uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
2523 else if ([parameter isKindOfClass:[NSNumber self]])
2526 else if ([parameter isKindOfClass:[NSArray self]])
2529 else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
2531 point = [(NSValue*)parameter pointValue];
2533 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
2535 range = [(NSValue*)parameter rangeValue];
2537 // Attribute type is not supported. Allow super to handle.
2538 return [super accessibilityAttributeValue:attribute forParameter:parameter];
2542 if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
2543 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2544 AccessibilityObject* axObject = m_object->accessibilityObjectForPosition(visiblePos);
2547 return axObject->wrapper();
2550 if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
2551 VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
2552 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2555 if ([attribute isEqualToString:@"AXLineForTextMarker"]) {
2556 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2557 return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
2560 if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) {
2561 VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine([number intValue]);
2562 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2565 if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) {
2566 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2567 return m_object->stringForVisiblePositionRange(visiblePosRange);
2570 if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
2571 IntPoint webCorePoint = IntPoint(point);
2572 return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil;
2575 if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
2576 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2577 NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
2578 return [NSValue valueWithRect:rect];
2581 if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2582 VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2583 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2584 if (start.isNull() || end.isNull())
2586 NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
2587 return [NSValue valueWithRect:rect];
2590 if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
2591 VisiblePosition start = m_object->visiblePositionForIndex(range.location);
2592 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
2593 if (start.isNull() || end.isNull())
2595 return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
2598 if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
2599 return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
2601 if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
2602 if ([array count] < 2)
2605 id textMarker1 = [array objectAtIndex:0];
2606 id textMarker2 = [array objectAtIndex:1];
2607 if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2))
2610 VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:(textMarker1)];
2611 VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:(textMarker2)];
2612 VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
2613 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2616 if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
2617 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2618 return [self textMarkerForVisiblePosition:m_object->nextVisiblePosition(visiblePos)];
2621 if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
2622 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2623 return [self textMarkerForVisiblePosition:m_object->previousVisiblePosition(visiblePos)];
2626 if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
2627 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2628 VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
2629 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2632 if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
2633 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2634 VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
2635 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2638 if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
2639 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2640 VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
2641 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2644 if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"]) {
2645 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2646 VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
2647 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2650 if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
2651 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2652 VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
2653 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2656 if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
2657 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2658 VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
2659 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2662 if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
2663 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2664 return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
2667 if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
2668 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2669 return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
2672 if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
2673 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2674 return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)];
2677 if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) {
2678 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2679 return [self textMarkerForVisiblePosition:m_object->previousLineStartPosition(visiblePos)];
2682 if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
2683 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2684 return [self textMarkerForVisiblePosition:m_object->nextSentenceEndPosition(visiblePos)];
2687 if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
2688 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2689 return [self textMarkerForVisiblePosition:m_object->previousSentenceStartPosition(visiblePos)];
2692 if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
2693 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2694 return [self textMarkerForVisiblePosition:m_object->nextParagraphEndPosition(visiblePos)];
2697 if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
2698 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2699 return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)];
2702 if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
2703 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
2704 VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
2705 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
2708 if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
2709 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2710 int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
2713 return [NSNumber numberWithInt:length];
2716 // Used only by DumpRenderTree (so far).
2717 if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) {
2718 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2719 return [self textMarkerForVisiblePosition:visiblePosRange.start];
2722 if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) {
2723 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
2724 return [self textMarkerForVisiblePosition:visiblePosRange.end];
2727 if (m_object->isAccessibilityTable()) {
2728 if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
2729 if (array == nil || [array count] != 2)
2731 AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
2735 return cell->wrapper();
2739 if (m_object->isTextControl()) {
2740 if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
2741 int lineNumber = m_object->doAXLineForIndex([number intValue]);
2744 return [NSNumber numberWithUnsignedInt:lineNumber];
2747 if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
2748 PlainTextRange textRange = m_object->doAXRangeForLine([number intValue]);
2749 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2752 if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) {
2753 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2754 return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
2757 if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
2760 IntPoint webCorePoint = IntPoint(point);
2761 PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
2762 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2765 if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
2766 PlainTextRange textRange = m_object->doAXRangeForIndex([number intValue]);
2767 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2770 if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
2773 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
2774 NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
2775 return [NSValue valueWithRect:rect];
2778 if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
2779 return rangeSet ? [self doAXRTFForRange:range] : nil;
2781 if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
2782 return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
2784 if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
2785 PlainTextRange textRange = m_object->doAXStyleRangeForIndex([number intValue]);
2786 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
2790 // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
2791 // In that case it must be passed to super.
2792 return [super accessibilityAttributeValue:attribute forParameter:parameter];
2795 - (BOOL)accessibilitySupportsOverriddenAttributes
2800 - (BOOL)accessibilityShouldUseUniqueId
2802 // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up.
2806 // API that AppKit uses for faster access
2807 - (NSUInteger)accessibilityIndexOfChild:(id)child
2809 if (![self updateObjectBackingStore])
2812 // Tree objects return their rows as their children. We can use the original method
2813 // here, because we won't gain any speed up.
2814 if (m_object->isTree())
2815 return [super accessibilityIndexOfChild:child];
2817 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2819 if (children.isEmpty())
2820 return [[self renderWidgetChildren] indexOfObject:child];
2822 unsigned count = children.size();
2823 for (unsigned k = 0; k < count; ++k) {
2824 AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
2825 if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child))
2832 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
2834 if (![self updateObjectBackingStore])
2837 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2838 // Tree items object returns a different set of children than those that are in children()
2839 // because an AXOutline (the mac role is becomes) has some odd stipulations.
2840 if (m_object->isTree() || m_object->isTreeItem())
2841 return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
2843 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2844 if (children.isEmpty())
2845 return [[self renderWidgetChildren] count];
2847 return children.size();
2850 return [super accessibilityArrayAttributeCount:attribute];
2853 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
2855 if (![self updateObjectBackingStore])
2858 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
2859 if (m_object->children().isEmpty()) {
2860 NSArray *children = [self renderWidgetChildren];
2864 NSUInteger childCount = [children count];
2865 if (index >= childCount)
2868 NSUInteger arrayLength = min(childCount - index, maxCount);
2869 return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
2870 } else if (m_object->isTree()) {
2871 // Tree objects return their rows as their children. We can use the original method in this case.
2872 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2875 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
2876 unsigned childCount = children.size();
2877 if (index >= childCount)
2880 unsigned available = min(childCount - index, maxCount);
2882 NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
2883 for (unsigned added = 0; added < available; ++index, ++added) {
2884 AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
2886 // The attachment view should be returned, otherwise AX palindrome errors occur.
2887 if (children[index]->isAttachment() && [wrapper attachmentView])
2888 [subarray addObject:[wrapper attachmentView]];
2890 [subarray addObject:wrapper];
2897 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
2900 // This is set by DRT when it wants to listen for notifications.
2901 static BOOL accessibilityShouldRepostNotifications;
2902 - (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
2904 accessibilityShouldRepostNotifications = repost;
2907 - (void)accessibilityPostedNotification:(NSString *)notificationName
2909 if (accessibilityShouldRepostNotifications) {
2910 NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", nil];
2911 [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:nil userInfo:userInfo];
2917 #endif // HAVE(ACCESSIBILITY)