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