Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008, 2009, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008, 2009, 2011 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 #include "config.h" | 29 #include "config.h" |
| 30 #include "modules/accessibility/AXObject.h" | 30 #include "modules/accessibility/AXObject.h" |
| 31 #include "core/dom/NodeTraversal.h" | 31 |
| 32 #include "core/dom/LayoutTreeBuilderTraversal.h" | |
| 32 #include "core/editing/VisibleUnits.h" | 33 #include "core/editing/VisibleUnits.h" |
| 33 #include "core/editing/htmlediting.h" | 34 #include "core/editing/htmlediting.h" |
| 34 #include "core/frame/LocalFrame.h" | 35 #include "core/frame/LocalFrame.h" |
| 35 #include "core/frame/Settings.h" | 36 #include "core/frame/Settings.h" |
| 37 #include "core/html/HTMLDialogElement.h" | |
| 38 #include "core/html/HTMLFrameOwnerElement.h" | |
| 36 #include "core/layout/LayoutListItem.h" | 39 #include "core/layout/LayoutListItem.h" |
| 37 #include "core/layout/LayoutTheme.h" | 40 #include "core/layout/LayoutTheme.h" |
| 38 #include "core/layout/LayoutView.h" | 41 #include "core/layout/LayoutView.h" |
| 39 #include "modules/accessibility/AXObjectCacheImpl.h" | 42 #include "modules/accessibility/AXObjectCacheImpl.h" |
| 43 #include "modules/accessibility/InspectorTypeBuilderHelper.h" | |
| 40 #include "platform/UserGestureIndicator.h" | 44 #include "platform/UserGestureIndicator.h" |
| 41 #include "platform/text/PlatformLocale.h" | 45 #include "platform/text/PlatformLocale.h" |
| 42 #include "wtf/HashSet.h" | 46 #include "wtf/HashSet.h" |
| 43 #include "wtf/StdLibExtras.h" | 47 #include "wtf/StdLibExtras.h" |
| 44 #include "wtf/text/WTFString.h" | 48 #include "wtf/text/WTFString.h" |
| 45 | 49 |
| 46 using blink::WebLocalizedString; | 50 using blink::WebLocalizedString; |
| 47 | 51 |
| 48 namespace blink { | 52 namespace blink { |
| 49 | 53 |
| 50 using namespace HTMLNames; | 54 using namespace HTMLNames; |
| 51 | 55 |
| 56 using TypeBuilder::Accessibility::AXIgnoredReasons; | |
| 57 using TypeBuilder::Accessibility::AXNode; | |
| 58 using TypeBuilder::Accessibility::AXProperty; | |
| 59 using TypeBuilder::Accessibility::AXRelatedNode; | |
| 60 using TypeBuilder::Accessibility::AXValue; | |
| 61 using TypeBuilder::Accessibility::AXValueType; | |
| 62 | |
| 52 namespace { | 63 namespace { |
| 53 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; | 64 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; |
| 54 typedef HashSet<String, CaseFoldingHash> ARIAWidgetSet; | 65 typedef HashSet<String, CaseFoldingHash> ARIAWidgetSet; |
| 55 | 66 |
| 56 struct RoleEntry { | 67 struct RoleEntry { |
| 57 const char* ariaRole; | 68 const char* ariaRole; |
| 58 AccessibilityRole webcoreRole; | 69 AccessibilityRole webcoreRole; |
| 59 }; | 70 }; |
| 60 | 71 |
| 61 const RoleEntry roles[] = { | 72 const RoleEntry roles[] = { |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 "aria-controls", | 362 "aria-controls", |
| 352 "aria-disabled", // If it's disabled, it can be made interactive. | 363 "aria-disabled", // If it's disabled, it can be made interactive. |
| 353 "aria-expanded", | 364 "aria-expanded", |
| 354 "aria-haspopup", | 365 "aria-haspopup", |
| 355 "aria-multiselectable", | 366 "aria-multiselectable", |
| 356 "aria-pressed", | 367 "aria-pressed", |
| 357 "aria-required", | 368 "aria-required", |
| 358 "aria-selected" | 369 "aria-selected" |
| 359 }; | 370 }; |
| 360 | 371 |
| 372 | |
| 373 HTMLDialogElement* getActiveDialogElement(Node* node) | |
| 374 { | |
| 375 HTMLDialogElement* dialog = node->document().activeModalDialog(); | |
| 376 if (dialog && node != node->document() && !LayoutTreeBuilderTraversal::conta ins(*dialog, *node)) | |
| 377 return dialog; | |
| 378 if (node->document().ownerElement()) | |
| 379 return getActiveDialogElement(node->document().ownerElement()); | |
| 380 return 0; | |
| 381 } | |
| 382 | |
| 361 } // namespace | 383 } // namespace |
| 362 | 384 |
| 363 AXObject::AXObject(AXObjectCacheImpl* axObjectCache) | 385 AXObject::AXObject(AXObjectCacheImpl* axObjectCache) |
| 364 : m_id(0) | 386 : m_id(0) |
| 365 , m_haveChildren(false) | 387 , m_haveChildren(false) |
| 366 , m_role(UnknownRole) | 388 , m_role(UnknownRole) |
| 367 , m_lastKnownIsIgnoredValue(DefaultBehavior) | 389 , m_lastKnownIsIgnoredValue(DefaultBehavior) |
| 368 , m_detached(false) | 390 , m_detached(false) |
| 369 , m_parent(0) | 391 , m_parent(0) |
| 370 , m_lastModificationCount(-1) | 392 , m_lastModificationCount(-1) |
| 371 , m_cachedIsIgnored(false) | 393 , m_cachedIsIgnored(false) |
| 372 , m_cachedIsInertOrAriaHidden(false) | 394 , m_cachedIsInertOrAriaHidden(false) |
| 373 , m_cachedIsDescendantOfBarrenParent(false) | 395 , m_cachedIsDescendantOfLeafNode(false) |
| 374 , m_cachedIsDescendantOfDisabledNode(false) | 396 , m_cachedIsDescendantOfDisabledNode(false) |
| 375 , m_cachedHasInheritedPresentationalRole(false) | 397 , m_cachedHasInheritedPresentationalRole(false) |
| 376 , m_cachedLiveRegionRoot(0) | 398 , m_cachedLiveRegionRoot(0) |
| 377 , m_axObjectCache(axObjectCache) | 399 , m_axObjectCache(axObjectCache) |
| 378 { | 400 { |
| 379 } | 401 } |
| 380 | 402 |
| 381 AXObject::~AXObject() | 403 AXObject::~AXObject() |
| 382 { | 404 { |
| 383 ASSERT(isDetached()); | 405 ASSERT(isDetached()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 { | 520 { |
| 499 AXObjectCacheImpl* cache = axObjectCache(); | 521 AXObjectCacheImpl* cache = axObjectCache(); |
| 500 if (!cache) | 522 if (!cache) |
| 501 return; | 523 return; |
| 502 | 524 |
| 503 if (cache->modificationCount() == m_lastModificationCount) | 525 if (cache->modificationCount() == m_lastModificationCount) |
| 504 return; | 526 return; |
| 505 | 527 |
| 506 m_lastModificationCount = cache->modificationCount(); | 528 m_lastModificationCount = cache->modificationCount(); |
| 507 m_cachedIsInertOrAriaHidden = computeIsInertOrAriaHidden(); | 529 m_cachedIsInertOrAriaHidden = computeIsInertOrAriaHidden(); |
| 508 m_cachedIsDescendantOfBarrenParent = computeIsDescendantOfBarrenParent(); | 530 m_cachedIsDescendantOfLeafNode = (leafNodeAncestor() != 0); |
| 509 m_cachedIsDescendantOfDisabledNode = computeIsDescendantOfDisabledNode(); | 531 m_cachedIsDescendantOfDisabledNode = (disabledAncestor() != 0); |
| 510 m_cachedHasInheritedPresentationalRole = computeHasInheritedPresentationalRo le(); | 532 m_cachedHasInheritedPresentationalRole = (inheritsPresentationalRoleFrom() ! = 0); |
| 511 m_cachedIsIgnored = computeAccessibilityIsIgnored(); | 533 m_cachedIsIgnored = computeAccessibilityIsIgnored(); |
| 512 m_cachedLiveRegionRoot = isLiveRegion() ? | 534 m_cachedLiveRegionRoot = isLiveRegion() ? |
| 513 this : | 535 this : |
| 514 (parentObjectIfExists() ? parentObjectIfExists()->liveRegionRoot() : 0); | 536 (parentObjectIfExists() ? parentObjectIfExists()->liveRegionRoot() : 0); |
| 515 } | 537 } |
| 516 | 538 |
| 517 bool AXObject::accessibilityIsIgnoredByDefault() const | 539 bool AXObject::accessibilityIsIgnoredByDefault(PassRefPtr<TypeBuilder::Array<Typ eBuilder::Accessibility::AXProperty>> passIgnoredReasons) const |
| 518 { | 540 { |
| 519 return defaultObjectInclusion() == IgnoreObject; | 541 return defaultObjectInclusion(passIgnoredReasons) == IgnoreObject; |
| 520 } | 542 } |
| 521 | 543 |
| 522 AXObjectInclusion AXObject::accessibilityPlatformIncludesObject() const | 544 AXObjectInclusion AXObject::accessibilityPlatformIncludesObject() const |
| 523 { | 545 { |
| 524 if (isMenuListPopup() || isMenuListOption()) | 546 if (isMenuListPopup() || isMenuListOption()) |
| 525 return IncludeObject; | 547 return IncludeObject; |
| 526 | 548 |
| 527 return DefaultBehavior; | 549 return DefaultBehavior; |
| 528 } | 550 } |
| 529 | 551 |
| 530 AXObjectInclusion AXObject::defaultObjectInclusion() const | 552 AXObjectInclusion AXObject::defaultObjectInclusion(PassRefPtr<TypeBuilder::Array <TypeBuilder::Accessibility::AXProperty>> passIgnoredReasons) const |
| 531 { | 553 { |
| 532 if (isInertOrAriaHidden()) | 554 RefPtr<TypeBuilder::Array<TypeBuilder::Accessibility::AXProperty>> ignoredRe asons = passIgnoredReasons; |
| 555 | |
| 556 if (isInertOrAriaHidden()) { | |
| 557 if (ignoredReasons) | |
| 558 computeIsInertOrAriaHidden(ignoredReasons); | |
| 533 return IgnoreObject; | 559 return IgnoreObject; |
| 560 } | |
| 534 | 561 |
| 535 if (isPresentationalChildOfAriaRole()) | 562 if (AXObject* ancestor = ancestorForWhichThisIsAPresentationalChild()) { |
| 563 if (ignoredReasons) | |
| 564 ignoredReasons->addItem(createProperty(AXIgnoredReasons::AncestorDis allowsChild, createRelatedNodeValue(ancestor))); | |
| 536 return IgnoreObject; | 565 return IgnoreObject; |
| 566 } | |
| 537 | 567 |
| 538 return accessibilityPlatformIncludesObject(); | 568 return accessibilityPlatformIncludesObject(); |
| 539 } | 569 } |
| 540 | 570 |
| 541 bool AXObject::isInertOrAriaHidden() const | 571 bool AXObject::isInertOrAriaHidden() const |
| 542 { | 572 { |
| 543 updateCachedAttributeValuesIfNeeded(); | 573 updateCachedAttributeValuesIfNeeded(); |
| 544 return m_cachedIsInertOrAriaHidden; | 574 return m_cachedIsInertOrAriaHidden; |
| 545 } | 575 } |
| 546 | 576 |
| 547 bool AXObject::computeIsInertOrAriaHidden() const | 577 bool AXObject::computeIsInertOrAriaHidden(PassRefPtr<TypeBuilder::Array<TypeBuil der::Accessibility::AXProperty>> passIgnoredReasons) const |
| 548 { | 578 { |
| 579 RefPtr<TypeBuilder::Array<TypeBuilder::Accessibility::AXProperty>> ignoredRe asons = passIgnoredReasons; | |
| 580 | |
| 549 if (node()) { | 581 if (node()) { |
| 550 if (node()->isInert()) | 582 if (node()->isInert()) { |
| 583 if (ignoredReasons) { | |
| 584 HTMLDialogElement* dialog = getActiveDialogElement(node()); | |
| 585 if (dialog) { | |
| 586 AXObject* dialogObject = axObjectCache()->getOrCreate(dialog ); | |
| 587 if (dialogObject) | |
| 588 ignoredReasons->addItem(createProperty(AXIgnoredReasons: :ActiveModalDialog, createRelatedNodeValue(dialogObject))); | |
| 589 } | |
|
dmazzoni
2015/04/15 17:00:02
Handle the else case?
In the future there may be
aboxhall
2015/04/15 17:55:46
But it'll be due to an inert attribute somewhere,
| |
| 590 } | |
| 551 return true; | 591 return true; |
| 592 } | |
| 552 } else { | 593 } else { |
| 553 AXObject* parent = parentObject(); | 594 AXObject* parent = parentObject(); |
| 554 if (parent && parent->isInertOrAriaHidden()) | 595 if (parent && parent->isInertOrAriaHidden()) { |
| 596 if (ignoredReasons) | |
| 597 parent->computeIsInertOrAriaHidden(ignoredReasons); | |
| 555 return true; | 598 return true; |
| 599 } | |
| 556 } | 600 } |
| 557 | 601 |
| 558 return ariaHiddenRoot() != 0; | 602 const AXObject* hiddenRoot = ariaHiddenRoot(); |
| 559 } | 603 if (hiddenRoot) { |
| 560 | 604 if (ignoredReasons) { |
| 561 bool AXObject::isDescendantOfBarrenParent() const | 605 if (hiddenRoot == this) |
| 562 { | 606 ignoredReasons->addItem(createProperty(AXIgnoredReasons::AriaHid den, createBooleanValue(true))); |
| 563 updateCachedAttributeValuesIfNeeded(); | 607 else |
| 564 return m_cachedIsDescendantOfBarrenParent; | 608 ignoredReasons->addItem(createProperty(AXIgnoredReasons::AriaHid denRoot, createRelatedNodeValue(hiddenRoot))); |
| 565 } | 609 } |
| 566 | 610 return true; |
| 567 bool AXObject::computeIsDescendantOfBarrenParent() const | |
| 568 { | |
| 569 if (AXObject* parent = parentObject()) { | |
| 570 if (!parent->canHaveChildren()) | |
| 571 return true; | |
| 572 | |
| 573 return parent->isDescendantOfBarrenParent(); | |
| 574 } | 611 } |
| 575 | 612 |
| 576 return false; | 613 return false; |
| 577 } | 614 } |
| 578 | 615 |
| 616 bool AXObject::isDescendantOfLeafNode() const | |
| 617 { | |
| 618 updateCachedAttributeValuesIfNeeded(); | |
| 619 return m_cachedIsDescendantOfLeafNode; | |
| 620 } | |
| 621 | |
| 622 AXObject* AXObject::leafNodeAncestor() const | |
| 623 { | |
| 624 if (AXObject* parent = parentObject()) { | |
| 625 if (!parent->canHaveChildren()) | |
| 626 return parent; | |
| 627 | |
| 628 return parent->leafNodeAncestor(); | |
| 629 } | |
| 630 | |
| 631 return 0; | |
| 632 } | |
| 633 | |
| 579 const AXObject* AXObject::ariaHiddenRoot() const | 634 const AXObject* AXObject::ariaHiddenRoot() const |
| 580 { | 635 { |
| 581 for (const AXObject* object = this; object; object = object->parentObject()) { | 636 for (const AXObject* object = this; object; object = object->parentObject()) { |
| 582 if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true")) | 637 if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true")) |
| 583 return object; | 638 return object; |
| 584 } | 639 } |
| 585 | 640 |
| 586 return 0; | 641 return 0; |
| 587 } | 642 } |
| 588 | 643 |
| 589 bool AXObject::isDescendantOfDisabledNode() const | 644 bool AXObject::isDescendantOfDisabledNode() const |
| 590 { | 645 { |
| 591 updateCachedAttributeValuesIfNeeded(); | 646 updateCachedAttributeValuesIfNeeded(); |
| 592 return m_cachedIsDescendantOfDisabledNode; | 647 return m_cachedIsDescendantOfDisabledNode; |
| 593 } | 648 } |
| 594 | 649 |
| 595 bool AXObject::computeIsDescendantOfDisabledNode() const | 650 const AXObject* AXObject::disabledAncestor() const |
| 596 { | 651 { |
| 597 const AtomicString& disabled = getAttribute(aria_disabledAttr); | 652 const AtomicString& disabled = getAttribute(aria_disabledAttr); |
| 598 if (equalIgnoringCase(disabled, "true")) | 653 if (equalIgnoringCase(disabled, "true")) |
| 599 return true; | 654 return this; |
| 600 if (equalIgnoringCase(disabled, "false")) | 655 if (equalIgnoringCase(disabled, "false")) |
| 601 return false; | 656 return 0; |
| 602 | 657 |
| 603 if (AXObject* parent = parentObject()) | 658 if (AXObject* parent = parentObject()) |
| 604 return parent->isDescendantOfDisabledNode(); | 659 return parent->disabledAncestor(); |
| 605 | 660 |
| 606 return false; | 661 return 0; |
| 607 } | 662 } |
| 608 | 663 |
| 609 bool AXObject::lastKnownIsIgnoredValue() | 664 bool AXObject::lastKnownIsIgnoredValue() |
| 610 { | 665 { |
| 611 if (m_lastKnownIsIgnoredValue == DefaultBehavior) | 666 if (m_lastKnownIsIgnoredValue == DefaultBehavior) |
| 612 m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : In cludeObject; | 667 m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : In cludeObject; |
| 613 | 668 |
| 614 return m_lastKnownIsIgnoredValue == IgnoreObject; | 669 return m_lastKnownIsIgnoredValue == IgnoreObject; |
| 615 } | 670 } |
| 616 | 671 |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1299 } | 1354 } |
| 1300 | 1355 |
| 1301 const AtomicString& AXObject::internalRoleName(AccessibilityRole role) | 1356 const AtomicString& AXObject::internalRoleName(AccessibilityRole role) |
| 1302 { | 1357 { |
| 1303 static const Vector<AtomicString>* internalRoleNameVector = createInternalRo leNameVector(); | 1358 static const Vector<AtomicString>* internalRoleNameVector = createInternalRo leNameVector(); |
| 1304 | 1359 |
| 1305 return internalRoleNameVector->at(role); | 1360 return internalRoleNameVector->at(role); |
| 1306 } | 1361 } |
| 1307 | 1362 |
| 1308 } // namespace blink | 1363 } // namespace blink |
| OLD | NEW |