1/* 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#import "config.h" 30#import "AccessibilityObjectWrapper.h" 31 32#if HAVE(ACCESSIBILITY) 33 34#import "AXObjectCache.h" 35#import "AccessibilityARIAGridRow.h" 36#import "AccessibilityListBox.h" 37#import "AccessibilityList.h" 38#import "AccessibilityRenderObject.h" 39#import "AccessibilityTable.h" 40#import "AccessibilityTableCell.h" 41#import "AccessibilityTableRow.h" 42#import "AccessibilityTableColumn.h" 43#import "ColorMac.h" 44#import "Frame.h" 45#import "HTMLAnchorElement.h" 46#import "HTMLAreaElement.h" 47#import "HTMLImageElement.h" 48#import "HTMLInputElement.h" 49#import "HTMLTextAreaElement.h" 50#import "LocalizedStrings.h" 51#import "RenderTextControl.h" 52#import "RenderView.h" 53#import "RenderWidget.h" 54#import "SelectionController.h" 55#import "SimpleFontData.h" 56#import "TextIterator.h" 57#import "WebCoreFrameView.h" 58#import "WebCoreObjCExtras.h" 59#import "WebCoreViewFactory.h" 60#import "htmlediting.h" 61#import "visible_units.h" 62#import <runtime/InitializeThreading.h> 63 64using namespace WebCore; 65using namespace HTMLNames; 66using namespace std; 67 68// Cell Tables 69#ifndef NSAccessibilitySelectedCellsAttribute 70#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells" 71#endif 72 73#ifndef NSAccessibilityVisibleCellsAttribute 74#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells" 75#endif 76 77#ifndef NSAccessibilityRowHeaderUIElementsAttribute 78#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements" 79#endif 80 81#ifndef NSAccessibilityRowIndexRangeAttribute 82#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange" 83#endif 84 85#ifndef NSAccessibilityColumnIndexRangeAttribute 86#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange" 87#endif 88 89#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute 90#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow" 91#endif 92 93#ifndef NSAccessibilityCellRole 94#define NSAccessibilityCellRole @"AXCell" 95#endif 96 97// Lists 98#ifndef NSAccessibilityContentListSubrole 99#define NSAccessibilityContentListSubrole @"AXContentList" 100#endif 101 102#ifndef NSAccessibilityDefinitionListSubrole 103#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList" 104#endif 105 106// Miscellaneous 107#ifndef NSAccessibilityBlockQuoteLevelAttribute 108#define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel" 109#endif 110 111#ifndef NSAccessibilityAccessKeyAttribute 112#define NSAccessibilityAccessKeyAttribute @"AXAccessKey" 113#endif 114 115#ifndef NSAccessibilityLanguageAttribute 116#define NSAccessibilityLanguageAttribute @"AXLanguage" 117#endif 118 119#ifndef NSAccessibilityRequiredAttribute 120#define NSAccessibilityRequiredAttribute @"AXRequired" 121#endif 122 123#ifndef NSAccessibilityOwnsAttribute 124#define NSAccessibilityOwnsAttribute @"AXOwns" 125#endif 126 127#ifndef NSAccessibilityGrabbedAttribute 128#define NSAccessibilityGrabbedAttribute @"AXGrabbed" 129#endif 130 131#ifndef NSAccessibilityDropEffectsAttribute 132#define NSAccessibilityDropEffectsAttribute @"AXDropEffects" 133#endif 134 135#ifndef NSAccessibilityARIALiveAttribute 136#define NSAccessibilityARIALiveAttribute @"AXARIALive" 137#endif 138 139#ifndef NSAccessibilityARIAAtomicAttribute 140#define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic" 141#endif 142 143#ifndef NSAccessibilityARIARelevantAttribute 144#define NSAccessibilityARIARelevantAttribute @"AXARIARelevant" 145#endif 146 147#ifndef NSAccessibilityARIABusyAttribute 148#define NSAccessibilityARIABusyAttribute @"AXARIABusy" 149#endif 150 151#ifndef NSAccessibilityLoadingProgressAttribute 152#define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress" 153#endif 154 155#ifdef BUILDING_ON_TIGER 156typedef unsigned NSUInteger; 157#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription" 158#define NSAccessibilityTimelineSubrole @"AXTimeline" 159#endif 160 161@interface NSObject (WebKitAccessibilityArrayCategory) 162 163- (NSUInteger)accessibilityIndexOfChild:(id)child; 164- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute; 165- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount; 166 167@end 168 169@implementation AccessibilityObjectWrapper 170 171+ (void)initialize 172{ 173 JSC::initializeThreading(); 174#ifndef BUILDING_ON_TIGER 175 WebCoreObjCFinalizeOnMainThread(self); 176#endif 177} 178 179- (id)initWithAccessibilityObject:(AccessibilityObject*)axObject 180{ 181 [super init]; 182 183 m_object = axObject; 184 return self; 185} 186 187- (void)unregisterUniqueIdForUIElement 188{ 189 [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self]; 190} 191 192- (void)detach 193{ 194 // Send unregisterUniqueIdForUIElement unconditionally because if it is 195 // ever accidentally not done (via other bugs in our AX implementation) you 196 // end up with a crash like <rdar://problem/4273149>. It is safe and not 197 // expensive to send even if the object is not registered. 198 [self unregisterUniqueIdForUIElement]; 199 m_object = 0; 200} 201 202- (AccessibilityObject*)accessibilityObject 203{ 204 return m_object; 205} 206 207- (NSView*)attachmentView 208{ 209 ASSERT(m_object->isAttachment()); 210 Widget* widget = m_object->widgetForAttachmentView(); 211 if (!widget) 212 return nil; 213 return NSAccessibilityUnignoredDescendant(widget->platformWidget()); 214} 215 216static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos) 217{ 218 TextMarkerData textMarkerData; 219 AXObjectCache::textMarkerDataForVisiblePosition(textMarkerData, visiblePos); 220 if (!textMarkerData.axID) 221 return nil; 222 223 return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)]; 224} 225 226static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker) 227{ 228 TextMarkerData textMarkerData; 229 if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)]) 230 return VisiblePosition(); 231 232 return AXObjectCache::visiblePositionForTextMarkerData(textMarkerData); 233} 234 235static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange) 236{ 237 return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]); 238} 239 240static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange) 241{ 242 return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]); 243} 244 245static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2) 246{ 247 if (!textMarker1 || !textMarker2) 248 return nil; 249 250 return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2]; 251} 252 253static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range) 254{ 255 NSDictionary* dict; 256 257 if (font) { 258 dict = [NSDictionary dictionaryWithObjectsAndKeys: 259 [font fontName] , NSAccessibilityFontNameKey, 260 [font familyName] , NSAccessibilityFontFamilyKey, 261 [font displayName] , NSAccessibilityVisibleNameKey, 262 [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey, 263 nil]; 264 265 [attrString addAttribute:attribute value:dict range:range]; 266 } else 267 [attrString removeAttribute:attribute range:range]; 268 269} 270 271static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor) 272{ 273 // get color information assuming NSDeviceRGBColorSpace 274 NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 275 if (rgbColor == nil) 276 rgbColor = [NSColor blackColor]; 277 CGFloat components[4]; 278 [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; 279 280 // create a new CGColorRef to return 281 CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB(); 282 CGColorRef cgColor = CGColorCreate(cgColorSpace, components); 283 CGColorSpaceRelease(cgColorSpace); 284 285 // check for match with existing color 286 if (existingColor && CGColorEqualToColor(cgColor, existingColor)) { 287 CGColorRelease(cgColor); 288 cgColor = 0; 289 } 290 291 return cgColor; 292} 293 294static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range) 295{ 296 if (color) { 297 CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil]; 298 CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor); 299 if (cgColor) { 300 [attrString addAttribute:attribute value:(id)cgColor range:range]; 301 CGColorRelease(cgColor); 302 } 303 } else 304 [attrString removeAttribute:attribute range:range]; 305} 306 307static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range) 308{ 309 if (number) 310 [attrString addAttribute:attribute value:number range:range]; 311 else 312 [attrString removeAttribute:attribute range:range]; 313} 314 315static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 316{ 317 RenderStyle* style = renderer->style(); 318 319 // set basic font info 320 AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range); 321 322 // set basic colors 323 AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range); 324 AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range); 325 326 // set super/sub scripting 327 EVerticalAlign alignment = style->verticalAlign(); 328 if (alignment == SUB) 329 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range); 330 else if (alignment == SUPER) 331 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range); 332 else 333 [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range]; 334 335 // set shadow 336 if (style->textShadow()) 337 AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range); 338 else 339 [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range]; 340 341 // set underline and strikethrough 342 int decor = style->textDecorationsInEffect(); 343 if ((decor & UNDERLINE) == 0) { 344 [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range]; 345 [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range]; 346 } 347 348 if ((decor & LINE_THROUGH) == 0) { 349 [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range]; 350 [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range]; 351 } 352 353 if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) { 354 // find colors using quirk mode approach (strict mode would use current 355 // color for all but the root line box, which would use getTextDecorationColors) 356 Color underline, overline, linethrough; 357 renderer->getTextDecorationColors(decor, underline, overline, linethrough); 358 359 if ((decor & UNDERLINE) != 0) { 360 AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range); 361 AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range); 362 } 363 364 if ((decor & LINE_THROUGH) != 0) { 365 AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range); 366 AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range); 367 } 368 } 369} 370 371static int blockquoteLevel(RenderObject* renderer) 372{ 373 if (!renderer) 374 return 0; 375 376 int result = 0; 377 for (Node* node = renderer->node(); node; node = node->parent()) { 378 if (node->hasTagName(blockquoteTag)) 379 result += 1; 380 } 381 382 return result; 383} 384 385static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 386{ 387 int quoteLevel = blockquoteLevel(renderer); 388 389 if (quoteLevel) 390 [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range]; 391 else 392 [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range]; 393} 394 395static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range) 396{ 397 Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node); 398 Vector<DocumentMarker>::iterator markerIt = markers.begin(); 399 400 unsigned endOffset = (unsigned)offset + range.length; 401 for ( ; markerIt != markers.end(); markerIt++) { 402 DocumentMarker marker = *markerIt; 403 404 if (marker.type != DocumentMarker::Spelling) 405 continue; 406 407 if (marker.endOffset <= (unsigned)offset) 408 continue; 409 410 if (marker.startOffset > endOffset) 411 break; 412 413 // add misspelling attribute for the intersection of the marker and the range 414 int rStart = range.location + (marker.startOffset - offset); 415 int rLength = min(marker.endOffset, endOffset) - marker.startOffset; 416 NSRange spellRange = NSMakeRange(rStart, rLength); 417 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange); 418 419 if (marker.endOffset > endOffset + 1) 420 break; 421 } 422} 423 424static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 425{ 426 if (!renderer) 427 return; 428 429 AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent()); 430 int parentHeadingLevel = parentObject->headingLevel(); 431 432 if (parentHeadingLevel) 433 [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range]; 434 else 435 [attrString removeAttribute:@"AXHeadingLevel" range:range]; 436} 437 438static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range) 439{ 440 if (object && object->isAccessibilityRenderObject()) { 441 // make a serializable AX object 442 443 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer(); 444 if (!renderer) 445 return; 446 447 Document* doc = renderer->document(); 448 if (!doc) 449 return; 450 451 AXObjectCache* cache = doc->axObjectCache(); 452 if (!cache) 453 return; 454 455 AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()]; 456 if (axElement) { 457 [attrString addAttribute:attribute value:(id)axElement range:range]; 458 CFRelease(axElement); 459 } 460 } else 461 [attrString removeAttribute:attribute range:range]; 462} 463 464static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length) 465{ 466 // skip invisible text 467 if (!node->renderer()) 468 return; 469 470 // easier to calculate the range before appending the string 471 NSRange attrStringRange = NSMakeRange([attrString length], length); 472 473 // append the string from this node 474 [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]]; 475 476 // add new attributes and remove irrelevant inherited ones 477 // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge 478 // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means 479 // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually. 480 481 // remove inherited attachment from prior AXAttributedStringAppendReplaced 482 [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange]; 483 484 // set new attributes 485 AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange); 486 AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange); 487 AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange); 488 AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange); 489 490 // do spelling last because it tends to break up the range 491 AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange); 492} 493 494static NSString* nsStringForReplacedNode(Node* replacedNode) 495{ 496 // we should always be given a rendered node and a replaced node, but be safe 497 // replaced nodes are either attachments (widgets) or images 498 if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) { 499 ASSERT_NOT_REACHED(); 500 return nil; 501 } 502 503 // create an AX object, but skip it if it is not supposed to be seen 504 RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); 505 if (obj->accessibilityIsIgnored()) 506 return nil; 507 508 // use the attachmentCharacter to represent the replaced node 509 const UniChar attachmentChar = NSAttachmentCharacter; 510 return [NSString stringWithCharacters:&attachmentChar length:1]; 511} 512 513- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange 514{ 515 if (!m_object) 516 return nil; 517 518 // extract the start and end VisiblePosition 519 VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange); 520 if (startVisiblePosition.isNull()) 521 return nil; 522 523 VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange); 524 if (endVisiblePosition.isNull()) 525 return nil; 526 527 VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition); 528 // iterate over the range to build the AX attributed string 529 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init]; 530 TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get()); 531 while (!it.atEnd()) { 532 // locate the node and starting offset for this range 533 int exception = 0; 534 Node* node = it.range()->startContainer(exception); 535 ASSERT(node == it.range()->endContainer(exception)); 536 int offset = it.range()->startOffset(exception); 537 538 // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) 539 if (it.length() != 0) { 540 // Add the text of the list marker item if necessary. 541 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition())); 542 if (!listMarkerText.isEmpty()) 543 AXAttributedStringAppendText(attrString, node, offset, listMarkerText.characters(), listMarkerText.length()); 544 545 AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length()); 546 } else { 547 Node* replacedNode = node->childNode(offset); 548 NSString *attachmentString = nsStringForReplacedNode(replacedNode); 549 if (attachmentString) { 550 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]); 551 552 // append the placeholder string 553 [[attrString mutableString] appendString:attachmentString]; 554 555 // remove all inherited attributes 556 [attrString setAttributes:nil range:attrStringRange]; 557 558 // add the attachment attribute 559 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); 560 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange); 561 } 562 } 563 it.advance(); 564 } 565 566 return [attrString autorelease]; 567} 568 569static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition) 570{ 571 WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition); 572 WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(endPosition); 573 return textMarkerRangeFromMarkers(startTextMarker, endTextMarker); 574} 575 576- (NSArray*)accessibilityActionNames 577{ 578 if (!m_object) 579 return nil; 580 581 m_object->updateBackingStore(); 582 if (!m_object) 583 return nil; 584 585 static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; 586 static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil]; 587 static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil]; 588 static NSArray* sliderActions = [[NSArray alloc] initWithObjects: NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]; 589 590 NSArray *actions; 591 if (m_object->actionElement()) 592 actions = actionElementActions; 593 else if (m_object->isMenuRelated()) 594 actions = menuElementActions; 595 else if (m_object->isSlider()) 596 actions = sliderActions; 597 else if (m_object->isAttachment()) 598 actions = [[self attachmentView] accessibilityActionNames]; 599 else 600 actions = defaultElementActions; 601 602 return actions; 603} 604 605- (NSArray*)additionalAccessibilityAttributeNames 606{ 607 if (!m_object) 608 return nil; 609 610 NSMutableArray *additional = [NSMutableArray array]; 611 if (m_object->supportsARIAOwns()) 612 [additional addObject:NSAccessibilityOwnsAttribute]; 613 614 if (m_object->isScrollbar()) 615 [additional addObject:NSAccessibilityOrientationAttribute]; 616 617 if (m_object->supportsARIADragging()) 618 [additional addObject:NSAccessibilityGrabbedAttribute]; 619 620 if (m_object->supportsARIADropping()) 621 [additional addObject:NSAccessibilityDropEffectsAttribute]; 622 623 if (m_object->isDataTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows()) 624 [additional addObject:NSAccessibilitySelectedRowsAttribute]; 625 626 if (m_object->supportsARIALiveRegion()) { 627 [additional addObject:NSAccessibilityARIALiveAttribute]; 628 [additional addObject:NSAccessibilityARIARelevantAttribute]; 629 } 630 631 // If an object is a child of a live region, then add these 632 if (m_object->isInsideARIALiveRegion()) { 633 [additional addObject:NSAccessibilityARIAAtomicAttribute]; 634 [additional addObject:NSAccessibilityARIABusyAttribute]; 635 } 636 637 return additional; 638} 639 640- (NSArray*)accessibilityAttributeNames 641{ 642 if (!m_object) 643 return nil; 644 645 m_object->updateBackingStore(); 646 if (!m_object) 647 return nil; 648 649 if (m_object->isAttachment()) 650 return [[self attachmentView] accessibilityAttributeNames]; 651 652 static NSArray* attributes = nil; 653 static NSArray* anchorAttrs = nil; 654 static NSArray* webAreaAttrs = nil; 655 static NSArray* textAttrs = nil; 656 static NSArray* listBoxAttrs = nil; 657 static NSArray* rangeAttrs = nil; 658 static NSArray* commonMenuAttrs = nil; 659 static NSArray* menuAttrs = nil; 660 static NSArray* menuBarAttrs = nil; 661 static NSArray* menuItemAttrs = nil; 662 static NSArray* menuButtonAttrs = nil; 663 static NSArray* controlAttrs = nil; 664 static NSArray* tableAttrs = nil; 665 static NSArray* tableRowAttrs = nil; 666 static NSArray* tableColAttrs = nil; 667 static NSArray* tableCellAttrs = nil; 668 static NSArray* groupAttrs = nil; 669 static NSArray* inputImageAttrs = nil; 670 static NSArray* passwordFieldAttrs = nil; 671 static NSArray* tabListAttrs = nil; 672 static NSArray* comboBoxAttrs = nil; 673 static NSArray* outlineAttrs = nil; 674 static NSArray* outlineRowAttrs = nil; 675 static NSArray* buttonAttrs = nil; 676 NSMutableArray* tempArray; 677 if (attributes == nil) { 678 attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, 679 NSAccessibilitySubroleAttribute, 680 NSAccessibilityRoleDescriptionAttribute, 681 NSAccessibilityChildrenAttribute, 682 NSAccessibilityHelpAttribute, 683 NSAccessibilityParentAttribute, 684 NSAccessibilityPositionAttribute, 685 NSAccessibilitySizeAttribute, 686 NSAccessibilityTitleAttribute, 687 NSAccessibilityDescriptionAttribute, 688 NSAccessibilityValueAttribute, 689 NSAccessibilityFocusedAttribute, 690 NSAccessibilityEnabledAttribute, 691 NSAccessibilityWindowAttribute, 692 @"AXSelectedTextMarkerRange", 693 @"AXStartTextMarker", 694 @"AXEndTextMarker", 695 @"AXVisited", 696 NSAccessibilityLinkedUIElementsAttribute, 697 NSAccessibilitySelectedAttribute, 698 NSAccessibilityBlockQuoteLevelAttribute, 699 NSAccessibilityTopLevelUIElementAttribute, 700 nil]; 701 } 702 if (commonMenuAttrs == nil) { 703 commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, 704 NSAccessibilityRoleDescriptionAttribute, 705 NSAccessibilityChildrenAttribute, 706 NSAccessibilityParentAttribute, 707 NSAccessibilityEnabledAttribute, 708 NSAccessibilityPositionAttribute, 709 NSAccessibilitySizeAttribute, 710 nil]; 711 } 712 if (anchorAttrs == nil) { 713 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 714 [tempArray addObject:NSAccessibilityURLAttribute]; 715 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 716 anchorAttrs = [[NSArray alloc] initWithArray:tempArray]; 717 [tempArray release]; 718 } 719 if (webAreaAttrs == nil) { 720 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 721 [tempArray addObject:@"AXLinkUIElements"]; 722 [tempArray addObject:@"AXLoaded"]; 723 [tempArray addObject:@"AXLayoutCount"]; 724 [tempArray addObject:NSAccessibilityLoadingProgressAttribute]; 725 [tempArray addObject:NSAccessibilityURLAttribute]; 726 webAreaAttrs = [[NSArray alloc] initWithArray:tempArray]; 727 [tempArray release]; 728 } 729 if (textAttrs == nil) { 730 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 731 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute]; 732 [tempArray addObject:NSAccessibilitySelectedTextAttribute]; 733 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute]; 734 [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute]; 735 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute]; 736 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 737 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 738 [tempArray addObject:NSAccessibilityRequiredAttribute]; 739 textAttrs = [[NSArray alloc] initWithArray:tempArray]; 740 [tempArray release]; 741 } 742 if (listBoxAttrs == nil) { 743 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 744 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 745 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 746 [tempArray addObject:NSAccessibilityOrientationAttribute]; 747 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 748 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 749 [tempArray addObject:NSAccessibilityRequiredAttribute]; 750 listBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; 751 [tempArray release]; 752 } 753 if (rangeAttrs == nil) { 754 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 755 [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute]; 756 [tempArray addObject:NSAccessibilityValueAttribute]; 757 [tempArray addObject:NSAccessibilityMinValueAttribute]; 758 [tempArray addObject:NSAccessibilityMaxValueAttribute]; 759 [tempArray addObject:NSAccessibilityOrientationAttribute]; 760 [tempArray addObject:NSAccessibilityValueDescriptionAttribute]; 761 rangeAttrs = [[NSArray alloc] initWithArray:tempArray]; 762 [tempArray release]; 763 } 764 if (menuBarAttrs == nil) { 765 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 766 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 767 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 768 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 769 menuBarAttrs = [[NSArray alloc] initWithArray:tempArray]; 770 [tempArray release]; 771 } 772 if (menuAttrs == nil) { 773 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 774 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 775 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 776 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 777 menuAttrs = [[NSArray alloc] initWithArray:tempArray]; 778 [tempArray release]; 779 } 780 if (menuItemAttrs == nil) { 781 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 782 [tempArray addObject:NSAccessibilityTitleAttribute]; 783 [tempArray addObject:NSAccessibilityHelpAttribute]; 784 [tempArray addObject:NSAccessibilitySelectedAttribute]; 785 [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute]; 786 [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute]; 787 [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute]; 788 [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute]; 789 [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute]; 790 [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute]; 791 [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute]; 792 menuItemAttrs = [[NSArray alloc] initWithArray:tempArray]; 793 [tempArray release]; 794 } 795 if (menuButtonAttrs == nil) { 796 menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute, 797 NSAccessibilityRoleDescriptionAttribute, 798 NSAccessibilityParentAttribute, 799 NSAccessibilityPositionAttribute, 800 NSAccessibilitySizeAttribute, 801 NSAccessibilityWindowAttribute, 802 NSAccessibilityTopLevelUIElementAttribute, 803 NSAccessibilityEnabledAttribute, 804 NSAccessibilityFocusedAttribute, 805 NSAccessibilityTitleAttribute, 806 NSAccessibilityChildrenAttribute, nil]; 807 } 808 if (controlAttrs == nil) { 809 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 810 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 811 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 812 [tempArray addObject:NSAccessibilityRequiredAttribute]; 813 controlAttrs = [[NSArray alloc] initWithArray:tempArray]; 814 [tempArray release]; 815 } 816 if (buttonAttrs == nil) { 817 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 818 // Buttons should not expose AXValue. 819 [tempArray removeObject:NSAccessibilityValueAttribute]; 820 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 821 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 822 buttonAttrs = [[NSArray alloc] initWithArray:tempArray]; 823 [tempArray release]; 824 } 825 if (comboBoxAttrs == nil) { 826 tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs]; 827 [tempArray addObject:NSAccessibilityExpandedAttribute]; 828 comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; 829 [tempArray release]; 830 } 831 if (tableAttrs == nil) { 832 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 833 [tempArray addObject:NSAccessibilityRowsAttribute]; 834 [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; 835 [tempArray addObject:NSAccessibilityColumnsAttribute]; 836 [tempArray addObject:NSAccessibilityVisibleColumnsAttribute]; 837 [tempArray addObject:NSAccessibilityVisibleCellsAttribute]; 838 [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute]; 839 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute]; 840 [tempArray addObject:NSAccessibilityHeaderAttribute]; 841 tableAttrs = [[NSArray alloc] initWithArray:tempArray]; 842 [tempArray release]; 843 } 844 if (tableRowAttrs == nil) { 845 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 846 [tempArray addObject:NSAccessibilityIndexAttribute]; 847 tableRowAttrs = [[NSArray alloc] initWithArray:tempArray]; 848 [tempArray release]; 849 } 850 if (tableColAttrs == nil) { 851 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 852 [tempArray addObject:NSAccessibilityIndexAttribute]; 853 [tempArray addObject:NSAccessibilityHeaderAttribute]; 854 [tempArray addObject:NSAccessibilityRowsAttribute]; 855 [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; 856 tableColAttrs = [[NSArray alloc] initWithArray:tempArray]; 857 [tempArray release]; 858 } 859 if (tableCellAttrs == nil) { 860 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 861 [tempArray addObject:NSAccessibilityRowIndexRangeAttribute]; 862 [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute]; 863 tableCellAttrs = [[NSArray alloc] initWithArray:tempArray]; 864 [tempArray release]; 865 } 866 if (groupAttrs == nil) { 867 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 868 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 869 groupAttrs = [[NSArray alloc] initWithArray:tempArray]; 870 [tempArray release]; 871 } 872 if (inputImageAttrs == nil) { 873 tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs]; 874 [tempArray addObject:NSAccessibilityURLAttribute]; 875 inputImageAttrs = [[NSArray alloc] initWithArray:tempArray]; 876 [tempArray release]; 877 } 878 if (passwordFieldAttrs == nil) { 879 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 880 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 881 [tempArray addObject:NSAccessibilityRequiredAttribute]; 882 passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray]; 883 [tempArray release]; 884 } 885 if (tabListAttrs == nil) { 886 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 887 [tempArray addObject:NSAccessibilityTabsAttribute]; 888 [tempArray addObject:NSAccessibilityContentsAttribute]; 889 tabListAttrs = [[NSArray alloc] initWithArray:tempArray]; 890 [tempArray release]; 891 } 892 if (outlineAttrs == nil) { 893 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 894 [tempArray addObject:NSAccessibilitySelectedRowsAttribute]; 895 [tempArray addObject:NSAccessibilityRowsAttribute]; 896 [tempArray addObject:NSAccessibilityColumnsAttribute]; 897 outlineAttrs = [[NSArray alloc] initWithArray:tempArray]; 898 [tempArray release]; 899 } 900 if (outlineRowAttrs == nil) { 901 tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs]; 902 [tempArray addObject:NSAccessibilityDisclosingAttribute]; 903 [tempArray addObject:NSAccessibilityDisclosedByRowAttribute]; 904 [tempArray addObject:NSAccessibilityDisclosureLevelAttribute]; 905 [tempArray addObject:NSAccessibilityDisclosedRowsAttribute]; 906 outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray]; 907 [tempArray release]; 908 } 909 910 NSArray *objectAttributes = attributes; 911 912 if (m_object->isPasswordField()) 913 objectAttributes = passwordFieldAttrs; 914 915 else if (m_object->isWebArea()) 916 objectAttributes = webAreaAttrs; 917 918 else if (m_object->isTextControl()) 919 objectAttributes = textAttrs; 920 921 else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink()) 922 objectAttributes = anchorAttrs; 923 924 else if (m_object->isDataTable()) 925 objectAttributes = tableAttrs; 926 else if (m_object->isTableColumn()) 927 objectAttributes = tableColAttrs; 928 else if (m_object->isTableCell()) 929 objectAttributes = tableCellAttrs; 930 else if (m_object->isTableRow()) { 931 // An ARIA table row can be collapsed and expanded, so it needs the extra attributes. 932 if (m_object->isARIATreeGridRow()) 933 objectAttributes = outlineRowAttrs; 934 else 935 objectAttributes = tableRowAttrs; 936 } 937 938 else if (m_object->isTree()) 939 objectAttributes = outlineAttrs; 940 else if (m_object->isTreeItem()) 941 objectAttributes = outlineRowAttrs; 942 943 else if (m_object->isListBox() || m_object->isList()) 944 objectAttributes = listBoxAttrs; 945 946 else if (m_object->isComboBox()) 947 objectAttributes = comboBoxAttrs; 948 949 else if (m_object->isProgressIndicator() || m_object->isSlider()) 950 objectAttributes = rangeAttrs; 951 952 // These are processed in order because an input image is a button, and a button is a control. 953 else if (m_object->isInputImage()) 954 objectAttributes = inputImageAttrs; 955 else if (m_object->isButton()) 956 objectAttributes = buttonAttrs; 957 else if (m_object->isControl()) 958 objectAttributes = controlAttrs; 959 960 else if (m_object->isGroup()) 961 objectAttributes = groupAttrs; 962 else if (m_object->isTabList()) 963 objectAttributes = tabListAttrs; 964 965 else if (m_object->isMenu()) 966 objectAttributes = menuAttrs; 967 else if (m_object->isMenuBar()) 968 objectAttributes = menuBarAttrs; 969 else if (m_object->isMenuButton()) 970 objectAttributes = menuButtonAttrs; 971 else if (m_object->isMenuItem()) 972 objectAttributes = menuItemAttrs; 973 974 NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames]; 975 if ([additionalAttributes count]) 976 objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes]; 977 978 return objectAttributes; 979} 980 981- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange 982{ 983 return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange)); 984} 985 986- (NSArray*)renderWidgetChildren 987{ 988 Widget* widget = m_object->widget(); 989 if (!widget) 990 return nil; 991 return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute]; 992} 993 994static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector) 995{ 996 unsigned length = [array count]; 997 vector.reserveInitialCapacity(length); 998 for (unsigned i = 0; i < length; ++i) { 999 AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject]; 1000 if (obj) 1001 vector.append(obj); 1002 } 1003} 1004 1005static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector) 1006{ 1007 unsigned length = vector.size(); 1008 NSMutableArray* array = [NSMutableArray arrayWithCapacity: length]; 1009 for (unsigned i = 0; i < length; ++i) { 1010 AccessibilityObjectWrapper* wrapper = vector[i]->wrapper(); 1011 ASSERT(wrapper); 1012 if (wrapper) { 1013 // we want to return the attachment view instead of the object representing the attachment. 1014 // otherwise, we get palindrome errors in the AX hierarchy 1015 if (vector[i]->isAttachment() && [wrapper attachmentView]) 1016 [array addObject:[wrapper attachmentView]]; 1017 else 1018 [array addObject:wrapper]; 1019 } 1020 } 1021 return array; 1022} 1023 1024- (WebCoreTextMarkerRange*)textMarkerRangeForSelection 1025{ 1026 VisibleSelection selection = m_object->selection(); 1027 if (selection.isNone()) 1028 return nil; 1029 return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd()); 1030} 1031 1032- (NSValue*)position 1033{ 1034 IntRect rect = m_object->elementRect(); 1035 1036 // The Cocoa accessibility API wants the lower-left corner. 1037 NSPoint point = NSMakePoint(rect.x(), rect.bottom()); 1038 FrameView* frameView = m_object->documentFrameView(); 1039 if (frameView) { 1040 NSView* view = frameView->documentView(); 1041 point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]]; 1042 } 1043 1044 return [NSValue valueWithPoint: point]; 1045} 1046 1047typedef HashMap<int, NSString*> AccessibilityRoleMap; 1048 1049static const AccessibilityRoleMap& createAccessibilityRoleMap() 1050{ 1051 struct RoleEntry { 1052 AccessibilityRole value; 1053 NSString* string; 1054 }; 1055 1056 static const RoleEntry roles[] = { 1057 { UnknownRole, NSAccessibilityUnknownRole }, 1058 { ButtonRole, NSAccessibilityButtonRole }, 1059 { RadioButtonRole, NSAccessibilityRadioButtonRole }, 1060 { CheckBoxRole, NSAccessibilityCheckBoxRole }, 1061 { SliderRole, NSAccessibilitySliderRole }, 1062 { TabGroupRole, NSAccessibilityTabGroupRole }, 1063 { TextFieldRole, NSAccessibilityTextFieldRole }, 1064 { StaticTextRole, NSAccessibilityStaticTextRole }, 1065 { TextAreaRole, NSAccessibilityTextAreaRole }, 1066 { ScrollAreaRole, NSAccessibilityScrollAreaRole }, 1067 { PopUpButtonRole, NSAccessibilityPopUpButtonRole }, 1068 { MenuButtonRole, NSAccessibilityMenuButtonRole }, 1069 { TableRole, NSAccessibilityTableRole }, 1070 { ApplicationRole, NSAccessibilityApplicationRole }, 1071 { GroupRole, NSAccessibilityGroupRole }, 1072 { RadioGroupRole, NSAccessibilityRadioGroupRole }, 1073 { ListRole, NSAccessibilityListRole }, 1074 { DirectoryRole, NSAccessibilityListRole }, 1075 { ScrollBarRole, NSAccessibilityScrollBarRole }, 1076 { ValueIndicatorRole, NSAccessibilityValueIndicatorRole }, 1077 { ImageRole, NSAccessibilityImageRole }, 1078 { MenuBarRole, NSAccessibilityMenuBarRole }, 1079 { MenuRole, NSAccessibilityMenuRole }, 1080 { MenuItemRole, NSAccessibilityMenuItemRole }, 1081 { ColumnRole, NSAccessibilityColumnRole }, 1082 { RowRole, NSAccessibilityRowRole }, 1083 { ToolbarRole, NSAccessibilityToolbarRole }, 1084 { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole }, 1085 { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole }, 1086 { WindowRole, NSAccessibilityWindowRole }, 1087 { DrawerRole, NSAccessibilityDrawerRole }, 1088 { SystemWideRole, NSAccessibilitySystemWideRole }, 1089 { OutlineRole, NSAccessibilityOutlineRole }, 1090 { IncrementorRole, NSAccessibilityIncrementorRole }, 1091 { BrowserRole, NSAccessibilityBrowserRole }, 1092 { ComboBoxRole, NSAccessibilityComboBoxRole }, 1093 { SplitGroupRole, NSAccessibilitySplitGroupRole }, 1094 { SplitterRole, NSAccessibilitySplitterRole }, 1095 { ColorWellRole, NSAccessibilityColorWellRole }, 1096 { GrowAreaRole, NSAccessibilityGrowAreaRole }, 1097 { SheetRole, NSAccessibilitySheetRole }, 1098 { HelpTagRole, NSAccessibilityHelpTagRole }, 1099 { MatteRole, NSAccessibilityMatteRole }, 1100 { RulerRole, NSAccessibilityRulerRole }, 1101 { RulerMarkerRole, NSAccessibilityRulerMarkerRole }, 1102 { LinkRole, NSAccessibilityLinkRole }, 1103#ifndef BUILDING_ON_TIGER 1104 { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole }, 1105 { GridRole, NSAccessibilityGridRole }, 1106#endif 1107 { WebCoreLinkRole, NSAccessibilityLinkRole }, 1108 { ImageMapLinkRole, NSAccessibilityLinkRole }, 1109 { ImageMapRole, @"AXImageMap" }, 1110 { ListMarkerRole, @"AXListMarker" }, 1111 { WebAreaRole, @"AXWebArea" }, 1112 { HeadingRole, @"AXHeading" }, 1113 { ListBoxRole, NSAccessibilityListRole }, 1114 { ListBoxOptionRole, NSAccessibilityStaticTextRole }, 1115#if ACCESSIBILITY_TABLES 1116 { CellRole, NSAccessibilityCellRole }, 1117#else 1118 { CellRole, NSAccessibilityGroupRole }, 1119#endif 1120 { TableHeaderContainerRole, NSAccessibilityGroupRole }, 1121 { DefinitionListDefinitionRole, NSAccessibilityGroupRole }, 1122 { DefinitionListTermRole, NSAccessibilityGroupRole }, 1123 { SliderThumbRole, NSAccessibilityValueIndicatorRole }, 1124 { LandmarkApplicationRole, NSAccessibilityGroupRole }, 1125 { LandmarkBannerRole, NSAccessibilityGroupRole }, 1126 { LandmarkComplementaryRole, NSAccessibilityGroupRole }, 1127 { LandmarkContentInfoRole, NSAccessibilityGroupRole }, 1128 { LandmarkMainRole, NSAccessibilityGroupRole }, 1129 { LandmarkNavigationRole, NSAccessibilityGroupRole }, 1130 { LandmarkSearchRole, NSAccessibilityGroupRole }, 1131 { ApplicationAlertRole, NSAccessibilityGroupRole }, 1132 { ApplicationAlertDialogRole, NSAccessibilityGroupRole }, 1133 { ApplicationDialogRole, NSAccessibilityGroupRole }, 1134 { ApplicationLogRole, NSAccessibilityGroupRole }, 1135 { ApplicationMarqueeRole, NSAccessibilityGroupRole }, 1136 { ApplicationStatusRole, NSAccessibilityGroupRole }, 1137 { ApplicationTimerRole, NSAccessibilityGroupRole }, 1138 { DocumentRole, NSAccessibilityGroupRole }, 1139 { DocumentArticleRole, NSAccessibilityGroupRole }, 1140 { DocumentMathRole, NSAccessibilityGroupRole }, 1141 { DocumentNoteRole, NSAccessibilityGroupRole }, 1142 { DocumentRegionRole, NSAccessibilityGroupRole }, 1143 { UserInterfaceTooltipRole, NSAccessibilityGroupRole }, 1144 { TabRole, NSAccessibilityRadioButtonRole }, 1145 { TabListRole, NSAccessibilityTabGroupRole }, 1146 { TabPanelRole, NSAccessibilityGroupRole }, 1147 { TreeRole, NSAccessibilityOutlineRole }, 1148 { TreeItemRole, NSAccessibilityRowRole }, 1149 }; 1150 AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap; 1151 1152 const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); 1153 for (unsigned i = 0; i < numRoles; ++i) 1154 roleMap.set(roles[i].value, roles[i].string); 1155 return roleMap; 1156} 1157 1158static NSString* roleValueToNSString(AccessibilityRole value) 1159{ 1160 ASSERT(value); 1161 static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap(); 1162 return roleMap.get(value); 1163} 1164 1165- (NSString*)role 1166{ 1167 if (m_object->isAttachment()) 1168 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute]; 1169 NSString* string = roleValueToNSString(m_object->roleValue()); 1170 if (string != nil) 1171 return string; 1172 return NSAccessibilityUnknownRole; 1173} 1174 1175- (NSString*)subrole 1176{ 1177 if (m_object->isPasswordField()) 1178 return NSAccessibilitySecureTextFieldSubrole; 1179 1180 if (m_object->isAttachment()) { 1181 NSView* attachView = [self attachmentView]; 1182 if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) { 1183 return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute]; 1184 } 1185 } 1186 1187 if (m_object->isTreeItem()) 1188 return NSAccessibilityOutlineRowSubrole; 1189 1190 if (m_object->isList()) { 1191 AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object); 1192 if (listObject->isUnorderedList() || listObject->isOrderedList()) 1193 return NSAccessibilityContentListSubrole; 1194 if (listObject->isDefinitionList()) 1195 return NSAccessibilityDefinitionListSubrole; 1196 } 1197 1198 // ARIA content subroles. 1199 switch (m_object->roleValue()) { 1200 case LandmarkApplicationRole: 1201 return @"AXLandmarkApplication"; 1202 case LandmarkBannerRole: 1203 return @"AXLandmarkBanner"; 1204 case LandmarkComplementaryRole: 1205 return @"AXLandmarkComplementary"; 1206 case LandmarkContentInfoRole: 1207 return @"AXLandmarkContentInfo"; 1208 case LandmarkMainRole: 1209 return @"AXLandmarkMain"; 1210 case LandmarkNavigationRole: 1211 return @"AXLandmarkNavigation"; 1212 case LandmarkSearchRole: 1213 return @"AXLandmarkSearch"; 1214 case ApplicationAlertRole: 1215 return @"AXApplicationAlert"; 1216 case ApplicationAlertDialogRole: 1217 return @"AXApplicationAlertDialog"; 1218 case ApplicationDialogRole: 1219 return @"AXApplicationDialog"; 1220 case ApplicationLogRole: 1221 return @"AXApplicationLog"; 1222 case ApplicationMarqueeRole: 1223 return @"AXApplicationMarquee"; 1224 case ApplicationStatusRole: 1225 return @"AXApplicationStatus"; 1226 case ApplicationTimerRole: 1227 return @"AXApplicationTimer"; 1228 case DocumentRole: 1229 return @"AXDocument"; 1230 case DocumentArticleRole: 1231 return @"AXDocumentArticle"; 1232 case DocumentMathRole: 1233 return @"AXDocumentMath"; 1234 case DocumentNoteRole: 1235 return @"AXDocumentNote"; 1236 case DocumentRegionRole: 1237 return @"AXDocumentRegion"; 1238 case UserInterfaceTooltipRole: 1239 return @"AXUserInterfaceTooltip"; 1240 case TabPanelRole: 1241 return @"AXTabPanel"; 1242 case DefinitionListTermRole: 1243 return @"AXTerm"; 1244 case DefinitionListDefinitionRole: 1245 return @"AXDefinition"; 1246 // Default doesn't return anything, so roles defined below can be chosen. 1247 default: 1248 break; 1249 } 1250 1251 if (m_object->isMediaTimeline()) 1252 return NSAccessibilityTimelineSubrole; 1253 1254 return nil; 1255} 1256 1257- (NSString*)roleDescription 1258{ 1259 if (!m_object) 1260 return nil; 1261 1262 // attachments have the AXImage role, but a different subrole 1263 if (m_object->isAttachment()) 1264 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute]; 1265 1266 NSString* axRole = [self role]; 1267 1268 if ([axRole isEqualToString:NSAccessibilityGroupRole]) { 1269 switch (m_object->roleValue()) { 1270 default: 1271 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]); 1272 case LandmarkApplicationRole: 1273 return AXARIAContentGroupText(@"ARIALandmarkApplication"); 1274 case LandmarkBannerRole: 1275 return AXARIAContentGroupText(@"ARIALandmarkBanner"); 1276 case LandmarkComplementaryRole: 1277 return AXARIAContentGroupText(@"ARIALandmarkComplementary"); 1278 case LandmarkContentInfoRole: 1279 return AXARIAContentGroupText(@"ARIALandmarkContentInfo"); 1280 case LandmarkMainRole: 1281 return AXARIAContentGroupText(@"ARIALandmarkMain"); 1282 case LandmarkNavigationRole: 1283 return AXARIAContentGroupText(@"ARIALandmarkNavigation"); 1284 case LandmarkSearchRole: 1285 return AXARIAContentGroupText(@"ARIALandmarkSearch"); 1286 case ApplicationAlertRole: 1287 return AXARIAContentGroupText(@"ARIAApplicationAlert"); 1288 case ApplicationAlertDialogRole: 1289 return AXARIAContentGroupText(@"ARIAApplicationAlertDialog"); 1290 case ApplicationDialogRole: 1291 return AXARIAContentGroupText(@"ARIAApplicationDialog"); 1292 case ApplicationLogRole: 1293 return AXARIAContentGroupText(@"ARIAApplicationLog"); 1294 case ApplicationMarqueeRole: 1295 return AXARIAContentGroupText(@"ARIAApplicationMarquee"); 1296 case ApplicationStatusRole: 1297 return AXARIAContentGroupText(@"ARIAApplicationStatus"); 1298 case ApplicationTimerRole: 1299 return AXARIAContentGroupText(@"ARIAApplicationTimer"); 1300 case DocumentRole: 1301 return AXARIAContentGroupText(@"ARIADocument"); 1302 case DocumentArticleRole: 1303 return AXARIAContentGroupText(@"ARIADocumentArticle"); 1304 case DocumentMathRole: 1305 return AXARIAContentGroupText(@"ARIADocumentMath"); 1306 case DocumentNoteRole: 1307 return AXARIAContentGroupText(@"ARIADocumentNote"); 1308 case DocumentRegionRole: 1309 return AXARIAContentGroupText(@"ARIADocumentRegion"); 1310 case UserInterfaceTooltipRole: 1311 return AXARIAContentGroupText(@"ARIAUserInterfaceTooltip"); 1312 case TabPanelRole: 1313 return AXARIAContentGroupText(@"ARIATabPanel"); 1314 case DefinitionListTermRole: 1315 return AXDefinitionListTermText(); 1316 case DefinitionListDefinitionRole: 1317 return AXDefinitionListDefinitionText(); 1318 } 1319 } 1320 1321 if ([axRole isEqualToString:@"AXWebArea"]) 1322 return AXWebAreaText(); 1323 1324 if ([axRole isEqualToString:@"AXLink"]) 1325 return AXLinkText(); 1326 1327 if ([axRole isEqualToString:@"AXListMarker"]) 1328 return AXListMarkerText(); 1329 1330 if ([axRole isEqualToString:@"AXImageMap"]) 1331 return AXImageMapText(); 1332 1333 if ([axRole isEqualToString:@"AXHeading"]) 1334 return AXHeadingText(); 1335 1336 // AppKit also returns AXTab for the role description for a tab item. 1337 if (m_object->isTabItem()) 1338 return NSAccessibilityRoleDescription(@"AXTab", nil); 1339 1340 // We should try the system default role description for all other roles. 1341 // If we get the same string back, then as a last resort, return unknown. 1342 NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]); 1343 if (![defaultRoleDescription isEqualToString:axRole]) 1344 return defaultRoleDescription; 1345 1346 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil); 1347} 1348 1349// FIXME: split up this function in a better way. 1350// suggestions: Use a hash table that maps attribute names to function calls, 1351// or maybe pointers to member functions 1352- (id)accessibilityAttributeValue:(NSString*)attributeName 1353{ 1354 if (!m_object) 1355 return nil; 1356 1357 m_object->updateBackingStore(); 1358 if (!m_object) 1359 return nil; 1360 1361 if ([attributeName isEqualToString: NSAccessibilityRoleAttribute]) 1362 return [self role]; 1363 1364 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute]) 1365 return [self subrole]; 1366 1367 if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute]) 1368 return [self roleDescription]; 1369 1370 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) { 1371 if (m_object->isAccessibilityRenderObject()) { 1372 FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView(); 1373 if (fv) 1374 return fv->platformWidget(); 1375 } 1376 1377 // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent. 1378 if (m_object->isTreeItem()) { 1379 AccessibilityObject* parent = m_object->parentObjectUnignored(); 1380 while (parent) { 1381 if (parent->isTree()) 1382 return parent->wrapper(); 1383 parent = parent->parentObjectUnignored(); 1384 } 1385 } 1386 1387 return m_object->parentObjectUnignored()->wrapper(); 1388 } 1389 1390 if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) { 1391 if (m_object->children().isEmpty()) { 1392 NSArray* children = [self renderWidgetChildren]; 1393 if (children != nil) 1394 return children; 1395 } 1396 1397 // The tree's (AXOutline) children are supposed to be its rows and columns. 1398 // The ARIA spec doesn't have columns, so we just need rows. 1399 if (m_object->isTree()) 1400 return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute]; 1401 1402 // A tree item should only expose its content as its children (not its rows) 1403 if (m_object->isTreeItem()) { 1404 AccessibilityObject::AccessibilityChildrenVector contentCopy; 1405 m_object->ariaTreeItemContent(contentCopy); 1406 return convertToNSArray(contentCopy); 1407 } 1408 1409 return convertToNSArray(m_object->children()); 1410 } 1411 1412 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { 1413 if (m_object->isListBox()) { 1414 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 1415 m_object->selectedChildren(selectedChildrenCopy); 1416 return convertToNSArray(selectedChildrenCopy); 1417 } 1418 return nil; 1419 } 1420 1421 if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) { 1422 if (m_object->isListBox()) { 1423 AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy; 1424 m_object->visibleChildren(visibleChildrenCopy); 1425 return convertToNSArray(visibleChildrenCopy); 1426 } 1427 else if (m_object->isList()) 1428 return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; 1429 1430 return nil; 1431 } 1432 1433 1434 if (m_object->isWebArea()) { 1435 if ([attributeName isEqualToString:@"AXLinkUIElements"]) { 1436 AccessibilityObject::AccessibilityChildrenVector links; 1437 static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links); 1438 return convertToNSArray(links); 1439 } 1440 if ([attributeName isEqualToString:@"AXLoaded"]) 1441 return [NSNumber numberWithBool:m_object->isLoaded()]; 1442 if ([attributeName isEqualToString:@"AXLayoutCount"]) 1443 return [NSNumber numberWithInt:m_object->layoutCount()]; 1444 if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute]) 1445 return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()]; 1446 } 1447 1448 if (m_object->isTextControl()) { 1449 if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) { 1450 int length = m_object->textLength(); 1451 if (length < 0) 1452 return nil; 1453 return [NSNumber numberWithUnsignedInt:length]; 1454 } 1455 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { 1456 String selectedText = m_object->selectedText(); 1457 if (selectedText.isNull()) 1458 return nil; 1459 return (NSString*)selectedText; 1460 } 1461 if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { 1462 PlainTextRange textRange = m_object->selectedTextRange(); 1463 if (textRange.isNull()) 1464 return nil; 1465 return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)]; 1466 } 1467 // TODO: Get actual visible range. <rdar://problem/4712101> 1468 if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) 1469 return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())]; 1470 if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) { 1471 // if selectionEnd > 0, then there is selected text and this question should not be answered 1472 if (m_object->isPasswordField() || m_object->selectionEnd() > 0) 1473 return nil; 1474 int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true)); 1475 if (lineNumber < 0) 1476 return nil; 1477 return [NSNumber numberWithInt:lineNumber]; 1478 } 1479 } 1480 1481 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) { 1482 KURL url = m_object->url(); 1483 if (url.isNull()) 1484 return nil; 1485 return (NSURL*)url; 1486 } 1487 1488 if ([attributeName isEqualToString: @"AXVisited"]) 1489 return [NSNumber numberWithBool: m_object->isVisited()]; 1490 1491 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) { 1492 if (m_object->isAttachment()) { 1493 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 1494 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute]; 1495 } 1496 return m_object->title(); 1497 } 1498 1499 if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) { 1500 if (m_object->isAttachment()) { 1501 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute]) 1502 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute]; 1503 } 1504 return m_object->accessibilityDescription(); 1505 } 1506 1507 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { 1508 if (m_object->isAttachment()) { 1509 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 1510 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute]; 1511 } 1512 if (m_object->isProgressIndicator() || m_object->isSlider() || m_object->isScrollbar()) 1513 return [NSNumber numberWithFloat:m_object->valueForRange()]; 1514 if (m_object->hasIntValue()) 1515 return [NSNumber numberWithInt:m_object->intValue()]; 1516 1517 // radio groups return the selected radio button as the AXValue 1518 if (m_object->isRadioGroup()) { 1519 AccessibilityObject* radioButton = m_object->selectedRadioButton(); 1520 if (!radioButton) 1521 return nil; 1522 return radioButton->wrapper(); 1523 } 1524 1525 if (m_object->isTabList()) { 1526 AccessibilityObject* tabItem = m_object->selectedTabItem(); 1527 if (!tabItem) 1528 return nil; 1529 return tabItem->wrapper(); 1530 } 1531 1532 if (m_object->isTabItem()) 1533 return [NSNumber numberWithInt:m_object->isSelected()]; 1534 1535 return m_object->stringValue(); 1536 } 1537 1538 if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) 1539 return [NSNumber numberWithFloat:m_object->minValueForRange()]; 1540 1541 if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) 1542 return [NSNumber numberWithFloat:m_object->maxValueForRange()]; 1543 1544 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute]) 1545 return m_object->helpText(); 1546 1547 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) 1548 return [NSNumber numberWithBool: m_object->isFocused()]; 1549 1550 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute]) 1551 return [NSNumber numberWithBool: m_object->isEnabled()]; 1552 1553 if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) { 1554 IntSize s = m_object->size(); 1555 return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())]; 1556 } 1557 1558 if ([attributeName isEqualToString: NSAccessibilityPositionAttribute]) 1559 return [self position]; 1560 1561 if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] || 1562 [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) { 1563 FrameView* fv = m_object->documentFrameView(); 1564 if (fv) 1565 return [fv->platformWidget() window]; 1566 return nil; 1567 } 1568 1569 if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) { 1570 AtomicString accessKey = m_object->accessKey(); 1571 if (accessKey.isNull()) 1572 return nil; 1573 return accessKey; 1574 } 1575 1576 if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) { 1577 if (m_object->isTabList()) { 1578 AccessibilityObject::AccessibilityChildrenVector tabsChildren; 1579 m_object->tabChildren(tabsChildren); 1580 return convertToNSArray(tabsChildren); 1581 } 1582 } 1583 1584 if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) { 1585 // The contents of a tab list are all the children except the tabs. 1586 if (m_object->isTabList()) { 1587 AccessibilityObject::AccessibilityChildrenVector children = m_object->children(); 1588 AccessibilityObject::AccessibilityChildrenVector tabsChildren; 1589 m_object->tabChildren(tabsChildren); 1590 1591 AccessibilityObject::AccessibilityChildrenVector contents; 1592 unsigned childrenSize = children.size(); 1593 for (unsigned k = 0; k < childrenSize; ++k) { 1594 if (tabsChildren.find(children[k]) == WTF::notFound) 1595 contents.append(children[k]); 1596 } 1597 return convertToNSArray(contents); 1598 } 1599 } 1600 1601 if (m_object->isDataTable()) { 1602 // TODO: distinguish between visible and non-visible rows 1603 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 1604 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { 1605 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows()); 1606 } 1607 // TODO: distinguish between visible and non-visible columns 1608 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] || 1609 [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) { 1610 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns()); 1611 } 1612 1613 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 1614 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 1615 m_object->selectedChildren(selectedChildrenCopy); 1616 return convertToNSArray(selectedChildrenCopy); 1617 } 1618 1619 // HTML tables don't support these 1620 if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] || 1621 [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute]) 1622 return nil; 1623 1624 if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) { 1625 AccessibilityObject::AccessibilityChildrenVector columnHeaders; 1626 static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders); 1627 return convertToNSArray(columnHeaders); 1628 } 1629 1630 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { 1631 AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer(); 1632 if (headerContainer) 1633 return headerContainer->wrapper(); 1634 return nil; 1635 } 1636 1637 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) { 1638 AccessibilityObject::AccessibilityChildrenVector rowHeaders; 1639 static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders); 1640 return convertToNSArray(rowHeaders); 1641 } 1642 1643 if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) { 1644 AccessibilityObject::AccessibilityChildrenVector cells; 1645 static_cast<AccessibilityTable*>(m_object)->cells(cells); 1646 return convertToNSArray(cells); 1647 } 1648 } 1649 1650 if (m_object->isTableColumn()) { 1651 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) 1652 return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()]; 1653 1654 // rows attribute for a column is the list of all the elements in that column at each row 1655 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 1656 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { 1657 return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children()); 1658 } 1659 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { 1660 AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject(); 1661 if (!header) 1662 return nil; 1663 return header->wrapper(); 1664 } 1665 } 1666 1667 if (m_object->isTableCell()) { 1668 if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) { 1669 pair<int, int> rowRange; 1670 static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange); 1671 return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)]; 1672 } 1673 if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) { 1674 pair<int, int> columnRange; 1675 static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange); 1676 return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)]; 1677 } 1678 } 1679 1680 if (m_object->isTree()) { 1681 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 1682 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 1683 m_object->selectedChildren(selectedChildrenCopy); 1684 return convertToNSArray(selectedChildrenCopy); 1685 } 1686 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) { 1687 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 1688 m_object->ariaTreeRows(rowsCopy); 1689 return convertToNSArray(rowsCopy); 1690 } 1691 1692 // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least. 1693 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]) 1694 return [NSArray array]; 1695 } 1696 1697 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) { 1698 if (m_object->isTreeItem()) { 1699 AccessibilityObject* parent = m_object->parentObject(); 1700 for (; parent && !parent->isTree(); parent = parent->parentObject()) 1701 { } 1702 1703 if (!parent) 1704 return nil; 1705 1706 // Find the index of this item by iterating the parents. 1707 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 1708 parent->ariaTreeRows(rowsCopy); 1709 size_t count = rowsCopy.size(); 1710 for (size_t k = 0; k < count; ++k) 1711 if (rowsCopy[k]->wrapper() == self) 1712 return [NSNumber numberWithUnsignedInt:k]; 1713 1714 return nil; 1715 } 1716 if (m_object->isTableRow()) { 1717 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) 1718 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()]; 1719 } 1720 } 1721 1722 // The rows that are considered inside this row. 1723 if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) { 1724 if (m_object->isTreeItem()) { 1725 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 1726 m_object->ariaTreeItemDisclosedRows(rowsCopy); 1727 return convertToNSArray(rowsCopy); 1728 } else if (m_object->isARIATreeGridRow()) { 1729 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 1730 static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy); 1731 return convertToNSArray(rowsCopy); 1732 } 1733 } 1734 1735 // The row that contains this row. It should be the same as the first parent that is a treeitem. 1736 if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) { 1737 if (m_object->isTreeItem()) { 1738 AccessibilityObject* parent = m_object->parentObject(); 1739 while (parent) { 1740 if (parent->isTreeItem()) 1741 return parent->wrapper(); 1742 // If the parent is the tree itself, then this value == nil. 1743 if (parent->isTree()) 1744 return nil; 1745 parent = parent->parentObject(); 1746 } 1747 return nil; 1748 } else if (m_object->isARIATreeGridRow()) { 1749 AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow(); 1750 if (!row) 1751 return nil; 1752 return row->wrapper(); 1753 } 1754 } 1755 1756 if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) 1757 return [NSNumber numberWithInt:m_object->hierarchicalLevel()]; 1758 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 1759 return [NSNumber numberWithBool:m_object->isExpanded()]; 1760 1761 if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute]) 1762 return NSAccessibilityVerticalOrientationValue; 1763 1764 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) 1765 return [self textMarkerRangeForSelection]; 1766 1767 if (m_object->isAccessibilityRenderObject()) { 1768 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer(); 1769 if (!renderer) 1770 return nil; 1771 1772 if ([attributeName isEqualToString: @"AXStartTextMarker"]) 1773 return textMarkerForVisiblePosition(startOfDocument(renderer->document())); 1774 if ([attributeName isEqualToString: @"AXEndTextMarker"]) 1775 return textMarkerForVisiblePosition(endOfDocument(renderer->document())); 1776 1777 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) 1778 return [NSNumber numberWithInt:blockquoteLevel(renderer)]; 1779 } else { 1780 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) { 1781 AccessibilityObject* parent = m_object->parentObjectUnignored(); 1782 if (!parent) 1783 return [NSNumber numberWithInt:0]; 1784 return [parent->wrapper() accessibilityAttributeValue:NSAccessibilityBlockQuoteLevelAttribute]; 1785 } 1786 } 1787 1788 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) { 1789 AccessibilityObject::AccessibilityChildrenVector linkedUIElements; 1790 m_object->linkedUIElements(linkedUIElements); 1791 if (linkedUIElements.size() == 0) 1792 return nil; 1793 return convertToNSArray(linkedUIElements); 1794 } 1795 1796 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) 1797 return [NSNumber numberWithBool:m_object->isSelected()]; 1798 1799 if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) { 1800 AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton(); 1801 if (uiElement) 1802 return [NSArray arrayWithObject:uiElement->wrapper()]; 1803 } 1804 1805 if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) { 1806 AccessibilityObject* obj = m_object->titleUIElement(); 1807 if (obj) 1808 return obj->wrapper(); 1809 return nil; 1810 } 1811 1812 if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute]) 1813 return m_object->valueDescription(); 1814 1815 if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) { 1816 AccessibilityOrientation elementOrientation = m_object->orientation(); 1817 if (elementOrientation == AccessibilityOrientationVertical) 1818 return NSAccessibilityVerticalOrientationValue; 1819 if (elementOrientation == AccessibilityOrientationHorizontal) 1820 return NSAccessibilityHorizontalOrientationValue; 1821 return nil; 1822 } 1823 1824 if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute]) 1825 return m_object->language(); 1826 1827 if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute]) 1828 return [NSNumber numberWithBool:m_object->isExpanded()]; 1829 1830 if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute]) 1831 return [NSNumber numberWithBool:m_object->isRequired()]; 1832 1833 if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) { 1834 AccessibilityObject::AccessibilityChildrenVector ariaOwns; 1835 m_object->ariaOwnsElements(ariaOwns); 1836 return convertToNSArray(ariaOwns); 1837 } 1838 1839 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 1840 return [NSNumber numberWithBool:m_object->isARIAGrabbed()]; 1841 1842 if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) { 1843 Vector<String> dropEffects; 1844 m_object->determineARIADropEffects(dropEffects); 1845 size_t length = dropEffects.size(); 1846 1847 NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length]; 1848 for (size_t i = 0; i < length; ++i) 1849 [dropEffectsArray addObject:dropEffects[i]]; 1850 return dropEffectsArray; 1851 } 1852 1853 // ARIA Live region attributes. 1854 if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute]) 1855 return m_object->ariaLiveRegionStatus(); 1856 if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute]) 1857 return m_object->ariaLiveRegionRelevant(); 1858 if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute]) 1859 return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()]; 1860 if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute]) 1861 return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()]; 1862 1863 // this is used only by DumpRenderTree for testing 1864 if ([attributeName isEqualToString:@"AXClickPoint"]) 1865 return [NSValue valueWithPoint:m_object->clickPoint()]; 1866 1867 return nil; 1868} 1869 1870- (id)accessibilityFocusedUIElement 1871{ 1872 if (!m_object) 1873 return nil; 1874 1875 m_object->updateBackingStore(); 1876 if (!m_object) 1877 return nil; 1878 1879 RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement(); 1880 1881 if (!focusedObj) 1882 return nil; 1883 1884 return focusedObj->wrapper(); 1885} 1886 1887- (id)accessibilityHitTest:(NSPoint)point 1888{ 1889 if (!m_object) 1890 return nil; 1891 1892 m_object->updateBackingStore(); 1893 if (!m_object) 1894 return nil; 1895 1896 RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point)); 1897 if (axObject) 1898 return NSAccessibilityUnignoredAncestor(axObject->wrapper()); 1899 return NSAccessibilityUnignoredAncestor(self); 1900} 1901 1902- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName 1903{ 1904 if (!m_object) 1905 return nil; 1906 1907 m_object->updateBackingStore(); 1908 if (!m_object) 1909 return nil; 1910 1911 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) 1912 return YES; 1913 1914 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) 1915 return m_object->canSetFocusAttribute(); 1916 1917 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) 1918 return m_object->canSetValueAttribute(); 1919 1920 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) 1921 return m_object->canSetSelectedAttribute(); 1922 1923 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) 1924 return m_object->canSetSelectedChildrenAttribute(); 1925 1926 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 1927 return m_object->canSetExpandedAttribute(); 1928 1929 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) 1930 return YES; 1931 1932 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] || 1933 [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] || 1934 [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) 1935 return m_object->canSetTextRangeAttributes(); 1936 1937 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 1938 return YES; 1939 1940 return NO; 1941} 1942 1943// accessibilityShouldUseUniqueId is an AppKit method we override so that 1944// objects will be given a unique ID, and therefore allow AppKit to know when they 1945// become obsolete (e.g. when the user navigates to a new web page, making this one 1946// unrendered but not deallocated because it is in the back/forward cache). 1947// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the 1948// appropriate place (e.g. dealloc) to remove these non-retained references from 1949// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement. 1950// 1951// Registering an object is also required for observing notifications. Only registered objects can be observed. 1952- (BOOL)accessibilityIsIgnored 1953{ 1954 if (!m_object) 1955 return nil; 1956 1957 m_object->updateBackingStore(); 1958 if (!m_object) 1959 return nil; 1960 1961 if (m_object->isAttachment()) 1962 return [[self attachmentView] accessibilityIsIgnored]; 1963 return m_object->accessibilityIsIgnored(); 1964} 1965 1966- (NSArray* )accessibilityParameterizedAttributeNames 1967{ 1968 if (!m_object) 1969 return nil; 1970 1971 m_object->updateBackingStore(); 1972 if (!m_object) 1973 return nil; 1974 1975 if (m_object->isAttachment()) 1976 return nil; 1977 1978 static NSArray* paramAttrs = nil; 1979 static NSArray* textParamAttrs = nil; 1980 static NSArray* tableParamAttrs = nil; 1981 if (paramAttrs == nil) { 1982 paramAttrs = [[NSArray alloc] initWithObjects: 1983 @"AXUIElementForTextMarker", 1984 @"AXTextMarkerRangeForUIElement", 1985 @"AXLineForTextMarker", 1986 @"AXTextMarkerRangeForLine", 1987 @"AXStringForTextMarkerRange", 1988 @"AXTextMarkerForPosition", 1989 @"AXBoundsForTextMarkerRange", 1990 @"AXAttributedStringForTextMarkerRange", 1991 @"AXTextMarkerRangeForUnorderedTextMarkers", 1992 @"AXNextTextMarkerForTextMarker", 1993 @"AXPreviousTextMarkerForTextMarker", 1994 @"AXLeftWordTextMarkerRangeForTextMarker", 1995 @"AXRightWordTextMarkerRangeForTextMarker", 1996 @"AXLeftLineTextMarkerRangeForTextMarker", 1997 @"AXRightLineTextMarkerRangeForTextMarker", 1998 @"AXSentenceTextMarkerRangeForTextMarker", 1999 @"AXParagraphTextMarkerRangeForTextMarker", 2000 @"AXNextWordEndTextMarkerForTextMarker", 2001 @"AXPreviousWordStartTextMarkerForTextMarker", 2002 @"AXNextLineEndTextMarkerForTextMarker", 2003 @"AXPreviousLineStartTextMarkerForTextMarker", 2004 @"AXNextSentenceEndTextMarkerForTextMarker", 2005 @"AXPreviousSentenceStartTextMarkerForTextMarker", 2006 @"AXNextParagraphEndTextMarkerForTextMarker", 2007 @"AXPreviousParagraphStartTextMarkerForTextMarker", 2008 @"AXStyleTextMarkerRangeForTextMarker", 2009 @"AXLengthForTextMarkerRange", 2010 NSAccessibilityBoundsForRangeParameterizedAttribute, 2011 NSAccessibilityStringForRangeParameterizedAttribute, 2012 nil]; 2013 } 2014 2015 if (textParamAttrs == nil) { 2016 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; 2017 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute]; 2018 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute]; 2019 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute]; 2020 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute]; 2021 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute]; 2022 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute]; 2023 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute]; 2024 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute]; 2025 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute]; 2026 textParamAttrs = [[NSArray alloc] initWithArray:tempArray]; 2027 [tempArray release]; 2028 } 2029 if (tableParamAttrs == nil) { 2030 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; 2031 [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute]; 2032 tableParamAttrs = [[NSArray alloc] initWithArray:tempArray]; 2033 [tempArray release]; 2034 } 2035 2036 if (m_object->isPasswordField()) 2037 return [NSArray array]; 2038 2039 if (!m_object->isAccessibilityRenderObject()) 2040 return paramAttrs; 2041 2042 if (m_object->isTextControl()) 2043 return textParamAttrs; 2044 2045 if (m_object->isDataTable()) 2046 return tableParamAttrs; 2047 2048 if (m_object->isMenuRelated()) 2049 return nil; 2050 2051 return paramAttrs; 2052} 2053 2054- (void)accessibilityPerformPressAction 2055{ 2056 if (!m_object) 2057 return; 2058 2059 m_object->updateBackingStore(); 2060 if (!m_object) 2061 return; 2062 2063 if (m_object->isAttachment()) 2064 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction]; 2065 else 2066 m_object->press(); 2067} 2068 2069- (void)accessibilityPerformIncrementAction 2070{ 2071 if (!m_object) 2072 return; 2073 2074 m_object->updateBackingStore(); 2075 if (!m_object) 2076 return; 2077 2078 if (m_object->isAttachment()) 2079 [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction]; 2080 else 2081 m_object->increment(); 2082} 2083 2084- (void)accessibilityPerformDecrementAction 2085{ 2086 if (!m_object) 2087 return; 2088 2089 m_object->updateBackingStore(); 2090 if (!m_object) 2091 return; 2092 2093 if (m_object->isAttachment()) 2094 [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction]; 2095 else 2096 m_object->decrement(); 2097} 2098 2099- (void)accessibilityPerformShowMenuAction 2100{ 2101 if (m_object->roleValue() == ComboBoxRole) 2102 m_object->setIsExpanded(true); 2103 else { 2104 // This needs to be performed in an iteration of the run loop that did not start from an AX call. 2105 // If it's the same run loop iteration, the menu open notification won't be sent 2106 [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0]; 2107 } 2108} 2109 2110- (void)accessibilityShowContextMenu 2111{ 2112 FrameView* frameView = m_object->documentFrameView(); 2113 if (!frameView) 2114 return; 2115 2116 // simulate a click in the middle of the object 2117 IntPoint clickPoint = m_object->clickPoint(); 2118 NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y()); 2119 2120 NSView* view = nil; 2121 if (m_object->isAttachment()) 2122 view = [self attachmentView]; 2123 else 2124 view = frameView->documentView(); 2125 2126 if (!view) 2127 return; 2128 2129 NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil]; 2130 2131 // Show the contextual menu for this event. 2132 NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1]; 2133 NSMenu* menu = [view menuForEvent:event]; 2134 2135 if (menu) 2136 [NSMenu popUpContextMenu:menu withEvent:event forView:view]; 2137} 2138 2139- (void)accessibilityPerformAction:(NSString*)action 2140{ 2141 if (!m_object) 2142 return; 2143 2144 m_object->updateBackingStore(); 2145 if (!m_object) 2146 return; 2147 2148 if ([action isEqualToString:NSAccessibilityPressAction]) 2149 [self accessibilityPerformPressAction]; 2150 2151 else if ([action isEqualToString:NSAccessibilityShowMenuAction]) 2152 [self accessibilityPerformShowMenuAction]; 2153 2154 else if ([action isEqualToString:NSAccessibilityIncrementAction]) 2155 [self accessibilityPerformIncrementAction]; 2156 2157 else if ([action isEqualToString:NSAccessibilityDecrementAction]) 2158 [self accessibilityPerformDecrementAction]; 2159} 2160 2161- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName 2162{ 2163 if (!m_object) 2164 return; 2165 2166 m_object->updateBackingStore(); 2167 if (!m_object) 2168 return; 2169 2170 WebCoreTextMarkerRange* textMarkerRange = nil; 2171 NSNumber* number = nil; 2172 NSString* string = nil; 2173 NSRange range = {0, 0}; 2174 NSArray* array = nil; 2175 2176 // decode the parameter 2177 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value]) 2178 textMarkerRange = (WebCoreTextMarkerRange*) value; 2179 2180 else if ([value isKindOfClass:[NSNumber self]]) 2181 number = value; 2182 2183 else if ([value isKindOfClass:[NSString self]]) 2184 string = value; 2185 2186 else if ([value isKindOfClass:[NSValue self]]) 2187 range = [value rangeValue]; 2188 2189 else if ([value isKindOfClass:[NSArray self]]) 2190 array = value; 2191 2192 // handle the command 2193 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) { 2194 ASSERT(textMarkerRange); 2195 m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]); 2196 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) { 2197 ASSERT(number); 2198 m_object->setFocused([number intValue] != 0); 2199 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { 2200 if (!string) 2201 return; 2202 m_object->setValue(string); 2203 } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) { 2204 if (!number) 2205 return; 2206 m_object->setSelected([number boolValue]); 2207 } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { 2208 if (!array || m_object->roleValue() != ListBoxRole) 2209 return; 2210 AccessibilityObject::AccessibilityChildrenVector selectedChildren; 2211 convertToVector(array, selectedChildren); 2212 static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren); 2213 } else if (m_object->isTextControl()) { 2214 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { 2215 m_object->setSelectedText(string); 2216 } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { 2217 m_object->setSelectedTextRange(PlainTextRange(range.location, range.length)); 2218 } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) { 2219 m_object->makeRangeVisible(PlainTextRange(range.location, range.length)); 2220 } 2221 } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 2222 m_object->setIsExpanded([number boolValue]); 2223 else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 2224 AccessibilityObject::AccessibilityChildrenVector selectedRows; 2225 convertToVector(array, selectedRows); 2226 if (m_object->isTree() || m_object->isDataTable()) 2227 m_object->setSelectedRows(selectedRows); 2228 } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 2229 m_object->setARIAGrabbed([number boolValue]); 2230} 2231 2232static RenderObject* rendererForView(NSView* view) 2233{ 2234 if (![view conformsToProtocol:@protocol(WebCoreFrameView)]) 2235 return 0; 2236 2237 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view; 2238 Frame* frame = [frameView _web_frame]; 2239 if (!frame) 2240 return 0; 2241 2242 Node* node = frame->document()->ownerElement(); 2243 if (!node) 2244 return 0; 2245 2246 return node->renderer(); 2247} 2248 2249- (id)_accessibilityParentForSubview:(NSView*)subview 2250{ 2251 RenderObject* renderer = rendererForView(subview); 2252 if (!renderer) 2253 return nil; 2254 2255 AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer); 2256 if (obj) 2257 return obj->parentObjectUnignored()->wrapper(); 2258 return nil; 2259} 2260 2261- (NSString*)accessibilityActionDescription:(NSString*)action 2262{ 2263 // we have no custom actions 2264 return NSAccessibilityActionDescription(action); 2265} 2266 2267// The CFAttributedStringType representation of the text associated with this accessibility 2268// object that is specified by the given range. 2269- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range 2270{ 2271 PlainTextRange textRange = PlainTextRange(range.location, range.length); 2272 VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange); 2273 return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)]; 2274} 2275 2276// The RTF representation of the text associated with this accessibility object that is 2277// specified by the given range. 2278- (NSData*)doAXRTFForRange:(NSRange)range 2279{ 2280 NSAttributedString* attrString = [self doAXAttributedStringForRange:range]; 2281 return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil]; 2282} 2283 2284- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter 2285{ 2286 WebCoreTextMarker* textMarker = nil; 2287 WebCoreTextMarkerRange* textMarkerRange = nil; 2288 NSNumber* number = nil; 2289 NSArray* array = nil; 2290 RefPtr<AccessibilityObject> uiElement = 0; 2291 NSPoint point = NSZeroPoint; 2292 bool pointSet = false; 2293 NSRange range = {0, 0}; 2294 bool rangeSet = false; 2295 2296 // basic parameter validation 2297 if (!m_object || !attribute || !parameter) 2298 return nil; 2299 2300 m_object->updateBackingStore(); 2301 if (!m_object) 2302 return nil; 2303 2304 // common parameter type check/casting. Nil checks in handlers catch wrong type case. 2305 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from 2306 // a parameter of the wrong type. 2307 if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter]) 2308 textMarker = (WebCoreTextMarker*) parameter; 2309 2310 else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter]) 2311 textMarkerRange = (WebCoreTextMarkerRange*) parameter; 2312 2313 else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]]) 2314 uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject]; 2315 2316 else if ([parameter isKindOfClass:[NSNumber self]]) 2317 number = parameter; 2318 2319 else if ([parameter isKindOfClass:[NSArray self]]) 2320 array = parameter; 2321 2322 else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) { 2323 pointSet = true; 2324 point = [(NSValue*)parameter pointValue]; 2325 2326 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) { 2327 rangeSet = true; 2328 range = [(NSValue*)parameter rangeValue]; 2329 2330 } else { 2331 // got a parameter of a type we never use 2332 // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally 2333 // while using accesstool (e.g.), forcing you to start over 2334 return nil; 2335 } 2336 2337 // Convert values to WebCore types 2338 // FIXME: prepping all of these values as WebCore types is unnecessary in many 2339 // cases. Re-organization of this function or performing the conversion on a 2340 // need basis are possible improvements. 2341 VisiblePosition visiblePos; 2342 if (textMarker) 2343 visiblePos = visiblePositionForTextMarker(textMarker); 2344 int intNumber = [number intValue]; 2345 VisiblePositionRange visiblePosRange; 2346 if (textMarkerRange) 2347 visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 2348 IntPoint webCorePoint = IntPoint(point); 2349 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length); 2350 2351 // dispatch 2352 if ([attribute isEqualToString: @"AXUIElementForTextMarker"]) 2353 return m_object->accessibilityObjectForPosition(visiblePos)->wrapper(); 2354 2355 if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) { 2356 VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange(); 2357 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2358 } 2359 2360 if ([attribute isEqualToString: @"AXLineForTextMarker"]) 2361 return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)]; 2362 2363 if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) { 2364 VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber); 2365 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2366 } 2367 2368 if ([attribute isEqualToString: @"AXStringForTextMarkerRange"]) 2369 return m_object->stringForVisiblePositionRange(visiblePosRange); 2370 2371 if ([attribute isEqualToString: @"AXTextMarkerForPosition"]) 2372 return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil; 2373 2374 if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) { 2375 NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange); 2376 return [NSValue valueWithRect:rect]; 2377 } 2378 2379 if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) { 2380 VisiblePosition start = m_object->visiblePositionForIndex(range.location); 2381 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length); 2382 if (start.isNull() || end.isNull()) 2383 return nil; 2384 NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end)); 2385 return [NSValue valueWithRect:rect]; 2386 } 2387 2388 if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) { 2389 VisiblePosition start = m_object->visiblePositionForIndex(range.location); 2390 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length); 2391 if (start.isNull() || end.isNull()) 2392 return nil; 2393 return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end)); 2394 } 2395 2396 if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"]) 2397 return [self doAXAttributedStringForTextMarkerRange:textMarkerRange]; 2398 2399 if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) { 2400 if ([array count] < 2) 2401 return nil; 2402 2403 WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0]; 2404 WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1]; 2405 if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1] 2406 || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2]) 2407 return nil; 2408 2409 VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1); 2410 VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2); 2411 VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2); 2412 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2413 } 2414 2415 if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"]) 2416 return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos)); 2417 2418 if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"]) 2419 return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos)); 2420 2421 if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) { 2422 VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos); 2423 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2424 } 2425 2426 if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) { 2427 VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos); 2428 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2429 } 2430 2431 if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) { 2432 VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos); 2433 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2434 } 2435 2436 if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) { 2437 VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos); 2438 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2439 } 2440 2441 if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) { 2442 VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos); 2443 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2444 } 2445 2446 if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) { 2447 VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos); 2448 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2449 } 2450 2451 if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"]) 2452 return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos)); 2453 2454 if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"]) 2455 return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos)); 2456 2457 if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"]) 2458 return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos)); 2459 2460 if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"]) 2461 return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos)); 2462 2463 if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"]) 2464 return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos)); 2465 2466 if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"]) 2467 return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos)); 2468 2469 if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"]) 2470 return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos)); 2471 2472 if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"]) 2473 return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos)); 2474 2475 if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) { 2476 VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos); 2477 return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); 2478 } 2479 2480 if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) { 2481 int length = m_object->lengthForVisiblePositionRange(visiblePosRange); 2482 if (length < 0) 2483 return nil; 2484 return [NSNumber numberWithInt:length]; 2485 } 2486 2487 if (m_object->isDataTable()) { 2488 if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) { 2489 if (array == nil || [array count] != 2) 2490 return nil; 2491 AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]); 2492 if (!cell) 2493 return nil; 2494 2495 return cell->wrapper(); 2496 } 2497 } 2498 2499 if (m_object->isTextControl()) { 2500 if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) { 2501 int lineNumber = m_object->doAXLineForIndex(intNumber); 2502 if (lineNumber < 0) 2503 return nil; 2504 return [NSNumber numberWithUnsignedInt:lineNumber]; 2505 } 2506 2507 if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) { 2508 PlainTextRange textRange = m_object->doAXRangeForLine(intNumber); 2509 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 2510 } 2511 2512 if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) 2513 return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil; 2514 2515 if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) { 2516 if (!pointSet) 2517 return nil; 2518 PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint); 2519 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 2520 } 2521 2522 if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) { 2523 PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber); 2524 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 2525 } 2526 2527 if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) { 2528 if (!rangeSet) 2529 return nil; 2530 NSRect rect = m_object->doAXBoundsForRange(plainTextRange); 2531 return [NSValue valueWithRect:rect]; 2532 } 2533 2534 if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute]) 2535 return rangeSet ? [self doAXRTFForRange:range] : nil; 2536 2537 if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute]) 2538 return rangeSet ? [self doAXAttributedStringForRange:range] : nil; 2539 2540 if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) { 2541 PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber); 2542 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 2543 } 2544 } 2545 2546 return nil; 2547} 2548 2549- (BOOL)accessibilityShouldUseUniqueId 2550{ 2551 return m_object->accessibilityShouldUseUniqueId(); 2552} 2553 2554// API that AppKit uses for faster access 2555- (NSUInteger)accessibilityIndexOfChild:(id)child 2556{ 2557 if (!m_object) 2558 return NSNotFound; 2559 2560 m_object->updateBackingStore(); 2561 if (!m_object) 2562 return NSNotFound; 2563 2564 // Tree objects return their rows as their children. We can use the original method 2565 // here, because we won't gain any speed up. 2566 if (m_object->isTree()) 2567 return [super accessibilityIndexOfChild:child]; 2568 2569 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 2570 2571 if (children.isEmpty()) 2572 return [[self renderWidgetChildren] indexOfObject:child]; 2573 2574 unsigned count = children.size(); 2575 for (unsigned k = 0; k < count; ++k) { 2576 AccessibilityObjectWrapper* wrapper = children[k]->wrapper(); 2577 if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child)) 2578 return k; 2579 } 2580 2581 return NSNotFound; 2582} 2583 2584- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute 2585{ 2586 if (!m_object) 2587 return 0; 2588 2589 m_object->updateBackingStore(); 2590 if (!m_object) 2591 return 0; 2592 2593 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 2594 // Tree items object returns a different set of children than those that are in children() 2595 // because an AXOutline (the mac role is becomes) has some odd stipulations. 2596 if (m_object->isTree() || m_object->isTreeItem()) 2597 return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count]; 2598 2599 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 2600 if (children.isEmpty()) 2601 return [[self renderWidgetChildren] count]; 2602 2603 return children.size(); 2604 } 2605 2606 return [super accessibilityArrayAttributeCount:attribute]; 2607} 2608 2609- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount 2610{ 2611 if (!m_object) 2612 return nil; 2613 2614 m_object->updateBackingStore(); 2615 if (!m_object) 2616 return nil; 2617 2618 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 2619 if (m_object->children().isEmpty()) { 2620 NSArray *children = [self renderWidgetChildren]; 2621 if (!children) 2622 return nil; 2623 2624 NSUInteger childCount = [children count]; 2625 if (index >= childCount) 2626 return nil; 2627 2628 NSUInteger arrayLength = min(childCount - index, maxCount); 2629 return [children subarrayWithRange:NSMakeRange(index, arrayLength)]; 2630 } else if (m_object->isTree()) { 2631 // Tree objects return their rows as their children. We can use the original method in this case. 2632 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; 2633 } 2634 2635 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 2636 unsigned childCount = children.size(); 2637 if (index >= childCount) 2638 return nil; 2639 2640 unsigned available = min(childCount - index, maxCount); 2641 2642 NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available]; 2643 for (unsigned added = 0; added < available; ++index, ++added) { 2644 AccessibilityObjectWrapper* wrapper = children[index]->wrapper(); 2645 if (wrapper) { 2646 // The attachment view should be returned, otherwise AX palindrome errors occur. 2647 if (children[index]->isAttachment() && [wrapper attachmentView]) 2648 [subarray addObject:[wrapper attachmentView]]; 2649 else 2650 [subarray addObject:wrapper]; 2651 } 2652 } 2653 2654 return subarray; 2655 } 2656 2657 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; 2658} 2659 2660// These are used by DRT so that it can know when notifications are sent. 2661// Since they are static, only one callback can be installed at a time (that's all DRT should need). 2662typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context); 2663static AXPostedNotificationCallback AXNotificationCallback = 0; 2664static void* AXPostedNotificationContext = 0; 2665 2666- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context 2667{ 2668 AXNotificationCallback = function; 2669 AXPostedNotificationContext = context; 2670} 2671 2672- (void)accessibilityPostedNotification:(NSString *)notification 2673{ 2674 if (AXNotificationCallback) 2675 AXNotificationCallback(self, notification, AXPostedNotificationContext); 2676} 2677 2678@end 2679 2680#endif // HAVE(ACCESSIBILITY) 2681