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