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