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