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 "WebAccessibilityObjectWrapperMac.h" 31 32#if HAVE(ACCESSIBILITY) 33 34#import "AXObjectCache.h" 35#import "AccessibilityARIAGridRow.h" 36#import "AccessibilityList.h" 37#import "AccessibilityListBox.h" 38#import "AccessibilityRenderObject.h" 39#import "AccessibilityScrollView.h" 40#import "AccessibilitySpinButton.h" 41#import "AccessibilityTable.h" 42#import "AccessibilityTableCell.h" 43#import "AccessibilityTableColumn.h" 44#import "AccessibilityTableRow.h" 45#import "Chrome.h" 46#import "ChromeClient.h" 47#import "ColorMac.h" 48#import "ContextMenuController.h" 49#import "Editor.h" 50#import "Font.h" 51#import "Frame.h" 52#import "FrameLoaderClient.h" 53#import "FrameSelection.h" 54#import "HTMLAnchorElement.h" 55#import "HTMLAreaElement.h" 56#import "HTMLFrameOwnerElement.h" 57#import "HTMLImageElement.h" 58#import "HTMLInputElement.h" 59#import "HTMLNames.h" 60#import "HTMLTextAreaElement.h" 61#import "LocalizedStrings.h" 62#import "Page.h" 63#import "RenderTextControl.h" 64#import "RenderView.h" 65#import "RenderWidget.h" 66#import "ScrollView.h" 67#import "SimpleFontData.h" 68#import "TextCheckerClient.h" 69#import "TextCheckingHelper.h" 70#import "TextIterator.h" 71#import "VisibleUnits.h" 72#import "WebCoreFrameView.h" 73#import "WebCoreObjCExtras.h" 74#import "WebCoreSystemInterface.h" 75#import "htmlediting.h" 76#import <wtf/ObjcRuntimeExtras.h> 77 78using namespace WebCore; 79using namespace HTMLNames; 80using namespace std; 81 82// Cell Tables 83#ifndef NSAccessibilitySelectedCellsAttribute 84#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells" 85#endif 86 87#ifndef NSAccessibilityVisibleCellsAttribute 88#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells" 89#endif 90 91#ifndef NSAccessibilityRowHeaderUIElementsAttribute 92#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements" 93#endif 94 95#ifndef NSAccessibilityRowIndexRangeAttribute 96#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange" 97#endif 98 99#ifndef NSAccessibilityColumnIndexRangeAttribute 100#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange" 101#endif 102 103#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute 104#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow" 105#endif 106 107#ifndef NSAccessibilityCellRole 108#define NSAccessibilityCellRole @"AXCell" 109#endif 110 111// Lists 112#ifndef NSAccessibilityContentListSubrole 113#define NSAccessibilityContentListSubrole @"AXContentList" 114#endif 115 116#ifndef NSAccessibilityDefinitionListSubrole 117#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList" 118#endif 119 120#ifndef NSAccessibilityDescriptionListSubrole 121#define NSAccessibilityDescriptionListSubrole @"AXDescriptionList" 122#endif 123 124// Miscellaneous 125#ifndef NSAccessibilityBlockQuoteLevelAttribute 126#define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel" 127#endif 128 129#ifndef NSAccessibilityAccessKeyAttribute 130#define NSAccessibilityAccessKeyAttribute @"AXAccessKey" 131#endif 132 133#ifndef NSAccessibilityLanguageAttribute 134#define NSAccessibilityLanguageAttribute @"AXLanguage" 135#endif 136 137#ifndef NSAccessibilityRequiredAttribute 138#define NSAccessibilityRequiredAttribute @"AXRequired" 139#endif 140 141#ifndef NSAccessibilityInvalidAttribute 142#define NSAccessibilityInvalidAttribute @"AXInvalid" 143#endif 144 145#ifndef NSAccessibilityOwnsAttribute 146#define NSAccessibilityOwnsAttribute @"AXOwns" 147#endif 148 149#ifndef NSAccessibilityGrabbedAttribute 150#define NSAccessibilityGrabbedAttribute @"AXGrabbed" 151#endif 152 153#ifndef NSAccessibilityDropEffectsAttribute 154#define NSAccessibilityDropEffectsAttribute @"AXDropEffects" 155#endif 156 157#ifndef NSAccessibilityARIALiveAttribute 158#define NSAccessibilityARIALiveAttribute @"AXARIALive" 159#endif 160 161#ifndef NSAccessibilityARIAAtomicAttribute 162#define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic" 163#endif 164 165#ifndef NSAccessibilityARIARelevantAttribute 166#define NSAccessibilityARIARelevantAttribute @"AXARIARelevant" 167#endif 168 169#ifndef NSAccessibilityARIABusyAttribute 170#define NSAccessibilityARIABusyAttribute @"AXARIABusy" 171#endif 172 173#ifndef NSAccessibilityARIAPosInSetAttribute 174#define NSAccessibilityARIAPosInSetAttribute @"AXARIAPosInSet" 175#endif 176 177#ifndef NSAccessibilityARIASetSizeAttribute 178#define NSAccessibilityARIASetSizeAttribute @"AXARIASetSize" 179#endif 180 181#ifndef NSAccessibilityLoadingProgressAttribute 182#define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress" 183#endif 184 185#ifndef NSAccessibilityHasPopupAttribute 186#define NSAccessibilityHasPopupAttribute @"AXHasPopup" 187#endif 188 189#ifndef NSAccessibilityPlaceholderValueAttribute 190#define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue" 191#endif 192 193// Search 194#ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute 195#define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate" 196#endif 197 198// Text 199#ifndef NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute 200#define NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute @"AXEndTextMarkerForBounds" 201#endif 202 203#ifndef NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute 204#define NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute @"AXStartTextMarkerForBounds" 205#endif 206 207// Search Keys 208#ifndef NSAccessibilityAnyTypeSearchKey 209#define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey" 210#endif 211 212#ifndef NSAccessibilityBlockquoteSameLevelSearchKey 213#define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey" 214#endif 215 216#ifndef NSAccessibilityBlockquoteSearchKey 217#define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey" 218#endif 219 220#ifndef NSAccessibilityBoldFontSearchKey 221#define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey" 222#endif 223 224#ifndef NSAccessibilityButtonSearchKey 225#define NSAccessibilityButtonSearchKey @"AXButtonSearchKey" 226#endif 227 228#ifndef NSAccessibilityCheckBoxSearchKey 229#define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey" 230#endif 231 232#ifndef NSAccessibilityControlSearchKey 233#define NSAccessibilityControlSearchKey @"AXControlSearchKey" 234#endif 235 236#ifndef NSAccessibilityDifferentTypeSearchKey 237#define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey" 238#endif 239 240#ifndef NSAccessibilityFontChangeSearchKey 241#define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey" 242#endif 243 244#ifndef NSAccessibilityFontColorChangeSearchKey 245#define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey" 246#endif 247 248#ifndef NSAccessibilityFrameSearchKey 249#define NSAccessibilityFrameSearchKey @"AXFrameSearchKey" 250#endif 251 252#ifndef NSAccessibilityGraphicSearchKey 253#define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey" 254#endif 255 256#ifndef NSAccessibilityHeadingLevel1SearchKey 257#define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey" 258#endif 259 260#ifndef NSAccessibilityHeadingLevel2SearchKey 261#define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey" 262#endif 263 264#ifndef NSAccessibilityHeadingLevel3SearchKey 265#define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey" 266#endif 267 268#ifndef NSAccessibilityHeadingLevel4SearchKey 269#define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey" 270#endif 271 272#ifndef NSAccessibilityHeadingLevel5SearchKey 273#define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey" 274#endif 275 276#ifndef NSAccessibilityHeadingLevel6SearchKey 277#define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey" 278#endif 279 280#ifndef NSAccessibilityHeadingSameLevelSearchKey 281#define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey" 282#endif 283 284#ifndef NSAccessibilityHeadingSearchKey 285#define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey" 286#endif 287 288#ifndef NSAccessibilityHighlightedSearchKey 289#define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey" 290#endif 291 292#ifndef NSAccessibilityItalicFontSearchKey 293#define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey" 294#endif 295 296#ifndef NSAccessibilityLandmarkSearchKey 297#define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey" 298#endif 299 300#ifndef NSAccessibilityLinkSearchKey 301#define NSAccessibilityLinkSearchKey @"AXLinkSearchKey" 302#endif 303 304#ifndef NSAccessibilityListSearchKey 305#define NSAccessibilityListSearchKey @"AXListSearchKey" 306#endif 307 308#ifndef NSAccessibilityLiveRegionSearchKey 309#define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey" 310#endif 311 312#ifndef NSAccessibilityMisspelledWordSearchKey 313#define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey" 314#endif 315 316#ifndef NSAccessibilityPlainTextSearchKey 317#define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey" 318#endif 319 320#ifndef NSAccessibilityRadioGroupSearchKey 321#define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey" 322#endif 323 324#ifndef NSAccessibilitySameTypeSearchKey 325#define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey" 326#endif 327 328#ifndef NSAccessibilityStaticTextSearchKey 329#define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey" 330#endif 331 332#ifndef NSAccessibilityStyleChangeSearchKey 333#define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey" 334#endif 335 336#ifndef NSAccessibilityTableSameLevelSearchKey 337#define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey" 338#endif 339 340#ifndef NSAccessibilityTableSearchKey 341#define NSAccessibilityTableSearchKey @"AXTableSearchKey" 342#endif 343 344#ifndef NSAccessibilityTextFieldSearchKey 345#define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey" 346#endif 347 348#ifndef NSAccessibilityUnderlineSearchKey 349#define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey" 350#endif 351 352#ifndef NSAccessibilityUnvisitedLinkSearchKey 353#define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey" 354#endif 355 356#ifndef NSAccessibilityVisitedLinkSearchKey 357#define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey" 358#endif 359 360#define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid" 361#define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker" 362#define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex" 363 364#ifndef NSAccessibilityScrollToVisibleAction 365#define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible" 366#endif 367 368#ifndef NSAccessibilityPathAttribute 369#define NSAccessibilityPathAttribute @"AXPath" 370#endif 371 372// Math attributes 373#define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand" 374#define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex" 375#define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator" 376#define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator" 377#define NSAccessibilityMathBaseAttribute @"AXMathBase" 378#define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript" 379#define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript" 380#define NSAccessibilityMathUnderAttribute @"AXMathUnder" 381#define NSAccessibilityMathOverAttribute @"AXMathOver" 382#define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen" 383#define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose" 384#define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness" 385#define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts" 386#define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts" 387 388@implementation WebAccessibilityObjectWrapper 389 390- (void)unregisterUniqueIdForUIElement 391{ 392 wkUnregisterUniqueIdForElement(self); 393} 394 395- (void)detach 396{ 397 // Send unregisterUniqueIdForUIElement unconditionally because if it is 398 // ever accidentally not done (via other bugs in our AX implementation) you 399 // end up with a crash like <rdar://problem/4273149>. It is safe and not 400 // expensive to send even if the object is not registered. 401 [self unregisterUniqueIdForUIElement]; 402 [super detach]; 403} 404 405- (id)attachmentView 406{ 407 ASSERT(m_object->isAttachment()); 408 Widget* widget = m_object->widgetForAttachmentView(); 409 if (!widget) 410 return nil; 411 return NSAccessibilityUnignoredDescendant(widget->platformWidget()); 412} 413 414#pragma mark SystemInterface wrappers 415 416static inline BOOL AXObjectIsTextMarker(id obj) 417{ 418 return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerTypeID(); 419} 420 421static inline BOOL AXObjectIsTextMarkerRange(id obj) 422{ 423 return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerRangeTypeID(); 424} 425 426static id AXTextMarkerRange(id startMarker, id endMarker) 427{ 428 ASSERT(startMarker != nil); 429 ASSERT(endMarker != nil); 430 ASSERT(CFGetTypeID(startMarker) == wkGetAXTextMarkerTypeID()); 431 ASSERT(CFGetTypeID(endMarker) == wkGetAXTextMarkerTypeID()); 432 return HardAutorelease(wkCreateAXTextMarkerRange((CFTypeRef)startMarker, (CFTypeRef)endMarker)); 433} 434 435static id AXTextMarkerRangeStart(id range) 436{ 437 ASSERT(range != nil); 438 ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID()); 439 return HardAutorelease(wkCopyAXTextMarkerRangeStart(range)); 440} 441 442static id AXTextMarkerRangeEnd(id range) 443{ 444 ASSERT(range != nil); 445 ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID()); 446 return HardAutorelease(wkCopyAXTextMarkerRangeEnd(range)); 447} 448 449#pragma mark Other helpers 450 451- (IntRect)screenToContents:(const IntRect&)rect 452{ 453 Document* document = m_object->document(); 454 if (!document) 455 return IntRect(); 456 457 FrameView* frameView = document->view(); 458 if (!frameView) 459 return IntRect(); 460 461 IntPoint startPoint = frameView->screenToContents(rect.minXMaxYCorner()); 462 IntPoint endPoint = frameView->screenToContents(rect.maxXMinYCorner()); 463 return IntRect(startPoint.x(), startPoint.y(), endPoint.x() - startPoint.x(), endPoint.y() - startPoint.y()); 464} 465 466#pragma mark Search helpers 467 468typedef HashMap<String, AccessibilitySearchKey> AccessibilitySearchKeyMap; 469 470struct SearchKeyEntry { 471 String key; 472 AccessibilitySearchKey value; 473}; 474 475static AccessibilitySearchKeyMap* createAccessibilitySearchKeyMap() 476{ 477 const SearchKeyEntry searchKeys[] = { 478 { NSAccessibilityAnyTypeSearchKey, AnyTypeSearchKey }, 479 { NSAccessibilityBlockquoteSameLevelSearchKey, BlockquoteSameLevelSearchKey }, 480 { NSAccessibilityBlockquoteSearchKey, BlockquoteSearchKey }, 481 { NSAccessibilityBoldFontSearchKey, BoldFontSearchKey }, 482 { NSAccessibilityButtonSearchKey, ButtonSearchKey }, 483 { NSAccessibilityCheckBoxSearchKey, CheckBoxSearchKey }, 484 { NSAccessibilityControlSearchKey, ControlSearchKey }, 485 { NSAccessibilityDifferentTypeSearchKey, DifferentTypeSearchKey }, 486 { NSAccessibilityFontChangeSearchKey, FontChangeSearchKey }, 487 { NSAccessibilityFontColorChangeSearchKey, FontColorChangeSearchKey }, 488 { NSAccessibilityFrameSearchKey, FrameSearchKey }, 489 { NSAccessibilityGraphicSearchKey, GraphicSearchKey }, 490 { NSAccessibilityHeadingLevel1SearchKey, HeadingLevel1SearchKey }, 491 { NSAccessibilityHeadingLevel2SearchKey, HeadingLevel2SearchKey }, 492 { NSAccessibilityHeadingLevel3SearchKey, HeadingLevel3SearchKey }, 493 { NSAccessibilityHeadingLevel4SearchKey, HeadingLevel4SearchKey }, 494 { NSAccessibilityHeadingLevel5SearchKey, HeadingLevel5SearchKey }, 495 { NSAccessibilityHeadingLevel6SearchKey, HeadingLevel6SearchKey }, 496 { NSAccessibilityHeadingSameLevelSearchKey, HeadingSameLevelSearchKey }, 497 { NSAccessibilityHeadingSearchKey, HeadingSearchKey }, 498 { NSAccessibilityHighlightedSearchKey, HighlightedSearchKey }, 499 { NSAccessibilityItalicFontSearchKey, ItalicFontSearchKey }, 500 { NSAccessibilityLandmarkSearchKey, LandmarkSearchKey }, 501 { NSAccessibilityLinkSearchKey, LinkSearchKey }, 502 { NSAccessibilityListSearchKey, ListSearchKey }, 503 { NSAccessibilityLiveRegionSearchKey, LiveRegionSearchKey }, 504 { NSAccessibilityMisspelledWordSearchKey, MisspelledWordSearchKey }, 505 { NSAccessibilityPlainTextSearchKey, PlainTextSearchKey }, 506 { NSAccessibilityRadioGroupSearchKey, RadioGroupSearchKey }, 507 { NSAccessibilitySameTypeSearchKey, SameTypeSearchKey }, 508 { NSAccessibilityStaticTextSearchKey, StaticTextSearchKey }, 509 { NSAccessibilityStyleChangeSearchKey, StyleChangeSearchKey }, 510 { NSAccessibilityTableSameLevelSearchKey, TableSameLevelSearchKey }, 511 { NSAccessibilityTableSearchKey, TableSearchKey }, 512 { NSAccessibilityTextFieldSearchKey, TextFieldSearchKey }, 513 { NSAccessibilityUnderlineSearchKey, UnderlineSearchKey }, 514 { NSAccessibilityUnvisitedLinkSearchKey, UnvisitedLinkSearchKey }, 515 { NSAccessibilityVisitedLinkSearchKey, VisitedLinkSearchKey } 516 }; 517 518 AccessibilitySearchKeyMap* searchKeyMap = new AccessibilitySearchKeyMap; 519 for (size_t i = 0; i < WTF_ARRAY_LENGTH(searchKeys); i++) 520 searchKeyMap->set(searchKeys[i].key, searchKeys[i].value); 521 522 return searchKeyMap; 523} 524 525static AccessibilitySearchKey accessibilitySearchKeyForString(const String& value) 526{ 527 if (value.isEmpty()) 528 return AnyTypeSearchKey; 529 530 static const AccessibilitySearchKeyMap* searchKeyMap = createAccessibilitySearchKeyMap(); 531 532 AccessibilitySearchKey searchKey = searchKeyMap->get(value); 533 534 return searchKey ? searchKey : AnyTypeSearchKey; 535} 536 537#pragma mark Text Marker helpers 538 539static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos) 540{ 541 ASSERT(cache); 542 543 TextMarkerData textMarkerData; 544 cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos); 545 if (!textMarkerData.axID) 546 return nil; 547 548 return HardAutorelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData))); 549} 550 551- (id)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos 552{ 553 return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos); 554} 555 556static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, CFTypeRef textMarker) 557{ 558 ASSERT(cache); 559 560 if (!textMarker) 561 return VisiblePosition(); 562 TextMarkerData textMarkerData; 563 if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData))) 564 return VisiblePosition(); 565 566 return cache->visiblePositionForTextMarkerData(textMarkerData); 567} 568 569- (VisiblePosition)visiblePositionForTextMarker:(id)textMarker 570{ 571 return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker); 572} 573 574static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange) 575{ 576 return visiblePositionForTextMarker(cache, AXTextMarkerRangeStart(textMarkerRange)); 577} 578 579static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange) 580{ 581 return visiblePositionForTextMarker(cache, AXTextMarkerRangeEnd(textMarkerRange)); 582} 583 584static id textMarkerRangeFromMarkers(id textMarker1, id textMarker2) 585{ 586 if (!textMarker1 || !textMarker2) 587 return nil; 588 589 return AXTextMarkerRange(textMarker1, textMarker2); 590} 591 592// When modifying attributed strings, the range can come from a source which may provide faulty information (e.g. the spell checker). 593// To protect against such cases the range should be validated before adding or removing attributes. 594static BOOL AXAttributedStringRangeIsValid(NSAttributedString* attrString, NSRange range) 595{ 596 return (range.location < [attrString length] && NSMaxRange(range) <= [attrString length]); 597} 598 599static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range) 600{ 601 if (!AXAttributedStringRangeIsValid(attrString, range)) 602 return; 603 604 if (font) { 605 NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: 606 [font fontName] , NSAccessibilityFontNameKey, 607 [font familyName] , NSAccessibilityFontFamilyKey, 608 [font displayName] , NSAccessibilityVisibleNameKey, 609 [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey, 610 nil]; 611 612 [attrString addAttribute:attribute value:dict range:range]; 613 } else 614 [attrString removeAttribute:attribute range:range]; 615 616} 617 618static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor) 619{ 620 // get color information assuming NSDeviceRGBColorSpace 621 NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 622 if (rgbColor == nil) 623 rgbColor = [NSColor blackColor]; 624 CGFloat components[4]; 625 [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; 626 627 // create a new CGColorRef to return 628 CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB(); 629 CGColorRef cgColor = CGColorCreate(cgColorSpace, components); 630 CGColorSpaceRelease(cgColorSpace); 631 632 // check for match with existing color 633 if (existingColor && CGColorEqualToColor(cgColor, existingColor)) { 634 CGColorRelease(cgColor); 635 cgColor = 0; 636 } 637 638 return cgColor; 639} 640 641static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range) 642{ 643 if (!AXAttributedStringRangeIsValid(attrString, range)) 644 return; 645 646 if (color) { 647 CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil]; 648 CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor); 649 if (cgColor) { 650 [attrString addAttribute:attribute value:(id)cgColor range:range]; 651 CGColorRelease(cgColor); 652 } 653 } else 654 [attrString removeAttribute:attribute range:range]; 655} 656 657static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range) 658{ 659 if (!AXAttributedStringRangeIsValid(attrString, range)) 660 return; 661 662 if (number) 663 [attrString addAttribute:attribute value:number range:range]; 664 else 665 [attrString removeAttribute:attribute range:range]; 666} 667 668static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 669{ 670 RenderStyle* style = renderer->style(); 671 672 // set basic font info 673 AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range); 674 675 // set basic colors 676 AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyColor)), range); 677 AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)), range); 678 679 // set super/sub scripting 680 EVerticalAlign alignment = style->verticalAlign(); 681 if (alignment == SUB) 682 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range); 683 else if (alignment == SUPER) 684 AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range); 685 else 686 [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range]; 687 688 // set shadow 689 if (style->textShadow()) 690 AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range); 691 else 692 [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range]; 693 694 // set underline and strikethrough 695 int decor = style->textDecorationsInEffect(); 696 if ((decor & TextDecorationUnderline) == 0) { 697 [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range]; 698 [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range]; 699 } 700 701 if ((decor & TextDecorationLineThrough) == 0) { 702 [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range]; 703 [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range]; 704 } 705 706 if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) { 707 // find colors using quirk mode approach (strict mode would use current 708 // color for all but the root line box, which would use getTextDecorationColors) 709 Color underline, overline, linethrough; 710 renderer->getTextDecorationColors(decor, underline, overline, linethrough); 711 712 if ((decor & TextDecorationUnderline) != 0) { 713 AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range); 714 AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range); 715 } 716 717 if ((decor & TextDecorationLineThrough) != 0) { 718 AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range); 719 AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range); 720 } 721 } 722 723 // Indicate background highlighting. 724 for (Node* node = renderer->node(); node; node = node->parentNode()) { 725 if (node->hasTagName(markTag)) 726 AXAttributeStringSetNumber(attrString, @"AXHighlight", [NSNumber numberWithBool:YES], range); 727 } 728} 729 730static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 731{ 732 if (!AXAttributedStringRangeIsValid(attrString, range)) 733 return; 734 735 AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer); 736 int quoteLevel = obj->blockquoteLevel(); 737 738 if (quoteLevel) 739 [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range]; 740 else 741 [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range]; 742} 743 744static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int charLength, NSRange range) 745{ 746 if (unifiedTextCheckerEnabled(node->document()->frame())) { 747 // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word. 748 TextCheckerClient* checker = node->document()->frame()->editor().textChecker(); 749 750 // checkTextOfParagraph is the only spelling/grammar checker implemented in WK1 and WK2 751 Vector<TextCheckingResult> results; 752 checkTextOfParagraph(checker, chars, charLength, TextCheckingTypeSpelling, results); 753 754 size_t size = results.size(); 755 NSNumber* trueValue = [NSNumber numberWithBool:YES]; 756 for (unsigned i = 0; i < size; i++) { 757 const TextCheckingResult& result = results[i]; 758 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length)); 759#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 760 AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length)); 761#endif 762 } 763 return; 764 } 765 766 int currentPosition = 0; 767 while (charLength > 0) { 768 const UChar* charData = chars + currentPosition; 769 TextCheckerClient* checker = node->document()->frame()->editor().textChecker(); 770 771 int misspellingLocation = -1; 772 int misspellingLength = 0; 773 checker->checkSpellingOfString(charData, charLength, &misspellingLocation, &misspellingLength); 774 if (misspellingLocation == -1 || !misspellingLength) 775 break; 776 777 NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength); 778 AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange); 779#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 780 AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange); 781#endif 782 charLength -= (misspellingLocation + misspellingLength); 783 currentPosition += (misspellingLocation + misspellingLength); 784 } 785} 786 787static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) 788{ 789 if (!renderer) 790 return; 791 792 if (!AXAttributedStringRangeIsValid(attrString, range)) 793 return; 794 795 // Sometimes there are objects between the text and the heading. 796 // In those cases the parent hierarchy should be queried to see if there is a heading level. 797 int parentHeadingLevel = 0; 798 AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent()); 799 for (; parentObject; parentObject = parentObject->parentObject()) { 800 parentHeadingLevel = parentObject->headingLevel(); 801 if (parentHeadingLevel) 802 break; 803 } 804 805 if (parentHeadingLevel) 806 [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range]; 807 else 808 [attrString removeAttribute:@"AXHeadingLevel" range:range]; 809} 810 811static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range) 812{ 813 if (!AXAttributedStringRangeIsValid(attrString, range)) 814 return; 815 816 if (object && object->isAccessibilityRenderObject()) { 817 // make a serializable AX object 818 819 RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer(); 820 if (!renderer) 821 return; 822 823 Document* doc = renderer->document(); 824 if (!doc) 825 return; 826 827 AXObjectCache* cache = doc->axObjectCache(); 828 if (!cache) 829 return; 830 831 AXUIElementRef axElement = wkCreateAXUIElementRef(object->wrapper()); 832 if (axElement) { 833 [attrString addAttribute:attribute value:(id)axElement range:range]; 834 CFRelease(axElement); 835 } 836 } else 837 [attrString removeAttribute:attribute range:range]; 838} 839 840static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length) 841{ 842 // skip invisible text 843 if (!node->renderer()) 844 return; 845 846 // easier to calculate the range before appending the string 847 NSRange attrStringRange = NSMakeRange([attrString length], length); 848 849 // append the string from this node 850 [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]]; 851 852 // add new attributes and remove irrelevant inherited ones 853 // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge 854 // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means 855 // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually. 856 857 // remove inherited attachment from prior AXAttributedStringAppendReplaced 858 [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange]; 859#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 860 [attrString removeAttribute:NSAccessibilityMarkedMisspelledTextAttribute range:attrStringRange]; 861#endif 862 [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange]; 863 864 // set new attributes 865 AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange); 866 AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange); 867 AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange); 868 AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange); 869 870 // do spelling last because it tends to break up the range 871 AXAttributeStringSetSpelling(attrString, node, chars, length, attrStringRange); 872} 873 874static NSString* nsStringForReplacedNode(Node* replacedNode) 875{ 876 // we should always be given a rendered node and a replaced node, but be safe 877 // replaced nodes are either attachments (widgets) or images 878 if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode()) { 879 ASSERT_NOT_REACHED(); 880 return nil; 881 } 882 883 // create an AX object, but skip it if it is not supposed to be seen 884 RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); 885 if (obj->accessibilityIsIgnored()) 886 return nil; 887 888 // use the attachmentCharacter to represent the replaced node 889 const UniChar attachmentChar = NSAttachmentCharacter; 890 return [NSString stringWithCharacters:&attachmentChar length:1]; 891} 892 893- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(id)textMarkerRange 894{ 895 if (!m_object) 896 return nil; 897 898 // extract the start and end VisiblePosition 899 VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange); 900 if (startVisiblePosition.isNull()) 901 return nil; 902 903 VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange); 904 if (endVisiblePosition.isNull()) 905 return nil; 906 907 VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition); 908 // iterate over the range to build the AX attributed string 909 NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init]; 910 TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get()); 911 while (!it.atEnd()) { 912 // locate the node and starting offset for this range 913 int exception = 0; 914 Node* node = it.range()->startContainer(exception); 915 ASSERT(node == it.range()->endContainer(exception)); 916 int offset = it.range()->startOffset(exception); 917 918 // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) 919 if (it.length() != 0) { 920 // Add the text of the list marker item if necessary. 921 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition())); 922 if (!listMarkerText.isEmpty()) 923 AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length()); 924 925 AXAttributedStringAppendText(attrString, node, it.characters(), it.length()); 926 } else { 927 Node* replacedNode = node->childNode(offset); 928 NSString *attachmentString = nsStringForReplacedNode(replacedNode); 929 if (attachmentString) { 930 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]); 931 932 // append the placeholder string 933 [[attrString mutableString] appendString:attachmentString]; 934 935 // remove all inherited attributes 936 [attrString setAttributes:nil range:attrStringRange]; 937 938 // add the attachment attribute 939 AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); 940 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange); 941 } 942 } 943 it.advance(); 944 } 945 946 return [attrString autorelease]; 947} 948 949static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosition startPosition, VisiblePosition endPosition) 950{ 951 id startTextMarker = textMarkerForVisiblePosition(cache, startPosition); 952 id endTextMarker = textMarkerForVisiblePosition(cache, endPosition); 953 return textMarkerRangeFromMarkers(startTextMarker, endTextMarker); 954} 955 956- (id)textMarkerRangeFromVisiblePositions:(VisiblePosition)startPosition endPosition:(VisiblePosition)endPosition 957{ 958 return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition); 959} 960 961- (NSArray*)accessibilityActionNames 962{ 963 if (![self updateObjectBackingStore]) 964 return nil; 965 966 // All elements should get ShowMenu and ScrollToVisible. 967 // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list. 968#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090 969 static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, nil]; 970#else 971 static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil]; 972#endif 973 974 // Action elements allow Press. 975 // The order is important to VoiceOver, which expects the 'default' action to be the first action. In this case the default action should be press. 976#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090 977 static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; 978#else 979 static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil]; 980#endif 981 982 // Menu elements allow Press and Cancel. 983 static NSArray *menuElementActions = [[actionElementActions arrayByAddingObject:NSAccessibilityCancelAction] retain]; 984 985 // Slider elements allow Increment/Decrement. 986 static NSArray *sliderActions = [[defaultElementActions arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]] retain]; 987 988 NSArray *actions; 989 if (m_object->actionElement() || m_object->isButton()) 990 actions = actionElementActions; 991 else if (m_object->isMenuRelated()) 992 actions = menuElementActions; 993 else if (m_object->isSlider()) 994 actions = sliderActions; 995 else if (m_object->isAttachment()) 996 actions = [[self attachmentView] accessibilityActionNames]; 997 else 998 actions = defaultElementActions; 999 1000 return actions; 1001} 1002 1003- (NSArray*)additionalAccessibilityAttributeNames 1004{ 1005 if (!m_object) 1006 return nil; 1007 1008 NSMutableArray *additional = [NSMutableArray array]; 1009 if (m_object->supportsARIAOwns()) 1010 [additional addObject:NSAccessibilityOwnsAttribute]; 1011 1012 if (m_object->supportsARIAExpanded()) 1013 [additional addObject:NSAccessibilityExpandedAttribute]; 1014 1015 if (m_object->isScrollbar()) 1016 [additional addObject:NSAccessibilityOrientationAttribute]; 1017 1018 if (m_object->supportsARIADragging()) 1019 [additional addObject:NSAccessibilityGrabbedAttribute]; 1020 1021 if (m_object->supportsARIADropping()) 1022 [additional addObject:NSAccessibilityDropEffectsAttribute]; 1023 1024 if (m_object->isAccessibilityTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows()) 1025 [additional addObject:NSAccessibilitySelectedRowsAttribute]; 1026 1027 if (m_object->supportsARIALiveRegion()) { 1028 [additional addObject:NSAccessibilityARIALiveAttribute]; 1029 [additional addObject:NSAccessibilityARIARelevantAttribute]; 1030 } 1031 1032 if (m_object->supportsARIASetSize()) 1033 [additional addObject:NSAccessibilityARIASetSizeAttribute]; 1034 if (m_object->supportsARIAPosInSet()) 1035 [additional addObject:NSAccessibilityARIAPosInSetAttribute]; 1036 1037 if (m_object->sortDirection() != SortDirectionNone) 1038 [additional addObject:NSAccessibilitySortDirectionAttribute]; 1039 1040 // If an object is a child of a live region, then add these 1041 if (m_object->isInsideARIALiveRegion()) 1042 [additional addObject:NSAccessibilityARIAAtomicAttribute]; 1043 // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538). 1044 [additional addObject:NSAccessibilityARIABusyAttribute]; 1045 1046 // Popup buttons on the Mac expose the value attribute. 1047 if (m_object->isPopUpButton()) { 1048 [additional addObject:NSAccessibilityValueAttribute]; 1049 } 1050 1051 if (m_object->supportsRequiredAttribute()) { 1052 [additional addObject:NSAccessibilityRequiredAttribute]; 1053 } 1054 1055 if (m_object->ariaHasPopup()) 1056 [additional addObject:NSAccessibilityHasPopupAttribute]; 1057 1058 if (m_object->isMathRoot()) { 1059 // The index of a square root is always known, so there's no object associated with it. 1060 if (!m_object->isMathSquareRoot()) 1061 [additional addObject:NSAccessibilityMathRootIndexAttribute]; 1062 [additional addObject:NSAccessibilityMathRootRadicandAttribute]; 1063 } else if (m_object->isMathFraction()) { 1064 [additional addObject:NSAccessibilityMathFractionNumeratorAttribute]; 1065 [additional addObject:NSAccessibilityMathFractionDenominatorAttribute]; 1066 [additional addObject:NSAccessibilityMathLineThicknessAttribute]; 1067 } else if (m_object->isMathSubscriptSuperscript()) { 1068 [additional addObject:NSAccessibilityMathBaseAttribute]; 1069 [additional addObject:NSAccessibilityMathSubscriptAttribute]; 1070 [additional addObject:NSAccessibilityMathSuperscriptAttribute]; 1071 } else if (m_object->isMathUnderOver()) { 1072 [additional addObject:NSAccessibilityMathBaseAttribute]; 1073 [additional addObject:NSAccessibilityMathUnderAttribute]; 1074 [additional addObject:NSAccessibilityMathOverAttribute]; 1075 } else if (m_object->isMathFenced()) { 1076 [additional addObject:NSAccessibilityMathFencedOpenAttribute]; 1077 [additional addObject:NSAccessibilityMathFencedCloseAttribute]; 1078 } else if (m_object->isMathMultiscript()) { 1079 [additional addObject:NSAccessibilityMathBaseAttribute]; 1080 [additional addObject:NSAccessibilityMathPrescriptsAttribute]; 1081 [additional addObject:NSAccessibilityMathPostscriptsAttribute]; 1082 } 1083 1084 if (m_object->supportsPath()) 1085 [additional addObject:NSAccessibilityPathAttribute]; 1086 1087 return additional; 1088} 1089 1090- (NSArray*)accessibilityAttributeNames 1091{ 1092 if (![self updateObjectBackingStore]) 1093 return nil; 1094 1095 if (m_object->isAttachment()) 1096 return [[self attachmentView] accessibilityAttributeNames]; 1097 1098 static NSArray* attributes = nil; 1099 static NSArray* anchorAttrs = nil; 1100 static NSArray* webAreaAttrs = nil; 1101 static NSArray* textAttrs = nil; 1102 static NSArray* listAttrs = nil; 1103 static NSArray* listBoxAttrs = nil; 1104 static NSArray* rangeAttrs = nil; 1105 static NSArray* commonMenuAttrs = nil; 1106 static NSArray* menuAttrs = nil; 1107 static NSArray* menuBarAttrs = nil; 1108 static NSArray* menuItemAttrs = nil; 1109 static NSArray* menuButtonAttrs = nil; 1110 static NSArray* controlAttrs = nil; 1111 static NSArray* tableAttrs = nil; 1112 static NSArray* tableRowAttrs = nil; 1113 static NSArray* tableColAttrs = nil; 1114 static NSArray* tableCellAttrs = nil; 1115 static NSArray* groupAttrs = nil; 1116 static NSArray* inputImageAttrs = nil; 1117 static NSArray* passwordFieldAttrs = nil; 1118 static NSArray* tabListAttrs = nil; 1119 static NSArray* comboBoxAttrs = nil; 1120 static NSArray* outlineAttrs = nil; 1121 static NSArray* outlineRowAttrs = nil; 1122 static NSArray* buttonAttrs = nil; 1123 static NSArray* scrollViewAttrs = nil; 1124 static NSArray* incrementorAttrs = nil; 1125 NSMutableArray* tempArray; 1126 if (attributes == nil) { 1127 attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, 1128 NSAccessibilitySubroleAttribute, 1129 NSAccessibilityRoleDescriptionAttribute, 1130 NSAccessibilityChildrenAttribute, 1131 NSAccessibilityHelpAttribute, 1132 NSAccessibilityParentAttribute, 1133 NSAccessibilityPositionAttribute, 1134 NSAccessibilitySizeAttribute, 1135 NSAccessibilityTitleAttribute, 1136 NSAccessibilityDescriptionAttribute, 1137 NSAccessibilityValueAttribute, 1138 NSAccessibilityFocusedAttribute, 1139 NSAccessibilityEnabledAttribute, 1140 NSAccessibilityWindowAttribute, 1141 @"AXSelectedTextMarkerRange", 1142 @"AXStartTextMarker", 1143 @"AXEndTextMarker", 1144 @"AXVisited", 1145 NSAccessibilityLinkedUIElementsAttribute, 1146 NSAccessibilitySelectedAttribute, 1147 NSAccessibilityBlockQuoteLevelAttribute, 1148 NSAccessibilityTopLevelUIElementAttribute, 1149 nil]; 1150 } 1151 if (commonMenuAttrs == nil) { 1152 commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, 1153 NSAccessibilityRoleDescriptionAttribute, 1154 NSAccessibilityChildrenAttribute, 1155 NSAccessibilityParentAttribute, 1156 NSAccessibilityEnabledAttribute, 1157 NSAccessibilityPositionAttribute, 1158 NSAccessibilitySizeAttribute, 1159 nil]; 1160 } 1161 if (anchorAttrs == nil) { 1162 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1163 [tempArray addObject:NSAccessibilityURLAttribute]; 1164 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 1165 anchorAttrs = [[NSArray alloc] initWithArray:tempArray]; 1166 [tempArray release]; 1167 } 1168 if (webAreaAttrs == nil) { 1169 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1170 [tempArray addObject:@"AXLinkUIElements"]; 1171 [tempArray addObject:@"AXLoaded"]; 1172 [tempArray addObject:@"AXLayoutCount"]; 1173 [tempArray addObject:NSAccessibilityLoadingProgressAttribute]; 1174 [tempArray addObject:NSAccessibilityURLAttribute]; 1175 webAreaAttrs = [[NSArray alloc] initWithArray:tempArray]; 1176 [tempArray release]; 1177 } 1178 if (textAttrs == nil) { 1179 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1180 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute]; 1181 [tempArray addObject:NSAccessibilitySelectedTextAttribute]; 1182 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute]; 1183 [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute]; 1184 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute]; 1185 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1186 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 1187 [tempArray addObject:NSAccessibilityRequiredAttribute]; 1188 [tempArray addObject:NSAccessibilityInvalidAttribute]; 1189 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute]; 1190 textAttrs = [[NSArray alloc] initWithArray:tempArray]; 1191 [tempArray release]; 1192 } 1193 if (listAttrs == nil) { 1194 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1195 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 1196 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 1197 [tempArray addObject:NSAccessibilityOrientationAttribute]; 1198 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1199 listAttrs = [[NSArray alloc] initWithArray:tempArray]; 1200 [tempArray release]; 1201 } 1202 if (listBoxAttrs == nil) { 1203 tempArray = [[NSMutableArray alloc] initWithArray:listAttrs]; 1204 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 1205 [tempArray addObject:NSAccessibilityRequiredAttribute]; 1206 [tempArray addObject:NSAccessibilityInvalidAttribute]; 1207 listBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; 1208 [tempArray release]; 1209 } 1210 if (rangeAttrs == nil) { 1211 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1212 [tempArray addObject:NSAccessibilityMinValueAttribute]; 1213 [tempArray addObject:NSAccessibilityMaxValueAttribute]; 1214 [tempArray addObject:NSAccessibilityOrientationAttribute]; 1215 [tempArray addObject:NSAccessibilityValueDescriptionAttribute]; 1216 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1217 rangeAttrs = [[NSArray alloc] initWithArray:tempArray]; 1218 [tempArray release]; 1219 } 1220 if (menuBarAttrs == nil) { 1221 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 1222 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 1223 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 1224 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1225 menuBarAttrs = [[NSArray alloc] initWithArray:tempArray]; 1226 [tempArray release]; 1227 } 1228 if (menuAttrs == nil) { 1229 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 1230 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; 1231 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; 1232 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1233 menuAttrs = [[NSArray alloc] initWithArray:tempArray]; 1234 [tempArray release]; 1235 } 1236 if (menuItemAttrs == nil) { 1237 tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; 1238 [tempArray addObject:NSAccessibilityTitleAttribute]; 1239 [tempArray addObject:NSAccessibilityHelpAttribute]; 1240 [tempArray addObject:NSAccessibilitySelectedAttribute]; 1241 [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute]; 1242 [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute]; 1243 [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute]; 1244 [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute]; 1245 [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute]; 1246 [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute]; 1247 [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute]; 1248 menuItemAttrs = [[NSArray alloc] initWithArray:tempArray]; 1249 [tempArray release]; 1250 } 1251 if (menuButtonAttrs == nil) { 1252 menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute, 1253 NSAccessibilityRoleDescriptionAttribute, 1254 NSAccessibilityParentAttribute, 1255 NSAccessibilityPositionAttribute, 1256 NSAccessibilitySizeAttribute, 1257 NSAccessibilityWindowAttribute, 1258 NSAccessibilityEnabledAttribute, 1259 NSAccessibilityFocusedAttribute, 1260 NSAccessibilityTitleAttribute, 1261 NSAccessibilityChildrenAttribute, nil]; 1262 } 1263 if (controlAttrs == nil) { 1264 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1265 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1266 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 1267 [tempArray addObject:NSAccessibilityRequiredAttribute]; 1268 [tempArray addObject:NSAccessibilityInvalidAttribute]; 1269 controlAttrs = [[NSArray alloc] initWithArray:tempArray]; 1270 [tempArray release]; 1271 } 1272 if (incrementorAttrs == nil) { 1273 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1274 [tempArray addObject:NSAccessibilityIncrementButtonAttribute]; 1275 [tempArray addObject:NSAccessibilityDecrementButtonAttribute]; 1276 incrementorAttrs = [[NSArray alloc] initWithArray:tempArray]; 1277 [tempArray release]; 1278 } 1279 if (buttonAttrs == nil) { 1280 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1281 // Buttons should not expose AXValue. 1282 [tempArray removeObject:NSAccessibilityValueAttribute]; 1283 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1284 [tempArray addObject:NSAccessibilityAccessKeyAttribute]; 1285 buttonAttrs = [[NSArray alloc] initWithArray:tempArray]; 1286 [tempArray release]; 1287 } 1288 if (comboBoxAttrs == nil) { 1289 tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs]; 1290 [tempArray addObject:NSAccessibilityExpandedAttribute]; 1291 comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; 1292 [tempArray release]; 1293 } 1294 if (tableAttrs == nil) { 1295 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1296 [tempArray addObject:NSAccessibilityRowsAttribute]; 1297 [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; 1298 [tempArray addObject:NSAccessibilityColumnsAttribute]; 1299 [tempArray addObject:NSAccessibilityVisibleColumnsAttribute]; 1300 [tempArray addObject:NSAccessibilityVisibleCellsAttribute]; 1301 [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute]; 1302 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute]; 1303 [tempArray addObject:NSAccessibilityHeaderAttribute]; 1304 tableAttrs = [[NSArray alloc] initWithArray:tempArray]; 1305 [tempArray release]; 1306 } 1307 if (tableRowAttrs == nil) { 1308 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1309 [tempArray addObject:NSAccessibilityIndexAttribute]; 1310 tableRowAttrs = [[NSArray alloc] initWithArray:tempArray]; 1311 [tempArray release]; 1312 } 1313 if (tableColAttrs == nil) { 1314 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1315 [tempArray addObject:NSAccessibilityIndexAttribute]; 1316 [tempArray addObject:NSAccessibilityHeaderAttribute]; 1317 [tempArray addObject:NSAccessibilityRowsAttribute]; 1318 [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; 1319 tableColAttrs = [[NSArray alloc] initWithArray:tempArray]; 1320 [tempArray release]; 1321 } 1322 if (tableCellAttrs == nil) { 1323 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1324 [tempArray addObject:NSAccessibilityRowIndexRangeAttribute]; 1325 [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute]; 1326 tableCellAttrs = [[NSArray alloc] initWithArray:tempArray]; 1327 [tempArray release]; 1328 } 1329 if (groupAttrs == nil) { 1330 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1331 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1332 groupAttrs = [[NSArray alloc] initWithArray:tempArray]; 1333 [tempArray release]; 1334 } 1335 if (inputImageAttrs == nil) { 1336 tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs]; 1337 [tempArray addObject:NSAccessibilityURLAttribute]; 1338 inputImageAttrs = [[NSArray alloc] initWithArray:tempArray]; 1339 [tempArray release]; 1340 } 1341 if (passwordFieldAttrs == nil) { 1342 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1343 [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; 1344 [tempArray addObject:NSAccessibilityRequiredAttribute]; 1345 [tempArray addObject:NSAccessibilityInvalidAttribute]; 1346 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute]; 1347 passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray]; 1348 [tempArray release]; 1349 } 1350 if (tabListAttrs == nil) { 1351 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1352 [tempArray addObject:NSAccessibilityTabsAttribute]; 1353 [tempArray addObject:NSAccessibilityContentsAttribute]; 1354 tabListAttrs = [[NSArray alloc] initWithArray:tempArray]; 1355 [tempArray release]; 1356 } 1357 if (outlineAttrs == nil) { 1358 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1359 [tempArray addObject:NSAccessibilitySelectedRowsAttribute]; 1360 [tempArray addObject:NSAccessibilityRowsAttribute]; 1361 [tempArray addObject:NSAccessibilityColumnsAttribute]; 1362 outlineAttrs = [[NSArray alloc] initWithArray:tempArray]; 1363 [tempArray release]; 1364 } 1365 if (outlineRowAttrs == nil) { 1366 tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs]; 1367 [tempArray addObject:NSAccessibilityDisclosingAttribute]; 1368 [tempArray addObject:NSAccessibilityDisclosedByRowAttribute]; 1369 [tempArray addObject:NSAccessibilityDisclosureLevelAttribute]; 1370 [tempArray addObject:NSAccessibilityDisclosedRowsAttribute]; 1371 outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray]; 1372 [tempArray release]; 1373 } 1374 if (scrollViewAttrs == nil) { 1375 tempArray = [[NSMutableArray alloc] initWithArray:attributes]; 1376 [tempArray addObject:NSAccessibilityContentsAttribute]; 1377 [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute]; 1378 [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute]; 1379 scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray]; 1380 [tempArray release]; 1381 } 1382 1383 NSArray *objectAttributes = attributes; 1384 1385 if (m_object->isPasswordField()) 1386 objectAttributes = passwordFieldAttrs; 1387 1388 else if (m_object->isWebArea()) 1389 objectAttributes = webAreaAttrs; 1390 1391 else if (m_object->isTextControl()) 1392 objectAttributes = textAttrs; 1393 1394 else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink()) 1395 objectAttributes = anchorAttrs; 1396 1397 else if (m_object->isAccessibilityTable()) 1398 objectAttributes = tableAttrs; 1399 else if (m_object->isTableColumn()) 1400 objectAttributes = tableColAttrs; 1401 else if (m_object->isTableCell()) 1402 objectAttributes = tableCellAttrs; 1403 else if (m_object->isTableRow()) { 1404 // An ARIA table row can be collapsed and expanded, so it needs the extra attributes. 1405 if (m_object->isARIATreeGridRow()) 1406 objectAttributes = outlineRowAttrs; 1407 else 1408 objectAttributes = tableRowAttrs; 1409 } 1410 1411 else if (m_object->isTree()) 1412 objectAttributes = outlineAttrs; 1413 else if (m_object->isTreeItem()) 1414 objectAttributes = outlineRowAttrs; 1415 1416 else if (m_object->isListBox()) 1417 objectAttributes = listBoxAttrs; 1418 else if (m_object->isList()) 1419 objectAttributes = listAttrs; 1420 1421 else if (m_object->isComboBox()) 1422 objectAttributes = comboBoxAttrs; 1423 1424 else if (m_object->isProgressIndicator() || m_object->isSlider()) 1425 objectAttributes = rangeAttrs; 1426 1427 // These are processed in order because an input image is a button, and a button is a control. 1428 else if (m_object->isInputImage()) 1429 objectAttributes = inputImageAttrs; 1430 else if (m_object->isButton()) 1431 objectAttributes = buttonAttrs; 1432 else if (m_object->isControl()) 1433 objectAttributes = controlAttrs; 1434 1435 else if (m_object->isGroup() || m_object->isListItem()) 1436 objectAttributes = groupAttrs; 1437 else if (m_object->isTabList()) 1438 objectAttributes = tabListAttrs; 1439 else if (m_object->isScrollView()) 1440 objectAttributes = scrollViewAttrs; 1441 else if (m_object->isSpinButton()) 1442 objectAttributes = incrementorAttrs; 1443 1444 else if (m_object->isMenu()) 1445 objectAttributes = menuAttrs; 1446 else if (m_object->isMenuBar()) 1447 objectAttributes = menuBarAttrs; 1448 else if (m_object->isMenuButton()) 1449 objectAttributes = menuButtonAttrs; 1450 else if (m_object->isMenuItem()) 1451 objectAttributes = menuItemAttrs; 1452 1453 NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames]; 1454 if ([additionalAttributes count]) 1455 objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes]; 1456 1457 return objectAttributes; 1458} 1459 1460- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange 1461{ 1462 if (!textMarkerRange) 1463 return VisiblePositionRange(); 1464 AXObjectCache* cache = m_object->axObjectCache(); 1465 return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange)); 1466} 1467 1468- (NSArray*)renderWidgetChildren 1469{ 1470 Widget* widget = m_object->widget(); 1471 if (!widget) 1472 return nil; 1473 return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute]; 1474} 1475 1476- (id)remoteAccessibilityParentObject 1477{ 1478 if (!m_object) 1479 return nil; 1480 1481 Document* document = m_object->document(); 1482 if (!document) 1483 return nil; 1484 1485 Frame* frame = document->frame(); 1486 if (!frame) 1487 return nil; 1488 1489 return frame->loader()->client()->accessibilityRemoteObject(); 1490} 1491 1492static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector) 1493{ 1494 unsigned length = [array count]; 1495 vector.reserveInitialCapacity(length); 1496 for (unsigned i = 0; i < length; ++i) { 1497 AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject]; 1498 if (obj) 1499 vector.append(obj); 1500 } 1501} 1502 1503static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector) 1504{ 1505 unsigned length = vector.size(); 1506 NSMutableArray* array = [NSMutableArray arrayWithCapacity: length]; 1507 for (unsigned i = 0; i < length; ++i) { 1508 WebAccessibilityObjectWrapper* wrapper = vector[i]->wrapper(); 1509 ASSERT(wrapper); 1510 if (wrapper) { 1511 // we want to return the attachment view instead of the object representing the attachment. 1512 // otherwise, we get palindrome errors in the AX hierarchy 1513 if (vector[i]->isAttachment() && [wrapper attachmentView]) 1514 [array addObject:[wrapper attachmentView]]; 1515 else 1516 [array addObject:wrapper]; 1517 } 1518 } 1519 return array; 1520} 1521 1522- (id)textMarkerRangeForSelection 1523{ 1524 VisibleSelection selection = m_object->selection(); 1525 if (selection.isNone()) 1526 return nil; 1527 return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()]; 1528} 1529 1530- (CGPoint)convertPointToScreenSpace:(FloatPoint &)point 1531{ 1532 FrameView* frameView = m_object->documentFrameView(); 1533 1534 // WebKit1 code path... platformWidget() exists. 1535 if (frameView && frameView->platformWidget()) { 1536 1537 NSPoint nsPoint = (NSPoint)point; 1538 NSView* view = frameView->documentView(); 1539 nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]]; 1540 return CGPointMake(nsPoint.x, nsPoint.y); 1541 1542 } else { 1543 1544 // Find the appropriate scroll view to use to convert the contents to the window. 1545 ScrollView* scrollView = 0; 1546 AccessibilityObject* parent = 0; 1547 for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) { 1548 if (parent->isAccessibilityScrollView()) { 1549 scrollView = toAccessibilityScrollView(parent)->scrollView(); 1550 break; 1551 } 1552 } 1553 1554 IntPoint intPoint = flooredIntPoint(point); 1555 if (scrollView) 1556 intPoint = scrollView->contentsToRootView(intPoint); 1557 1558 Page* page = m_object->page(); 1559 1560 // If we have an empty chrome client (like SVG) then we should use the page 1561 // of the scroll view parent to help us get to the screen rect. 1562 if (parent && page && page->chrome().client()->isEmptyChromeClient()) 1563 page = parent->page(); 1564 1565 if (page) { 1566 IntRect rect = IntRect(intPoint, IntSize(0, 0)); 1567 intPoint = page->chrome().rootViewToScreen(rect).location(); 1568 } 1569 1570 return intPoint; 1571 } 1572} 1573 1574static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element) 1575{ 1576 NSBezierPath *bezierPath = (NSBezierPath *)info; 1577 switch (element->type) { 1578 case kCGPathElementMoveToPoint: 1579 [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])]; 1580 break; 1581 case kCGPathElementAddLineToPoint: 1582 [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])]; 1583 break; 1584 case kCGPathElementAddCurveToPoint: 1585 [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])]; 1586 break; 1587 case kCGPathElementCloseSubpath: 1588 [bezierPath closePath]; 1589 break; 1590 default: 1591 break; 1592 } 1593} 1594 1595- (NSBezierPath *)bezierPathFromPath:(CGPathRef)path 1596{ 1597 NSBezierPath *bezierPath = [NSBezierPath bezierPath]; 1598 CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath); 1599 return bezierPath; 1600} 1601 1602- (NSBezierPath *)path 1603{ 1604 Path path = m_object->elementPath(); 1605 if (path.isEmpty()) 1606 return NULL; 1607 1608 CGPathRef transformedPath = [self convertPathToScreenSpace:path]; 1609 return [self bezierPathFromPath:transformedPath]; 1610} 1611 1612- (NSValue *)position 1613{ 1614 IntRect rect = pixelSnappedIntRect(m_object->elementRect()); 1615 1616 // The Cocoa accessibility API wants the lower-left corner. 1617 FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY()); 1618 1619 CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint]; 1620 1621 return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)]; 1622} 1623 1624typedef HashMap<int, NSString*> AccessibilityRoleMap; 1625 1626static const AccessibilityRoleMap& createAccessibilityRoleMap() 1627{ 1628 struct RoleEntry { 1629 AccessibilityRole value; 1630 NSString* string; 1631 }; 1632 1633 static const RoleEntry roles[] = { 1634 { UnknownRole, NSAccessibilityUnknownRole }, 1635 { ButtonRole, NSAccessibilityButtonRole }, 1636 { RadioButtonRole, NSAccessibilityRadioButtonRole }, 1637 { CheckBoxRole, NSAccessibilityCheckBoxRole }, 1638 { SliderRole, NSAccessibilitySliderRole }, 1639 { TabGroupRole, NSAccessibilityTabGroupRole }, 1640 { TextFieldRole, NSAccessibilityTextFieldRole }, 1641 { StaticTextRole, NSAccessibilityStaticTextRole }, 1642 { TextAreaRole, NSAccessibilityTextAreaRole }, 1643 { ScrollAreaRole, NSAccessibilityScrollAreaRole }, 1644 { PopUpButtonRole, NSAccessibilityPopUpButtonRole }, 1645 { MenuButtonRole, NSAccessibilityMenuButtonRole }, 1646 { TableRole, NSAccessibilityTableRole }, 1647 { ApplicationRole, NSAccessibilityApplicationRole }, 1648 { GroupRole, NSAccessibilityGroupRole }, 1649 { RadioGroupRole, NSAccessibilityRadioGroupRole }, 1650 { ListRole, NSAccessibilityListRole }, 1651 { DirectoryRole, NSAccessibilityListRole }, 1652 { ScrollBarRole, NSAccessibilityScrollBarRole }, 1653 { ValueIndicatorRole, NSAccessibilityValueIndicatorRole }, 1654 { ImageRole, NSAccessibilityImageRole }, 1655 { MenuBarRole, NSAccessibilityMenuBarRole }, 1656 { MenuRole, NSAccessibilityMenuRole }, 1657 { MenuItemRole, NSAccessibilityMenuItemRole }, 1658 { ColumnRole, NSAccessibilityColumnRole }, 1659 { RowRole, NSAccessibilityRowRole }, 1660 { ToolbarRole, NSAccessibilityToolbarRole }, 1661 { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole }, 1662 { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole }, 1663 { WindowRole, NSAccessibilityWindowRole }, 1664 { DrawerRole, NSAccessibilityDrawerRole }, 1665 { SystemWideRole, NSAccessibilitySystemWideRole }, 1666 { OutlineRole, NSAccessibilityOutlineRole }, 1667 { IncrementorRole, NSAccessibilityIncrementorRole }, 1668 { BrowserRole, NSAccessibilityBrowserRole }, 1669 { ComboBoxRole, NSAccessibilityComboBoxRole }, 1670 { SplitGroupRole, NSAccessibilitySplitGroupRole }, 1671 { SplitterRole, NSAccessibilitySplitterRole }, 1672 { ColorWellRole, NSAccessibilityColorWellRole }, 1673 { GrowAreaRole, NSAccessibilityGrowAreaRole }, 1674 { SheetRole, NSAccessibilitySheetRole }, 1675 { HelpTagRole, NSAccessibilityHelpTagRole }, 1676 { MatteRole, NSAccessibilityMatteRole }, 1677 { RulerRole, NSAccessibilityRulerRole }, 1678 { RulerMarkerRole, NSAccessibilityRulerMarkerRole }, 1679 { LinkRole, NSAccessibilityLinkRole }, 1680 { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole }, 1681 { GridRole, NSAccessibilityGridRole }, 1682 { WebCoreLinkRole, NSAccessibilityLinkRole }, 1683 { ImageMapLinkRole, NSAccessibilityLinkRole }, 1684 { ImageMapRole, @"AXImageMap" }, 1685 { ListMarkerRole, @"AXListMarker" }, 1686 { WebAreaRole, @"AXWebArea" }, 1687 { SeamlessWebAreaRole, NSAccessibilityGroupRole }, 1688 { HeadingRole, @"AXHeading" }, 1689 { ListBoxRole, NSAccessibilityListRole }, 1690 { ListBoxOptionRole, NSAccessibilityStaticTextRole }, 1691 { CellRole, NSAccessibilityCellRole }, 1692 { TableHeaderContainerRole, NSAccessibilityGroupRole }, 1693 { RowHeaderRole, NSAccessibilityGroupRole }, 1694 { DefinitionRole, NSAccessibilityGroupRole }, 1695 { DescriptionListDetailRole, NSAccessibilityGroupRole }, 1696 { DescriptionListTermRole, NSAccessibilityGroupRole }, 1697 { DescriptionListRole, NSAccessibilityListRole }, 1698 { SliderThumbRole, NSAccessibilityValueIndicatorRole }, 1699 { LandmarkApplicationRole, NSAccessibilityGroupRole }, 1700 { LandmarkBannerRole, NSAccessibilityGroupRole }, 1701 { LandmarkComplementaryRole, NSAccessibilityGroupRole }, 1702 { LandmarkContentInfoRole, NSAccessibilityGroupRole }, 1703 { LandmarkMainRole, NSAccessibilityGroupRole }, 1704 { LandmarkNavigationRole, NSAccessibilityGroupRole }, 1705 { LandmarkSearchRole, NSAccessibilityGroupRole }, 1706 { ApplicationAlertRole, NSAccessibilityGroupRole }, 1707 { ApplicationAlertDialogRole, NSAccessibilityGroupRole }, 1708 { ApplicationDialogRole, NSAccessibilityGroupRole }, 1709 { ApplicationLogRole, NSAccessibilityGroupRole }, 1710 { ApplicationMarqueeRole, NSAccessibilityGroupRole }, 1711 { ApplicationStatusRole, NSAccessibilityGroupRole }, 1712 { ApplicationTimerRole, NSAccessibilityGroupRole }, 1713 { DocumentRole, NSAccessibilityGroupRole }, 1714 { DocumentArticleRole, NSAccessibilityGroupRole }, 1715 { DocumentMathRole, NSAccessibilityGroupRole }, 1716 { DocumentNoteRole, NSAccessibilityGroupRole }, 1717 { DocumentRegionRole, NSAccessibilityGroupRole }, 1718 { UserInterfaceTooltipRole, NSAccessibilityGroupRole }, 1719 { TabRole, NSAccessibilityRadioButtonRole }, 1720 { TabListRole, NSAccessibilityTabGroupRole }, 1721 { TabPanelRole, NSAccessibilityGroupRole }, 1722 { TreeRole, NSAccessibilityOutlineRole }, 1723 { TreeItemRole, NSAccessibilityRowRole }, 1724 { ListItemRole, NSAccessibilityGroupRole }, 1725 { ParagraphRole, NSAccessibilityGroupRole }, 1726 { LabelRole, NSAccessibilityGroupRole }, 1727 { DivRole, NSAccessibilityGroupRole }, 1728 { FormRole, NSAccessibilityGroupRole }, 1729 { SpinButtonRole, NSAccessibilityIncrementorRole }, 1730 { FooterRole, NSAccessibilityGroupRole }, 1731 { ToggleButtonRole, NSAccessibilityButtonRole }, 1732 { CanvasRole, NSAccessibilityImageRole }, 1733 { SVGRootRole, NSAccessibilityGroupRole }, 1734 { LegendRole, NSAccessibilityGroupRole }, 1735 { MathElementRole, NSAccessibilityGroupRole }, 1736 { AudioRole, NSAccessibilityGroupRole }, 1737 { VideoRole, NSAccessibilityGroupRole } 1738 }; 1739 AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap; 1740 1741 const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); 1742 for (unsigned i = 0; i < numRoles; ++i) 1743 roleMap.set(roles[i].value, roles[i].string); 1744 return roleMap; 1745} 1746 1747static NSString* roleValueToNSString(AccessibilityRole value) 1748{ 1749 ASSERT(value); 1750 static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap(); 1751 return roleMap.get(value); 1752} 1753 1754- (NSString*)role 1755{ 1756 if (m_object->isAttachment()) 1757 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute]; 1758 AccessibilityRole role = m_object->roleValue(); 1759 if (role == CanvasRole && m_object->canvasHasFallbackContent()) 1760 role = GroupRole; 1761 NSString* string = roleValueToNSString(role); 1762 if (string != nil) 1763 return string; 1764 return NSAccessibilityUnknownRole; 1765} 1766 1767- (NSString*)subrole 1768{ 1769 if (m_object->isPasswordField()) 1770 return NSAccessibilitySecureTextFieldSubrole; 1771 if (m_object->isSearchField()) 1772 return NSAccessibilitySearchFieldSubrole; 1773 1774 if (m_object->isAttachment()) { 1775 NSView* attachView = [self attachmentView]; 1776 if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) { 1777 return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute]; 1778 } 1779 } 1780 1781 if (m_object->isSpinButtonPart()) { 1782 if (toAccessibilitySpinButtonPart(m_object)->isIncrementor()) 1783 return NSAccessibilityIncrementArrowSubrole; 1784 1785 return NSAccessibilityDecrementArrowSubrole; 1786 } 1787 1788 if (m_object->isFileUploadButton()) 1789 return @"AXFileUploadButton"; 1790 1791 if (m_object->isTreeItem()) 1792 return NSAccessibilityOutlineRowSubrole; 1793 1794 if (m_object->isList()) { 1795 AccessibilityList* listObject = toAccessibilityList(m_object); 1796 if (listObject->isUnorderedList() || listObject->isOrderedList()) 1797 return NSAccessibilityContentListSubrole; 1798 if (listObject->isDescriptionList()) { 1799#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090 1800 return NSAccessibilityDefinitionListSubrole; 1801#else 1802 return NSAccessibilityDescriptionListSubrole; 1803#endif 1804 } 1805 } 1806 1807 // ARIA content subroles. 1808 switch (m_object->roleValue()) { 1809 case LandmarkApplicationRole: 1810 return @"AXLandmarkApplication"; 1811 case LandmarkBannerRole: 1812 return @"AXLandmarkBanner"; 1813 case LandmarkComplementaryRole: 1814 return @"AXLandmarkComplementary"; 1815 // Footer roles should appear as content info types. 1816 case FooterRole: 1817 case LandmarkContentInfoRole: 1818 return @"AXLandmarkContentInfo"; 1819 case LandmarkMainRole: 1820 return @"AXLandmarkMain"; 1821 case LandmarkNavigationRole: 1822 return @"AXLandmarkNavigation"; 1823 case LandmarkSearchRole: 1824 return @"AXLandmarkSearch"; 1825 case ApplicationAlertRole: 1826 return @"AXApplicationAlert"; 1827 case ApplicationAlertDialogRole: 1828 return @"AXApplicationAlertDialog"; 1829 case ApplicationDialogRole: 1830 return @"AXApplicationDialog"; 1831 case ApplicationLogRole: 1832 return @"AXApplicationLog"; 1833 case ApplicationMarqueeRole: 1834 return @"AXApplicationMarquee"; 1835 case ApplicationStatusRole: 1836 return @"AXApplicationStatus"; 1837 case ApplicationTimerRole: 1838 return @"AXApplicationTimer"; 1839 case DocumentRole: 1840 return @"AXDocument"; 1841 case DocumentArticleRole: 1842 return @"AXDocumentArticle"; 1843 case DocumentMathRole: 1844 return @"AXDocumentMath"; 1845 case DocumentNoteRole: 1846 return @"AXDocumentNote"; 1847 case DocumentRegionRole: 1848 return @"AXDocumentRegion"; 1849 case UserInterfaceTooltipRole: 1850 return @"AXUserInterfaceTooltip"; 1851 case TabPanelRole: 1852 return @"AXTabPanel"; 1853 case DefinitionRole: 1854 return @"AXDefinition"; 1855 case DescriptionListTermRole: 1856 return @"AXTerm"; 1857 case DescriptionListDetailRole: 1858 return @"AXDescription"; 1859 // Default doesn't return anything, so roles defined below can be chosen. 1860 default: 1861 break; 1862 } 1863 1864 if (m_object->roleValue() == MathElementRole) { 1865 if (m_object->isMathFraction()) 1866 return @"AXMathFraction"; 1867 if (m_object->isMathFenced()) 1868 return @"AXMathFenced"; 1869 if (m_object->isMathSubscriptSuperscript()) 1870 return @"AXMathSubscriptSuperscript"; 1871 if (m_object->isMathRow()) 1872 return @"AXMathRow"; 1873 if (m_object->isMathUnderOver()) 1874 return @"AXMathUnderOver"; 1875 if (m_object->isMathSquareRoot()) 1876 return @"AXMathSquareRoot"; 1877 if (m_object->isMathRoot()) 1878 return @"AXMathRoot"; 1879 if (m_object->isMathText()) 1880 return @"AXMathText"; 1881 if (m_object->isMathNumber()) 1882 return @"AXMathNumber"; 1883 if (m_object->isMathIdentifier()) 1884 return @"AXMathIdentifier"; 1885 if (m_object->isMathTable()) 1886 return @"AXMathTable"; 1887 if (m_object->isMathTableRow()) 1888 return @"AXMathTableRow"; 1889 if (m_object->isMathTableCell()) 1890 return @"AXMathTableCell"; 1891 if (m_object->isMathFenceOperator()) 1892 return @"AXMathFenceOperator"; 1893 if (m_object->isMathSeparatorOperator()) 1894 return @"AXMathSeparatorOperator"; 1895 if (m_object->isMathOperator()) 1896 return @"AXMathOperator"; 1897 if (m_object->isMathMultiscript()) 1898 return @"AXMathMultiscript"; 1899 } 1900 1901 if (m_object->roleValue() == VideoRole) 1902 return @"AXVideo"; 1903 if (m_object->roleValue() == AudioRole) 1904 return @"AXAudio"; 1905 1906 if (m_object->isMediaTimeline()) 1907 return NSAccessibilityTimelineSubrole; 1908 1909 return nil; 1910} 1911 1912- (NSString*)roleDescription 1913{ 1914 if (!m_object) 1915 return nil; 1916 1917 // attachments have the AXImage role, but a different subrole 1918 if (m_object->isAttachment()) 1919 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute]; 1920 1921 NSString* axRole = [self role]; 1922 1923 if ([axRole isEqualToString:NSAccessibilityGroupRole]) { 1924 1925 NSString *ariaLandmarkRoleDescription = [self ariaLandmarkRoleDescription]; 1926 if (ariaLandmarkRoleDescription) 1927 return ariaLandmarkRoleDescription; 1928 1929 switch (m_object->roleValue()) { 1930 case AudioRole: 1931 return localizedMediaControlElementString("AudioElement"); 1932 case DefinitionRole: 1933 return AXDefinitionText(); 1934 case DescriptionListTermRole: 1935 return AXDescriptionListTermText(); 1936 case DescriptionListDetailRole: 1937 return AXDescriptionListDetailText(); 1938 case FooterRole: 1939 return AXFooterRoleDescriptionText(); 1940 case VideoRole: 1941 return localizedMediaControlElementString("VideoElement"); 1942 default: 1943 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]); 1944 } 1945 } 1946 1947 if ([axRole isEqualToString:@"AXWebArea"]) 1948 return AXWebAreaText(); 1949 1950 if ([axRole isEqualToString:@"AXLink"]) 1951 return AXLinkText(); 1952 1953 if ([axRole isEqualToString:@"AXListMarker"]) 1954 return AXListMarkerText(); 1955 1956 if ([axRole isEqualToString:@"AXImageMap"]) 1957 return AXImageMapText(); 1958 1959 if ([axRole isEqualToString:@"AXHeading"]) 1960 return AXHeadingText(); 1961 1962 if (m_object->isFileUploadButton()) 1963 return AXFileUploadButtonText(); 1964 1965 // Only returning for DL (not UL or OL) because description changed with HTML5 from 'definition list' to 1966 // superset 'description list' and does not return the same values in AX API on some OS versions. 1967 if (m_object->isList()) { 1968 AccessibilityList* listObject = toAccessibilityList(m_object); 1969 if (listObject->isDescriptionList()) 1970 return AXDescriptionListText(); 1971 } 1972 1973 // AppKit also returns AXTab for the role description for a tab item. 1974 if (m_object->isTabItem()) 1975 return NSAccessibilityRoleDescription(@"AXTab", nil); 1976 1977 // We should try the system default role description for all other roles. 1978 // If we get the same string back, then as a last resort, return unknown. 1979 NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]); 1980 1981 // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description 1982 // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions 1983 // we should fallback on a role description ignoring the subrole in these cases. 1984 if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, [self subrole]]]) 1985 defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil); 1986 1987 if (![defaultRoleDescription isEqualToString:axRole]) 1988 return defaultRoleDescription; 1989 1990 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil); 1991} 1992 1993- (id)scrollViewParent 1994{ 1995 if (!m_object || !m_object->isAccessibilityScrollView()) 1996 return nil; 1997 1998 // If this scroll view provides it's parent object (because it's a sub-frame), then 1999 // we should not find the remoteAccessibilityParent. 2000 if (m_object->parentObject()) 2001 return nil; 2002 2003 AccessibilityScrollView* scrollView = toAccessibilityScrollView(m_object); 2004 ScrollView* scroll = scrollView->scrollView(); 2005 if (!scroll) 2006 return nil; 2007 2008 if (scroll->platformWidget()) 2009 return NSAccessibilityUnignoredAncestor(scroll->platformWidget()); 2010 2011 return [self remoteAccessibilityParentObject]; 2012} 2013 2014// FIXME: Different kinds of elements are putting the title tag to use in different 2015// AX fields. This should be rectified, but in the initial patch I want to achieve 2016// parity with existing behavior. 2017- (BOOL)titleTagShouldBeUsedInDescriptionField 2018{ 2019 return (m_object->isLink() && !m_object->isImageMapLink()) || m_object->isImage(); 2020} 2021 2022// This should be the "visible" text that's actually on the screen if possible. 2023// If there's alternative text, that can override the title. 2024- (NSString *)accessibilityTitle 2025{ 2026 // Static text objects should not have a title. Its content is communicated in its AXValue. 2027 if (m_object->roleValue() == StaticTextRole) 2028 return [NSString string]; 2029 2030 // A file upload button presents a challenge because it has button text and a value, but the 2031 // API doesn't support this paradigm. 2032 // The compromise is to return the button type in the role description and the value of the file path in the title 2033 if (m_object->isFileUploadButton()) 2034 return m_object->stringValue(); 2035 2036 Vector<AccessibilityText> textOrder; 2037 m_object->accessibilityText(textOrder); 2038 2039 unsigned length = textOrder.size(); 2040 for (unsigned k = 0; k < length; k++) { 2041 const AccessibilityText& text = textOrder[k]; 2042 2043 // If we have alternative text, then we should not expose a title. 2044 if (text.textSource == AlternativeText) 2045 break; 2046 2047 // Once we encounter visible text, or the text from our children that should be used foremost. 2048 if (text.textSource == VisibleText || text.textSource == ChildrenText) 2049 return text.text; 2050 2051 // If there's an element that labels this object and it's not exposed, then we should use 2052 // that text as our title. 2053 if (text.textSource == LabelByElementText && !m_object->exposesTitleUIElement()) 2054 return text.text; 2055 2056 // FIXME: The title tag is used in certain cases for the title. This usage should 2057 // probably be in the description field since it's not "visible". 2058 if (text.textSource == TitleTagText && ![self titleTagShouldBeUsedInDescriptionField]) 2059 return text.text; 2060 } 2061 2062 return [NSString string]; 2063} 2064 2065- (NSString *)accessibilityDescription 2066{ 2067 // Static text objects should not have a description. Its content is communicated in its AXValue. 2068 // One exception is the media control labels that have a value and a description. Those are set programatically. 2069 if (m_object->roleValue() == StaticTextRole && !m_object->isMediaControlLabel()) 2070 return [NSString string]; 2071 2072 Vector<AccessibilityText> textOrder; 2073 m_object->accessibilityText(textOrder); 2074 2075 unsigned length = textOrder.size(); 2076 for (unsigned k = 0; k < length; k++) { 2077 const AccessibilityText& text = textOrder[k]; 2078 2079 if (text.textSource == AlternativeText) 2080 return text.text; 2081 2082 if (text.textSource == TitleTagText && [self titleTagShouldBeUsedInDescriptionField]) 2083 return text.text; 2084 } 2085 2086 return [NSString string]; 2087} 2088 2089- (NSString *)accessibilityHelpText 2090{ 2091 Vector<AccessibilityText> textOrder; 2092 m_object->accessibilityText(textOrder); 2093 2094 unsigned length = textOrder.size(); 2095 bool descriptiveTextAvailable = false; 2096 for (unsigned k = 0; k < length; k++) { 2097 const AccessibilityText& text = textOrder[k]; 2098 2099 if (text.textSource == HelpText || text.textSource == SummaryText) 2100 return text.text; 2101 2102 // If an element does NOT have other descriptive text the title tag should be used as its descriptive text. 2103 // But, if those ARE available, then the title tag should be used for help text instead. 2104 switch (text.textSource) { 2105 case AlternativeText: 2106 case VisibleText: 2107 case ChildrenText: 2108 case LabelByElementText: 2109 descriptiveTextAvailable = true; 2110 default: 2111 break; 2112 } 2113 2114 if (text.textSource == TitleTagText && descriptiveTextAvailable) 2115 return text.text; 2116 } 2117 2118 return [NSString string]; 2119} 2120 2121// FIXME: split up this function in a better way. 2122// suggestions: Use a hash table that maps attribute names to function calls, 2123// or maybe pointers to member functions 2124- (id)accessibilityAttributeValue:(NSString*)attributeName 2125{ 2126 if (![self updateObjectBackingStore]) 2127 return nil; 2128 2129 if ([attributeName isEqualToString: NSAccessibilityRoleAttribute]) 2130 return [self role]; 2131 2132 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute]) 2133 return [self subrole]; 2134 2135 if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute]) 2136 return [self roleDescription]; 2137 2138 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) { 2139 2140 // This will return the parent of the AXWebArea, if this is a web area. 2141 id scrollViewParent = [self scrollViewParent]; 2142 if (scrollViewParent) 2143 return scrollViewParent; 2144 2145 // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent. 2146 if (m_object->isTreeItem()) { 2147 AccessibilityObject* parent = m_object->parentObjectUnignored(); 2148 while (parent) { 2149 if (parent->isTree()) 2150 return parent->wrapper(); 2151 parent = parent->parentObjectUnignored(); 2152 } 2153 } 2154 2155 AccessibilityObject* parent = m_object->parentObjectUnignored(); 2156 if (!parent) 2157 return nil; 2158 2159 // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent 2160 // should be reported directly as such. 2161 if (m_object->isWebArea() && parent->isAttachment()) 2162 return [parent->wrapper() attachmentView]; 2163 2164 return parent->wrapper(); 2165 } 2166 2167 if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) { 2168 if (m_object->children().isEmpty()) { 2169 NSArray* children = [self renderWidgetChildren]; 2170 if (children != nil) 2171 return children; 2172 } 2173 2174 // The tree's (AXOutline) children are supposed to be its rows and columns. 2175 // The ARIA spec doesn't have columns, so we just need rows. 2176 if (m_object->isTree()) 2177 return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute]; 2178 2179 // A tree item should only expose its content as its children (not its rows) 2180 if (m_object->isTreeItem()) { 2181 AccessibilityObject::AccessibilityChildrenVector contentCopy; 2182 m_object->ariaTreeItemContent(contentCopy); 2183 return convertToNSArray(contentCopy); 2184 } 2185 2186 return convertToNSArray(m_object->children()); 2187 } 2188 2189 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { 2190 if (m_object->isListBox()) { 2191 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 2192 m_object->selectedChildren(selectedChildrenCopy); 2193 return convertToNSArray(selectedChildrenCopy); 2194 } 2195 return nil; 2196 } 2197 2198 if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) { 2199 if (m_object->isListBox()) { 2200 AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy; 2201 m_object->visibleChildren(visibleChildrenCopy); 2202 return convertToNSArray(visibleChildrenCopy); 2203 } 2204 else if (m_object->isList()) 2205 return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; 2206 2207 return nil; 2208 } 2209 2210 2211 if (m_object->isWebArea()) { 2212 if ([attributeName isEqualToString:@"AXLinkUIElements"]) { 2213 AccessibilityObject::AccessibilityChildrenVector links; 2214 static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links); 2215 return convertToNSArray(links); 2216 } 2217 if ([attributeName isEqualToString:@"AXLoaded"]) 2218 return [NSNumber numberWithBool:m_object->isLoaded()]; 2219 if ([attributeName isEqualToString:@"AXLayoutCount"]) 2220 return [NSNumber numberWithInt:m_object->layoutCount()]; 2221 if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute]) 2222 return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()]; 2223 } 2224 2225 if (m_object->isTextControl()) { 2226 if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) { 2227 int length = m_object->textLength(); 2228 if (length < 0) 2229 return nil; 2230 return [NSNumber numberWithUnsignedInt:length]; 2231 } 2232 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { 2233 String selectedText = m_object->selectedText(); 2234 if (selectedText.isNull()) 2235 return nil; 2236 return (NSString*)selectedText; 2237 } 2238 if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { 2239 PlainTextRange textRange = m_object->selectedTextRange(); 2240 if (textRange.isNull()) 2241 return [NSValue valueWithRange:NSMakeRange(0, 0)]; 2242 return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)]; 2243 } 2244 // TODO: Get actual visible range. <rdar://problem/4712101> 2245 if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) 2246 return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())]; 2247 if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) { 2248 // if selectionEnd > 0, then there is selected text and this question should not be answered 2249 if (m_object->isPasswordField() || m_object->selectionEnd() > 0) 2250 return nil; 2251 2252 AccessibilityObject* focusedObject = m_object->focusedUIElement(); 2253 if (focusedObject != m_object) 2254 return nil; 2255 2256 VisiblePosition focusedPosition = focusedObject->visiblePositionForIndex(focusedObject->selectionStart(), true); 2257 int lineNumber = m_object->lineForPosition(focusedPosition); 2258 if (lineNumber < 0) 2259 return nil; 2260 2261 return [NSNumber numberWithInt:lineNumber]; 2262 } 2263 } 2264 2265 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) { 2266 KURL url = m_object->url(); 2267 if (url.isNull()) 2268 return nil; 2269 return (NSURL*)url; 2270 } 2271 2272 // Only native spin buttons have increment and decrement buttons. 2273 if (m_object->isNativeSpinButton()) { 2274 if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute]) 2275 return toAccessibilitySpinButton(m_object)->incrementButton()->wrapper(); 2276 if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute]) 2277 return toAccessibilitySpinButton(m_object)->decrementButton()->wrapper(); 2278 } 2279 2280 if ([attributeName isEqualToString: @"AXVisited"]) 2281 return [NSNumber numberWithBool: m_object->isVisited()]; 2282 2283 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) { 2284 if (m_object->isAttachment()) { 2285 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) 2286 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute]; 2287 } 2288 2289 return [self accessibilityTitle]; 2290 } 2291 2292 if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) { 2293 if (m_object->isAttachment()) { 2294 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute]) 2295 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute]; 2296 } 2297 return [self accessibilityDescription]; 2298 } 2299 2300 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { 2301 if (m_object->isAttachment()) { 2302 if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 2303 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute]; 2304 } 2305 if (m_object->supportsRangeValue()) 2306 return [NSNumber numberWithFloat:m_object->valueForRange()]; 2307 if (m_object->roleValue() == SliderThumbRole) 2308 return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()]; 2309 if (m_object->isHeading()) 2310 return [NSNumber numberWithInt:m_object->headingLevel()]; 2311 2312 if (m_object->isCheckboxOrRadio()) { 2313 switch (m_object->checkboxOrRadioValue()) { 2314 case ButtonStateOff: 2315 return [NSNumber numberWithInt:0]; 2316 case ButtonStateOn: 2317 return [NSNumber numberWithInt:1]; 2318 case ButtonStateMixed: 2319 return [NSNumber numberWithInt:2]; 2320 } 2321 } 2322 2323 // radio groups return the selected radio button as the AXValue 2324 if (m_object->isRadioGroup()) { 2325 AccessibilityObject* radioButton = m_object->selectedRadioButton(); 2326 if (!radioButton) 2327 return nil; 2328 return radioButton->wrapper(); 2329 } 2330 2331 if (m_object->isTabList()) { 2332 AccessibilityObject* tabItem = m_object->selectedTabItem(); 2333 if (!tabItem) 2334 return nil; 2335 return tabItem->wrapper(); 2336 } 2337 2338 if (m_object->isTabItem()) 2339 return [NSNumber numberWithInt:m_object->isSelected()]; 2340 2341 if (m_object->isColorWell()) { 2342 int r, g, b; 2343 m_object->colorValue(r, g, b); 2344 return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.]; 2345 } 2346 2347 return m_object->stringValue(); 2348 } 2349 2350 if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) { 2351 const unichar ch = 0x2713; // ✓ used on Mac for selected menu items. 2352 return (m_object->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil; 2353 } 2354 2355 if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) 2356 return [NSNumber numberWithFloat:m_object->minValueForRange()]; 2357 2358 if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) 2359 return [NSNumber numberWithFloat:m_object->maxValueForRange()]; 2360 2361 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute]) 2362 return [self accessibilityHelpText]; 2363 2364 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) 2365 return [NSNumber numberWithBool: m_object->isFocused()]; 2366 2367 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute]) 2368 return [NSNumber numberWithBool: m_object->isEnabled()]; 2369 2370 if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) { 2371 IntSize s = m_object->pixelSnappedSize(); 2372 return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())]; 2373 } 2374 2375 if ([attributeName isEqualToString: NSAccessibilityPositionAttribute]) 2376 return [self position]; 2377 if ([attributeName isEqualToString:NSAccessibilityPathAttribute]) 2378 return [self path]; 2379 2380 if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] || 2381 [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) { 2382 2383 id remoteParent = [self remoteAccessibilityParentObject]; 2384 if (remoteParent) 2385 return [remoteParent accessibilityAttributeValue:attributeName]; 2386 2387 FrameView* fv = m_object->documentFrameView(); 2388 if (fv) 2389 return [fv->platformWidget() window]; 2390 return nil; 2391 } 2392 2393 if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) { 2394 AtomicString accessKey = m_object->accessKey(); 2395 if (accessKey.isNull()) 2396 return nil; 2397 return accessKey; 2398 } 2399 2400 if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) { 2401 if (m_object->isTabList()) { 2402 AccessibilityObject::AccessibilityChildrenVector tabsChildren; 2403 m_object->tabChildren(tabsChildren); 2404 return convertToNSArray(tabsChildren); 2405 } 2406 } 2407 2408 if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) { 2409 // The contents of a tab list are all the children except the tabs. 2410 if (m_object->isTabList()) { 2411 AccessibilityObject::AccessibilityChildrenVector children = m_object->children(); 2412 AccessibilityObject::AccessibilityChildrenVector tabsChildren; 2413 m_object->tabChildren(tabsChildren); 2414 2415 AccessibilityObject::AccessibilityChildrenVector contents; 2416 unsigned childrenSize = children.size(); 2417 for (unsigned k = 0; k < childrenSize; ++k) { 2418 if (tabsChildren.find(children[k]) == WTF::notFound) 2419 contents.append(children[k]); 2420 } 2421 return convertToNSArray(contents); 2422 } else if (m_object->isScrollView()) { 2423 AccessibilityObject::AccessibilityChildrenVector children = m_object->children(); 2424 2425 // A scrollView's contents are everything except the scroll bars. 2426 AccessibilityObject::AccessibilityChildrenVector contents; 2427 unsigned childrenSize = children.size(); 2428 for (unsigned k = 0; k < childrenSize; ++k) { 2429 if (!children[k]->isScrollbar()) 2430 contents.append(children[k]); 2431 } 2432 return convertToNSArray(contents); 2433 } 2434 } 2435 2436 if (m_object->isAccessibilityTable()) { 2437 // TODO: distinguish between visible and non-visible rows 2438 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 2439 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { 2440 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows()); 2441 } 2442 // TODO: distinguish between visible and non-visible columns 2443 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] || 2444 [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) { 2445 return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns()); 2446 } 2447 2448 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 2449 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 2450 m_object->selectedChildren(selectedChildrenCopy); 2451 return convertToNSArray(selectedChildrenCopy); 2452 } 2453 2454 // HTML tables don't support these 2455 if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] || 2456 [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute]) 2457 return nil; 2458 2459 if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) { 2460 AccessibilityObject::AccessibilityChildrenVector columnHeaders; 2461 static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders); 2462 return convertToNSArray(columnHeaders); 2463 } 2464 2465 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { 2466 AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer(); 2467 if (headerContainer) 2468 return headerContainer->wrapper(); 2469 return nil; 2470 } 2471 2472 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) { 2473 AccessibilityObject::AccessibilityChildrenVector rowHeaders; 2474 static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders); 2475 return convertToNSArray(rowHeaders); 2476 } 2477 2478 if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) { 2479 AccessibilityObject::AccessibilityChildrenVector cells; 2480 static_cast<AccessibilityTable*>(m_object)->cells(cells); 2481 return convertToNSArray(cells); 2482 } 2483 } 2484 2485 if (m_object->isTableColumn()) { 2486 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) 2487 return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()]; 2488 2489 // rows attribute for a column is the list of all the elements in that column at each row 2490 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || 2491 [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { 2492 return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children()); 2493 } 2494 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { 2495 AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject(); 2496 if (!header) 2497 return nil; 2498 return header->wrapper(); 2499 } 2500 } 2501 2502 if (m_object->isTableCell()) { 2503 if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) { 2504 pair<unsigned, unsigned> rowRange; 2505 static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange); 2506 return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)]; 2507 } 2508 if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) { 2509 pair<unsigned, unsigned> columnRange; 2510 static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange); 2511 return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)]; 2512 } 2513 } 2514 2515 if (m_object->isTree()) { 2516 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 2517 AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; 2518 m_object->selectedChildren(selectedChildrenCopy); 2519 return convertToNSArray(selectedChildrenCopy); 2520 } 2521 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) { 2522 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 2523 m_object->ariaTreeRows(rowsCopy); 2524 return convertToNSArray(rowsCopy); 2525 } 2526 2527 // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least. 2528 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]) 2529 return [NSArray array]; 2530 } 2531 2532 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) { 2533 if (m_object->isTreeItem()) { 2534 AccessibilityObject* parent = m_object->parentObject(); 2535 for (; parent && !parent->isTree(); parent = parent->parentObject()) 2536 { } 2537 2538 if (!parent) 2539 return nil; 2540 2541 // Find the index of this item by iterating the parents. 2542 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 2543 parent->ariaTreeRows(rowsCopy); 2544 size_t count = rowsCopy.size(); 2545 for (size_t k = 0; k < count; ++k) 2546 if (rowsCopy[k]->wrapper() == self) 2547 return [NSNumber numberWithUnsignedInt:k]; 2548 2549 return nil; 2550 } 2551 if (m_object->isTableRow()) { 2552 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) 2553 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()]; 2554 } 2555 } 2556 2557 // The rows that are considered inside this row. 2558 if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) { 2559 if (m_object->isTreeItem()) { 2560 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 2561 m_object->ariaTreeItemDisclosedRows(rowsCopy); 2562 return convertToNSArray(rowsCopy); 2563 } else if (m_object->isARIATreeGridRow()) { 2564 AccessibilityObject::AccessibilityChildrenVector rowsCopy; 2565 static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy); 2566 return convertToNSArray(rowsCopy); 2567 } 2568 } 2569 2570 // The row that contains this row. It should be the same as the first parent that is a treeitem. 2571 if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) { 2572 if (m_object->isTreeItem()) { 2573 AccessibilityObject* parent = m_object->parentObject(); 2574 while (parent) { 2575 if (parent->isTreeItem()) 2576 return parent->wrapper(); 2577 // If the parent is the tree itself, then this value == nil. 2578 if (parent->isTree()) 2579 return nil; 2580 parent = parent->parentObject(); 2581 } 2582 return nil; 2583 } else if (m_object->isARIATreeGridRow()) { 2584 AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow(); 2585 if (!row) 2586 return nil; 2587 return row->wrapper(); 2588 } 2589 } 2590 2591 if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) { 2592 // Convert from 1-based level (from aria-level spec) to 0-based level (Mac) 2593 int level = m_object->hierarchicalLevel(); 2594 if (level > 0) 2595 level -= 1; 2596 return [NSNumber numberWithInt:level]; 2597 } 2598 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 2599 return [NSNumber numberWithBool:m_object->isExpanded()]; 2600 2601 if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute]) 2602 return NSAccessibilityVerticalOrientationValue; 2603 2604 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) 2605 return [self textMarkerRangeForSelection]; 2606 2607 if (m_object->renderer()) { 2608 if ([attributeName isEqualToString: @"AXStartTextMarker"]) 2609 return [self textMarkerForVisiblePosition:startOfDocument(m_object->renderer()->document())]; 2610 if ([attributeName isEqualToString: @"AXEndTextMarker"]) 2611 return [self textMarkerForVisiblePosition:endOfDocument(m_object->renderer()->document())]; 2612 } 2613 2614 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute]) 2615 return [NSNumber numberWithInt:m_object->blockquoteLevel()]; 2616 if ([attributeName isEqualToString:@"AXTableLevel"]) 2617 return [NSNumber numberWithInt:m_object->tableLevel()]; 2618 2619 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) { 2620 AccessibilityObject::AccessibilityChildrenVector linkedUIElements; 2621 m_object->linkedUIElements(linkedUIElements); 2622 if (linkedUIElements.size() == 0) 2623 return nil; 2624 return convertToNSArray(linkedUIElements); 2625 } 2626 2627 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) 2628 return [NSNumber numberWithBool:m_object->isSelected()]; 2629 2630 if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) { 2631 AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton(); 2632 if (uiElement) 2633 return [NSArray arrayWithObject:uiElement->wrapper()]; 2634 } 2635 2636 if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) { 2637 if (!m_object->exposesTitleUIElement()) 2638 return nil; 2639 2640 AccessibilityObject* obj = m_object->titleUIElement(); 2641 if (obj) 2642 return obj->wrapper(); 2643 return nil; 2644 } 2645 2646 if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute]) 2647 return m_object->valueDescription(); 2648 2649 if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) { 2650 AccessibilityOrientation elementOrientation = m_object->orientation(); 2651 if (elementOrientation == AccessibilityOrientationVertical) 2652 return NSAccessibilityVerticalOrientationValue; 2653 if (elementOrientation == AccessibilityOrientationHorizontal) 2654 return NSAccessibilityHorizontalOrientationValue; 2655 return nil; 2656 } 2657 2658 if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) { 2659 AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal); 2660 if (scrollBar) 2661 return scrollBar->wrapper(); 2662 return nil; 2663 } 2664 if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) { 2665 AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical); 2666 if (scrollBar) 2667 return scrollBar->wrapper(); 2668 return nil; 2669 } 2670 2671 if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) { 2672 switch (m_object->sortDirection()) { 2673 case SortDirectionAscending: 2674 return NSAccessibilityAscendingSortDirectionValue; 2675 case SortDirectionDescending: 2676 return NSAccessibilityDescendingSortDirectionValue; 2677 default: 2678 return NSAccessibilityUnknownSortDirectionValue; 2679 } 2680 } 2681 2682 if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute]) 2683 return m_object->language(); 2684 2685 if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute]) 2686 return [NSNumber numberWithBool:m_object->isExpanded()]; 2687 2688 if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute]) 2689 return [NSNumber numberWithBool:m_object->isRequired()]; 2690 2691 if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute]) 2692 return m_object->invalidStatus(); 2693 2694 if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) { 2695 AccessibilityObject::AccessibilityChildrenVector ariaOwns; 2696 m_object->ariaOwnsElements(ariaOwns); 2697 return convertToNSArray(ariaOwns); 2698 } 2699 2700 if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute]) 2701 return [NSNumber numberWithInt:m_object->ariaPosInSet()]; 2702 if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute]) 2703 return [NSNumber numberWithInt:m_object->ariaSetSize()]; 2704 2705 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 2706 return [NSNumber numberWithBool:m_object->isARIAGrabbed()]; 2707 2708 if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) { 2709 Vector<String> dropEffects; 2710 m_object->determineARIADropEffects(dropEffects); 2711 size_t length = dropEffects.size(); 2712 2713 NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length]; 2714 for (size_t i = 0; i < length; ++i) 2715 [dropEffectsArray addObject:dropEffects[i]]; 2716 return dropEffectsArray; 2717 } 2718 2719 if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute]) 2720 return m_object->placeholderValue(); 2721 2722 if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute]) 2723 return [NSNumber numberWithBool:m_object->ariaHasPopup()]; 2724 2725 // ARIA Live region attributes. 2726 if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute]) 2727 return m_object->ariaLiveRegionStatus(); 2728 if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute]) 2729 return m_object->ariaLiveRegionRelevant(); 2730 if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute]) 2731 return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()]; 2732 if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute]) 2733 return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()]; 2734 2735 // MathML Attributes. 2736 if (m_object->isMathElement()) { 2737 if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute]) 2738 return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0; 2739 if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute]) 2740 return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0; 2741 if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute]) 2742 return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0; 2743 if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute]) 2744 return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0; 2745 if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute]) 2746 return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0; 2747 if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute]) 2748 return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0; 2749 if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute]) 2750 return (m_object->mathSuperscriptObject()) ? m_object->mathSuperscriptObject()->wrapper() : 0; 2751 if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute]) 2752 return (m_object->mathUnderObject()) ? m_object->mathUnderObject()->wrapper() : 0; 2753 if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute]) 2754 return (m_object->mathOverObject()) ? m_object->mathOverObject()->wrapper() : 0; 2755 if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute]) 2756 return m_object->mathFencedOpenString(); 2757 if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute]) 2758 return m_object->mathFencedCloseString(); 2759 if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute]) 2760 return [NSNumber numberWithInteger:m_object->mathLineThickness()]; 2761 if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute]) 2762 return [self accessibilityMathPostscriptPairs]; 2763 if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute]) 2764 return [self accessibilityMathPrescriptPairs]; 2765 } 2766 2767 // this is used only by DumpRenderTree for testing 2768 if ([attributeName isEqualToString:@"AXClickPoint"]) 2769 return [NSValue valueWithPoint:m_object->clickPoint()]; 2770 2771 // This is used by DRT to verify CSS3 speech works. 2772 if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) { 2773 ESpeak speakProperty = m_object->speakProperty(); 2774 switch (speakProperty) { 2775 case SpeakNone: 2776 return @"none"; 2777 case SpeakSpellOut: 2778 return @"spell-out"; 2779 case SpeakDigits: 2780 return @"digits"; 2781 case SpeakLiteralPunctuation: 2782 return @"literal-punctuation"; 2783 case SpeakNoPunctuation: 2784 return @"no-punctuation"; 2785 default: 2786 case SpeakNormal: 2787 return @"normal"; 2788 } 2789 } 2790 2791 // Used by DRT to find an accessible node by its element id. 2792 if ([attributeName isEqualToString:@"AXDRTElementIdAttribute"]) 2793 return m_object->getAttribute(idAttr); 2794 2795 return nil; 2796} 2797 2798- (NSString *)accessibilityPlatformMathSubscriptKey 2799{ 2800 return NSAccessibilityMathSubscriptAttribute; 2801} 2802 2803- (NSString *)accessibilityPlatformMathSuperscriptKey 2804{ 2805 return NSAccessibilityMathSuperscriptAttribute; 2806} 2807 2808- (id)accessibilityFocusedUIElement 2809{ 2810 if (![self updateObjectBackingStore]) 2811 return nil; 2812 2813 RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement(); 2814 2815 if (!focusedObj) 2816 return nil; 2817 2818 return focusedObj->wrapper(); 2819} 2820 2821- (id)accessibilityHitTest:(NSPoint)point 2822{ 2823 if (![self updateObjectBackingStore]) 2824 return nil; 2825 2826 m_object->updateChildrenIfNecessary(); 2827 RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point)); 2828 if (axObject) 2829 return NSAccessibilityUnignoredAncestor(axObject->wrapper()); 2830 return NSAccessibilityUnignoredAncestor(self); 2831} 2832 2833- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName 2834{ 2835 if (![self updateObjectBackingStore]) 2836 return nil; 2837 2838 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) 2839 return YES; 2840 2841 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) 2842 return m_object->canSetFocusAttribute(); 2843 2844 if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) 2845 return m_object->canSetValueAttribute(); 2846 2847 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) 2848 return m_object->canSetSelectedAttribute(); 2849 2850 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) 2851 return m_object->canSetSelectedChildrenAttribute(); 2852 2853 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 2854 return m_object->canSetExpandedAttribute(); 2855 2856 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) 2857 return YES; 2858 2859 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] || 2860 [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] || 2861 [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) 2862 return m_object->canSetTextRangeAttributes(); 2863 2864 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 2865 return YES; 2866 2867 return NO; 2868} 2869 2870// accessibilityShouldUseUniqueId is an AppKit method we override so that 2871// objects will be given a unique ID, and therefore allow AppKit to know when they 2872// become obsolete (e.g. when the user navigates to a new web page, making this one 2873// unrendered but not deallocated because it is in the back/forward cache). 2874// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the 2875// appropriate place (e.g. dealloc) to remove these non-retained references from 2876// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement. 2877// 2878// Registering an object is also required for observing notifications. Only registered objects can be observed. 2879- (BOOL)accessibilityIsIgnored 2880{ 2881 if (![self updateObjectBackingStore]) 2882 return YES; 2883 2884 if (m_object->isAttachment()) 2885 return [[self attachmentView] accessibilityIsIgnored]; 2886 return m_object->accessibilityIsIgnored(); 2887} 2888 2889- (NSArray* )accessibilityParameterizedAttributeNames 2890{ 2891 if (![self updateObjectBackingStore]) 2892 return nil; 2893 2894 if (m_object->isAttachment()) 2895 return nil; 2896 2897 static NSArray* paramAttrs = nil; 2898 static NSArray* textParamAttrs = nil; 2899 static NSArray* tableParamAttrs = nil; 2900 static NSArray* webAreaParamAttrs = nil; 2901 if (paramAttrs == nil) { 2902 paramAttrs = [[NSArray alloc] initWithObjects: 2903 @"AXUIElementForTextMarker", 2904 @"AXTextMarkerRangeForUIElement", 2905 @"AXLineForTextMarker", 2906 @"AXTextMarkerRangeForLine", 2907 @"AXStringForTextMarkerRange", 2908 @"AXTextMarkerForPosition", 2909 @"AXBoundsForTextMarkerRange", 2910 @"AXAttributedStringForTextMarkerRange", 2911 @"AXTextMarkerRangeForUnorderedTextMarkers", 2912 @"AXNextTextMarkerForTextMarker", 2913 @"AXPreviousTextMarkerForTextMarker", 2914 @"AXLeftWordTextMarkerRangeForTextMarker", 2915 @"AXRightWordTextMarkerRangeForTextMarker", 2916 @"AXLeftLineTextMarkerRangeForTextMarker", 2917 @"AXRightLineTextMarkerRangeForTextMarker", 2918 @"AXSentenceTextMarkerRangeForTextMarker", 2919 @"AXParagraphTextMarkerRangeForTextMarker", 2920 @"AXNextWordEndTextMarkerForTextMarker", 2921 @"AXPreviousWordStartTextMarkerForTextMarker", 2922 @"AXNextLineEndTextMarkerForTextMarker", 2923 @"AXPreviousLineStartTextMarkerForTextMarker", 2924 @"AXNextSentenceEndTextMarkerForTextMarker", 2925 @"AXPreviousSentenceStartTextMarkerForTextMarker", 2926 @"AXNextParagraphEndTextMarkerForTextMarker", 2927 @"AXPreviousParagraphStartTextMarkerForTextMarker", 2928 @"AXStyleTextMarkerRangeForTextMarker", 2929 @"AXLengthForTextMarkerRange", 2930 NSAccessibilityBoundsForRangeParameterizedAttribute, 2931 NSAccessibilityStringForRangeParameterizedAttribute, 2932 NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute, 2933 NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute, 2934 NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute, 2935 nil]; 2936 } 2937 2938 if (textParamAttrs == nil) { 2939 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; 2940 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute]; 2941 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute]; 2942 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute]; 2943 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute]; 2944 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute]; 2945 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute]; 2946 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute]; 2947 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute]; 2948 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute]; 2949 textParamAttrs = [[NSArray alloc] initWithArray:tempArray]; 2950 [tempArray release]; 2951 } 2952 if (tableParamAttrs == nil) { 2953 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; 2954 [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute]; 2955 tableParamAttrs = [[NSArray alloc] initWithArray:tempArray]; 2956 [tempArray release]; 2957 } 2958 if (!webAreaParamAttrs) { 2959 NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; 2960 [tempArray addObject:NSAccessibilityTextMarkerForIndexParameterizedAttribute]; 2961 [tempArray addObject:NSAccessibilityTextMarkerIsValidParameterizedAttribute]; 2962 [tempArray addObject:NSAccessibilityIndexForTextMarkerParameterizedAttribute]; 2963 webAreaParamAttrs = [[NSArray alloc] initWithArray:tempArray]; 2964 [tempArray release]; 2965 } 2966 2967 if (m_object->isPasswordField()) 2968 return [NSArray array]; 2969 2970 if (!m_object->isAccessibilityRenderObject()) 2971 return paramAttrs; 2972 2973 if (m_object->isTextControl()) 2974 return textParamAttrs; 2975 2976 if (m_object->isAccessibilityTable()) 2977 return tableParamAttrs; 2978 2979 if (m_object->isMenuRelated()) 2980 return nil; 2981 2982 if (m_object->isWebArea()) 2983 return webAreaParamAttrs; 2984 2985 return paramAttrs; 2986} 2987 2988- (void)accessibilityPerformPressAction 2989{ 2990 if (![self updateObjectBackingStore]) 2991 return; 2992 2993 if (m_object->isAttachment()) 2994 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction]; 2995 else 2996 m_object->press(); 2997} 2998 2999- (void)accessibilityPerformIncrementAction 3000{ 3001 if (![self updateObjectBackingStore]) 3002 return; 3003 3004 if (m_object->isAttachment()) 3005 [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction]; 3006 else 3007 m_object->increment(); 3008} 3009 3010- (void)accessibilityPerformDecrementAction 3011{ 3012 if (![self updateObjectBackingStore]) 3013 return; 3014 3015 if (m_object->isAttachment()) 3016 [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction]; 3017 else 3018 m_object->decrement(); 3019} 3020 3021- (void)accessibilityPerformShowMenuAction 3022{ 3023 if (m_object->roleValue() == ComboBoxRole) 3024 m_object->setIsExpanded(true); 3025 else { 3026 // This needs to be performed in an iteration of the run loop that did not start from an AX call. 3027 // If it's the same run loop iteration, the menu open notification won't be sent 3028 [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0]; 3029 } 3030} 3031 3032- (void)accessibilityShowContextMenu 3033{ 3034 Page* page = m_object->page(); 3035 if (!page) 3036 return; 3037 3038 IntRect rect = pixelSnappedIntRect(m_object->elementRect()); 3039 FrameView* frameView = m_object->documentFrameView(); 3040 3041 // On WK2, we need to account for the scroll position. 3042 // On WK1, this isn't necessary, it's taken care of by the attachment views. 3043 if (frameView && !frameView->platformWidget()) { 3044 // Find the appropriate scroll view to use to convert the contents to the window. 3045 for (AccessibilityObject* parent = m_object->parentObject(); parent; parent = parent->parentObject()) { 3046 if (parent->isAccessibilityScrollView()) { 3047 ScrollView* scrollView = toAccessibilityScrollView(parent)->scrollView(); 3048 rect = scrollView->contentsToRootView(rect); 3049 break; 3050 } 3051 } 3052 } 3053 3054 page->contextMenuController()->showContextMenuAt(page->mainFrame(), rect.center()); 3055} 3056 3057- (void)accessibilityScrollToVisible 3058{ 3059 m_object->scrollToMakeVisible(); 3060} 3061 3062- (void)accessibilityPerformAction:(NSString*)action 3063{ 3064 if (![self updateObjectBackingStore]) 3065 return; 3066 3067 if ([action isEqualToString:NSAccessibilityPressAction]) 3068 [self accessibilityPerformPressAction]; 3069 3070 else if ([action isEqualToString:NSAccessibilityShowMenuAction]) 3071 [self accessibilityPerformShowMenuAction]; 3072 3073 else if ([action isEqualToString:NSAccessibilityIncrementAction]) 3074 [self accessibilityPerformIncrementAction]; 3075 3076 else if ([action isEqualToString:NSAccessibilityDecrementAction]) 3077 [self accessibilityPerformDecrementAction]; 3078 3079 else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction]) 3080 [self accessibilityScrollToVisible]; 3081} 3082 3083- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName 3084{ 3085 if (![self updateObjectBackingStore]) 3086 return; 3087 3088 id textMarkerRange = nil; 3089 NSNumber* number = nil; 3090 NSString* string = nil; 3091 NSRange range = {0, 0}; 3092 NSArray* array = nil; 3093 3094 // decode the parameter 3095 if (AXObjectIsTextMarkerRange(value)) 3096 textMarkerRange = value; 3097 3098 else if ([value isKindOfClass:[NSNumber self]]) 3099 number = value; 3100 3101 else if ([value isKindOfClass:[NSString self]]) 3102 string = value; 3103 3104 else if ([value isKindOfClass:[NSValue self]]) 3105 range = [value rangeValue]; 3106 3107 else if ([value isKindOfClass:[NSArray self]]) 3108 array = value; 3109 3110 // handle the command 3111 if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) { 3112 ASSERT(textMarkerRange); 3113 m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]); 3114 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) { 3115 ASSERT(number); 3116 3117 bool focus = [number boolValue]; 3118 3119 // If focus is just set without making the view the first responder, then keyboard focus won't move to the right place. 3120 if (focus && m_object->isWebArea() && !m_object->document()->frame()->selection()->isFocusedAndActive()) { 3121 FrameView* frameView = m_object->documentFrameView(); 3122 Page* page = m_object->page(); 3123 if (page && frameView) { 3124 ChromeClient* client = page->chrome().client(); 3125 client->focus(); 3126 if (frameView->platformWidget()) 3127 client->makeFirstResponder(frameView->platformWidget()); 3128 else 3129 client->makeFirstResponder(); 3130 } 3131 } 3132 3133 m_object->setFocused(focus); 3134 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { 3135 if (number && m_object->canSetNumericValue()) 3136 m_object->setValue([number floatValue]); 3137 else if (string) 3138 m_object->setValue(string); 3139 } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) { 3140 if (!number) 3141 return; 3142 m_object->setSelected([number boolValue]); 3143 } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { 3144 if (!array || m_object->roleValue() != ListBoxRole) 3145 return; 3146 AccessibilityObject::AccessibilityChildrenVector selectedChildren; 3147 convertToVector(array, selectedChildren); 3148 static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren); 3149 } else if (m_object->isTextControl()) { 3150 if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { 3151 m_object->setSelectedText(string); 3152 } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { 3153 m_object->setSelectedTextRange(PlainTextRange(range.location, range.length)); 3154 } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) { 3155 m_object->makeRangeVisible(PlainTextRange(range.location, range.length)); 3156 } 3157 } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]) 3158 m_object->setIsExpanded([number boolValue]); 3159 else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) { 3160 AccessibilityObject::AccessibilityChildrenVector selectedRows; 3161 convertToVector(array, selectedRows); 3162 if (m_object->isTree() || m_object->isAccessibilityTable()) 3163 m_object->setSelectedRows(selectedRows); 3164 } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute]) 3165 m_object->setARIAGrabbed([number boolValue]); 3166} 3167 3168static RenderObject* rendererForView(NSView* view) 3169{ 3170 if (![view conformsToProtocol:@protocol(WebCoreFrameView)]) 3171 return 0; 3172 3173 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view; 3174 Frame* frame = [frameView _web_frame]; 3175 if (!frame) 3176 return 0; 3177 3178 Node* node = frame->document()->ownerElement(); 3179 if (!node) 3180 return 0; 3181 3182 return node->renderer(); 3183} 3184 3185- (id)_accessibilityParentForSubview:(NSView*)subview 3186{ 3187 RenderObject* renderer = rendererForView(subview); 3188 if (!renderer) 3189 return nil; 3190 3191 AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer); 3192 if (obj) 3193 return obj->parentObjectUnignored()->wrapper(); 3194 return nil; 3195} 3196 3197- (NSString*)accessibilityActionDescription:(NSString*)action 3198{ 3199 // we have no custom actions 3200 return NSAccessibilityActionDescription(action); 3201} 3202 3203// The CFAttributedStringType representation of the text associated with this accessibility 3204// object that is specified by the given range. 3205- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range 3206{ 3207 PlainTextRange textRange = PlainTextRange(range.location, range.length); 3208 VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange); 3209 return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]]; 3210} 3211 3212- (NSRange)_convertToNSRange:(Range*)range 3213{ 3214 NSRange result = NSMakeRange(NSNotFound, 0); 3215 if (!range || !range->startContainer()) 3216 return result; 3217 3218 Document* document = m_object->document(); 3219 if (!document) 3220 return result; 3221 3222 size_t location; 3223 size_t length; 3224 TextIterator::getLocationAndLengthFromRange(document->documentElement(), range, location, length); 3225 result.location = location; 3226 result.length = length; 3227 3228 return result; 3229} 3230 3231- (NSInteger)_indexForTextMarker:(id)marker 3232{ 3233 if (!marker) 3234 return NSNotFound; 3235 3236 VisibleSelection selection([self visiblePositionForTextMarker:marker]); 3237 return [self _convertToNSRange:selection.toNormalizedRange().get()].location; 3238} 3239 3240- (id)_textMarkerForIndex:(NSInteger)textIndex 3241{ 3242 Document* document = m_object->document(); 3243 if (!document) 3244 return nil; 3245 3246 PassRefPtr<Range> textRange = TextIterator::rangeFromLocationAndLength(document->documentElement(), textIndex, 0); 3247 if (!textRange || !textRange->boundaryPointsValid()) 3248 return nil; 3249 3250 VisiblePosition position(textRange->startPosition()); 3251 return [self textMarkerForVisiblePosition:position]; 3252} 3253 3254// The RTF representation of the text associated with this accessibility object that is 3255// specified by the given range. 3256- (NSData*)doAXRTFForRange:(NSRange)range 3257{ 3258 NSAttributedString* attrString = [self doAXAttributedStringForRange:range]; 3259 return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil]; 3260} 3261 3262- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter 3263{ 3264 id textMarker = nil; 3265 id textMarkerRange = nil; 3266 NSNumber* number = nil; 3267 NSArray* array = nil; 3268 NSDictionary* dictionary = nil; 3269 RefPtr<AccessibilityObject> uiElement = 0; 3270 NSPoint point = NSZeroPoint; 3271 bool pointSet = false; 3272 NSRange range = {0, 0}; 3273 bool rangeSet = false; 3274 NSRect rect = NSZeroRect; 3275 bool rectSet = false; 3276 3277 // basic parameter validation 3278 if (!m_object || !attribute || !parameter) 3279 return nil; 3280 3281 if (![self updateObjectBackingStore]) 3282 return nil; 3283 3284 // common parameter type check/casting. Nil checks in handlers catch wrong type case. 3285 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from 3286 // a parameter of the wrong type. 3287 if (AXObjectIsTextMarker(parameter)) 3288 textMarker = parameter; 3289 3290 else if (AXObjectIsTextMarkerRange(parameter)) 3291 textMarkerRange = parameter; 3292 3293 else if ([parameter isKindOfClass:[WebAccessibilityObjectWrapper self]]) 3294 uiElement = [(WebAccessibilityObjectWrapper*)parameter accessibilityObject]; 3295 3296 else if ([parameter isKindOfClass:[NSNumber self]]) 3297 number = parameter; 3298 3299 else if ([parameter isKindOfClass:[NSArray self]]) 3300 array = parameter; 3301 3302 else if ([parameter isKindOfClass:[NSDictionary self]]) 3303 dictionary = parameter; 3304 3305 else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) { 3306 pointSet = true; 3307 point = [(NSValue*)parameter pointValue]; 3308 3309 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) { 3310 rangeSet = true; 3311 range = [(NSValue*)parameter rangeValue]; 3312 } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRect)) == 0) { 3313 rectSet = true; 3314 rect = [(NSValue*)parameter rectValue]; 3315 } else { 3316 // Attribute type is not supported. Allow super to handle. 3317 return [super accessibilityAttributeValue:attribute forParameter:parameter]; 3318 } 3319 3320 // dispatch 3321 if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute]) { 3322 AccessibilityObject* startObject = 0; 3323 if ([[dictionary objectForKey:@"AXStartElement"] isKindOfClass:[WebAccessibilityObjectWrapper self]]) 3324 startObject = [(WebAccessibilityObjectWrapper*)[dictionary objectForKey:@"AXStartElement"] accessibilityObject]; 3325 3326 AccessibilitySearchDirection searchDirection = SearchDirectionNext; 3327 if ([[dictionary objectForKey:@"AXDirection"] isKindOfClass:[NSString self]]) 3328 searchDirection = ([(NSString*)[dictionary objectForKey:@"AXDirection"] isEqualToString:@"AXDirectionNext"]) ? SearchDirectionNext : SearchDirectionPrevious; 3329 3330 String searchText; 3331 if ([[dictionary objectForKey:@"AXSearchText"] isKindOfClass:[NSString self]]) 3332 searchText = (CFStringRef)[dictionary objectForKey:@"AXSearchText"]; 3333 3334 unsigned resultsLimit = 0; 3335 if ([[dictionary objectForKey:@"AXResultsLimit"] isKindOfClass:[NSNumber self]]) 3336 resultsLimit = [(NSNumber*)[dictionary objectForKey:@"AXResultsLimit"] unsignedIntValue]; 3337 3338 BOOL visibleOnly = NO; 3339 if ([[dictionary objectForKey:@"AXVisibleOnly"] isKindOfClass:[NSNumber self]]) 3340 visibleOnly = [(NSNumber*)[dictionary objectForKey:@"AXVisibleOnly"] boolValue]; 3341 3342 AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startObject, searchDirection, &searchText, resultsLimit, visibleOnly); 3343 3344 id searchKeyEntry = [dictionary objectForKey:@"AXSearchKey"]; 3345 if ([searchKeyEntry isKindOfClass:[NSString class]]) 3346 criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKeyEntry)); 3347 else if ([searchKeyEntry isKindOfClass:[NSArray class]]) { 3348 size_t length = static_cast<size_t>([(NSArray *)searchKeyEntry count]); 3349 criteria.searchKeys.reserveInitialCapacity(length); 3350 for (size_t i = 0; i < length; ++i) { 3351 id searchKey = [(NSArray *)searchKeyEntry objectAtIndex:i]; 3352 if ([searchKey isKindOfClass:[NSString class]]) 3353 criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKey)); 3354 } 3355 } 3356 3357 AccessibilityObject::AccessibilityChildrenVector results; 3358 m_object->findMatchingObjects(&criteria, results); 3359 3360 return convertToNSArray(results); 3361 } 3362 3363 if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute]) { 3364 IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)]; 3365 return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, LastVisiblePositionForBounds)]; 3366 } 3367 if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute]) { 3368 IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)]; 3369 return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, FirstVisiblePositionForBounds)]; 3370 } 3371 3372 if ([attribute isEqualToString:NSAccessibilityTextMarkerIsValidParameterizedAttribute]) { 3373 VisiblePosition pos = [self visiblePositionForTextMarker:textMarker]; 3374 return [NSNumber numberWithBool:!pos.isNull()]; 3375 } 3376 if ([attribute isEqualToString:NSAccessibilityIndexForTextMarkerParameterizedAttribute]) { 3377 return [NSNumber numberWithInteger:[self _indexForTextMarker:textMarker]]; 3378 } 3379 if ([attribute isEqualToString:NSAccessibilityTextMarkerForIndexParameterizedAttribute]) { 3380 return [self _textMarkerForIndex:[number integerValue]]; 3381 } 3382 3383 if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) { 3384 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3385 AccessibilityObject* axObject = m_object->accessibilityObjectForPosition(visiblePos); 3386 if (!axObject) 3387 return nil; 3388 return axObject->wrapper(); 3389 } 3390 3391 if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) { 3392 VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange(); 3393 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3394 } 3395 3396 if ([attribute isEqualToString:@"AXLineForTextMarker"]) { 3397 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3398 return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)]; 3399 } 3400 3401 if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) { 3402 VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine([number intValue]); 3403 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3404 } 3405 3406 if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) { 3407 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 3408 return m_object->stringForVisiblePositionRange(visiblePosRange); 3409 } 3410 3411 if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) { 3412 IntPoint webCorePoint = IntPoint(point); 3413 return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil; 3414 } 3415 3416 if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) { 3417 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 3418 NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange); 3419 return [NSValue valueWithRect:rect]; 3420 } 3421 3422 if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) { 3423 VisiblePosition start = m_object->visiblePositionForIndex(range.location); 3424 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length); 3425 if (start.isNull() || end.isNull()) 3426 return nil; 3427 NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end)); 3428 return [NSValue valueWithRect:rect]; 3429 } 3430 3431 if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) { 3432 VisiblePosition start = m_object->visiblePositionForIndex(range.location); 3433 VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length); 3434 if (start.isNull() || end.isNull()) 3435 return nil; 3436 return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end)); 3437 } 3438 3439 if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"]) 3440 return [self doAXAttributedStringForTextMarkerRange:textMarkerRange]; 3441 3442 if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) { 3443 if ([array count] < 2) 3444 return nil; 3445 3446 id textMarker1 = [array objectAtIndex:0]; 3447 id textMarker2 = [array objectAtIndex:1]; 3448 if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2)) 3449 return nil; 3450 3451 VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:(textMarker1)]; 3452 VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:(textMarker2)]; 3453 VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2); 3454 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3455 } 3456 3457 if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) { 3458 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3459 return [self textMarkerForVisiblePosition:m_object->nextVisiblePosition(visiblePos)]; 3460 } 3461 3462 if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) { 3463 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3464 return [self textMarkerForVisiblePosition:m_object->previousVisiblePosition(visiblePos)]; 3465 } 3466 3467 if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) { 3468 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3469 VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos); 3470 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3471 } 3472 3473 if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) { 3474 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3475 VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos); 3476 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3477 } 3478 3479 if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) { 3480 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3481 VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos); 3482 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3483 } 3484 3485 if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"]) { 3486 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3487 VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos); 3488 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3489 } 3490 3491 if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) { 3492 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3493 VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos); 3494 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3495 } 3496 3497 if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) { 3498 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3499 VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos); 3500 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3501 } 3502 3503 if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) { 3504 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3505 return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)]; 3506 } 3507 3508 if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) { 3509 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3510 return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)]; 3511 } 3512 3513 if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) { 3514 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3515 return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)]; 3516 } 3517 3518 if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) { 3519 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3520 return [self textMarkerForVisiblePosition:m_object->previousLineStartPosition(visiblePos)]; 3521 } 3522 3523 if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) { 3524 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3525 return [self textMarkerForVisiblePosition:m_object->nextSentenceEndPosition(visiblePos)]; 3526 } 3527 3528 if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) { 3529 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3530 return [self textMarkerForVisiblePosition:m_object->previousSentenceStartPosition(visiblePos)]; 3531 } 3532 3533 if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) { 3534 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3535 return [self textMarkerForVisiblePosition:m_object->nextParagraphEndPosition(visiblePos)]; 3536 } 3537 3538 if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) { 3539 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3540 return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)]; 3541 } 3542 3543 if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) { 3544 VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)]; 3545 VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos); 3546 return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end]; 3547 } 3548 3549 if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) { 3550 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 3551 int length = m_object->lengthForVisiblePositionRange(visiblePosRange); 3552 if (length < 0) 3553 return nil; 3554 return [NSNumber numberWithInt:length]; 3555 } 3556 3557 // Used only by DumpRenderTree (so far). 3558 if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) { 3559 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 3560 return [self textMarkerForVisiblePosition:visiblePosRange.start]; 3561 } 3562 3563 if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) { 3564 VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; 3565 return [self textMarkerForVisiblePosition:visiblePosRange.end]; 3566 } 3567 3568 if (m_object->isAccessibilityTable()) { 3569 if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) { 3570 if (array == nil || [array count] != 2) 3571 return nil; 3572 AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]); 3573 if (!cell) 3574 return nil; 3575 3576 return cell->wrapper(); 3577 } 3578 } 3579 3580 if (m_object->isTextControl()) { 3581 if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) { 3582 int lineNumber = m_object->doAXLineForIndex([number intValue]); 3583 if (lineNumber < 0) 3584 return nil; 3585 return [NSNumber numberWithUnsignedInt:lineNumber]; 3586 } 3587 3588 if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) { 3589 PlainTextRange textRange = m_object->doAXRangeForLine([number intValue]); 3590 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 3591 } 3592 3593 if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) { 3594 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length); 3595 return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil; 3596 } 3597 3598 if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) { 3599 if (!pointSet) 3600 return nil; 3601 IntPoint webCorePoint = IntPoint(point); 3602 PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint); 3603 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 3604 } 3605 3606 if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) { 3607 PlainTextRange textRange = m_object->doAXRangeForIndex([number intValue]); 3608 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 3609 } 3610 3611 if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) { 3612 if (!rangeSet) 3613 return nil; 3614 PlainTextRange plainTextRange = PlainTextRange(range.location, range.length); 3615 NSRect rect = m_object->doAXBoundsForRange(plainTextRange); 3616 return [NSValue valueWithRect:rect]; 3617 } 3618 3619 if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute]) 3620 return rangeSet ? [self doAXRTFForRange:range] : nil; 3621 3622 if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute]) 3623 return rangeSet ? [self doAXAttributedStringForRange:range] : nil; 3624 3625 if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) { 3626 PlainTextRange textRange = m_object->doAXStyleRangeForIndex([number intValue]); 3627 return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; 3628 } 3629 } 3630 3631 // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes. 3632 // In that case it must be passed to super. 3633 return [super accessibilityAttributeValue:attribute forParameter:parameter]; 3634} 3635 3636- (BOOL)accessibilitySupportsOverriddenAttributes 3637{ 3638 return YES; 3639} 3640 3641- (BOOL)accessibilityShouldUseUniqueId 3642{ 3643 // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up. 3644 return YES; 3645} 3646 3647// API that AppKit uses for faster access 3648- (NSUInteger)accessibilityIndexOfChild:(id)child 3649{ 3650 if (![self updateObjectBackingStore]) 3651 return NSNotFound; 3652 3653 // Tree objects return their rows as their children. We can use the original method 3654 // here, because we won't gain any speed up. 3655 if (m_object->isTree()) 3656 return [super accessibilityIndexOfChild:child]; 3657 3658 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 3659 3660 if (children.isEmpty()) 3661 return [[self renderWidgetChildren] indexOfObject:child]; 3662 3663 unsigned count = children.size(); 3664 for (unsigned k = 0; k < count; ++k) { 3665 WebAccessibilityObjectWrapper* wrapper = children[k]->wrapper(); 3666 if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child)) 3667 return k; 3668 } 3669 3670 return NSNotFound; 3671} 3672 3673- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute 3674{ 3675 if (![self updateObjectBackingStore]) 3676 return 0; 3677 3678 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 3679 // Tree items object returns a different set of children than those that are in children() 3680 // because an AXOutline (the mac role is becomes) has some odd stipulations. 3681 if (m_object->isTree() || m_object->isTreeItem()) 3682 return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count]; 3683 3684 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 3685 if (children.isEmpty()) 3686 return [[self renderWidgetChildren] count]; 3687 3688 return children.size(); 3689 } 3690 3691 return [super accessibilityArrayAttributeCount:attribute]; 3692} 3693 3694- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount 3695{ 3696 if (![self updateObjectBackingStore]) 3697 return nil; 3698 3699 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { 3700 if (m_object->children().isEmpty()) { 3701 NSArray *children = [self renderWidgetChildren]; 3702 if (!children) 3703 return nil; 3704 3705 NSUInteger childCount = [children count]; 3706 if (index >= childCount) 3707 return nil; 3708 3709 NSUInteger arrayLength = min(childCount - index, maxCount); 3710 return [children subarrayWithRange:NSMakeRange(index, arrayLength)]; 3711 } else if (m_object->isTree()) { 3712 // Tree objects return their rows as their children. We can use the original method in this case. 3713 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; 3714 } 3715 3716 const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); 3717 unsigned childCount = children.size(); 3718 if (index >= childCount) 3719 return nil; 3720 3721 unsigned available = min(childCount - index, maxCount); 3722 3723 NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available]; 3724 for (unsigned added = 0; added < available; ++index, ++added) { 3725 WebAccessibilityObjectWrapper* wrapper = children[index]->wrapper(); 3726 if (wrapper) { 3727 // The attachment view should be returned, otherwise AX palindrome errors occur. 3728 if (children[index]->isAttachment() && [wrapper attachmentView]) 3729 [subarray addObject:[wrapper attachmentView]]; 3730 else 3731 [subarray addObject:wrapper]; 3732 } 3733 } 3734 3735 return subarray; 3736 } 3737 3738 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; 3739} 3740 3741@end 3742 3743#endif // HAVE(ACCESSIBILITY) 3744