| 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 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 updateCachedAttributeValuesIfNeeded(); | 669 updateCachedAttributeValuesIfNeeded(); |
| 670 return m_cachedHasInheritedPresentationalRole; | 670 return m_cachedHasInheritedPresentationalRole; |
| 671 } | 671 } |
| 672 | 672 |
| 673 bool AXObject::isPresentationalChild() const | 673 bool AXObject::isPresentationalChild() const |
| 674 { | 674 { |
| 675 updateCachedAttributeValuesIfNeeded(); | 675 updateCachedAttributeValuesIfNeeded(); |
| 676 return m_cachedIsPresentationalChild; | 676 return m_cachedIsPresentationalChild; |
| 677 } | 677 } |
| 678 | 678 |
| 679 String AXObject::computedName() const |
| 680 { |
| 681 AXNameFrom nameFrom; |
| 682 AXObject::AXObjectVector nameObjects; |
| 683 return name(nameFrom, &nameObjects); |
| 684 } |
| 685 |
| 679 String AXObject::name(AXNameFrom& nameFrom, AXObject::AXObjectVector* nameObject
s) const | 686 String AXObject::name(AXNameFrom& nameFrom, AXObject::AXObjectVector* nameObject
s) const |
| 680 { | 687 { |
| 681 HeapHashSet<Member<const AXObject>> visited; | 688 HeapHashSet<Member<const AXObject>> visited; |
| 682 AXRelatedObjectVector relatedObjects; | 689 AXRelatedObjectVector relatedObjects; |
| 683 String text = textAlternative(false, false, visited, nameFrom, &relatedObjec
ts, nullptr); | 690 String text = textAlternative(false, false, visited, nameFrom, &relatedObjec
ts, nullptr); |
| 684 | 691 |
| 685 if (!node() || !isHTMLBRElement(node())) | 692 if (!node() || !isHTMLBRElement(node())) |
| 686 text = text.simplifyWhiteSpace(isHTMLSpace<UChar>); | 693 text = text.simplifyWhiteSpace(isHTMLSpace<UChar>, WTF::DoNotStripWhiteS
pace); |
| 687 | 694 |
| 688 if (nameObjects) { | 695 if (nameObjects) { |
| 689 nameObjects->clear(); | 696 nameObjects->clear(); |
| 690 for (size_t i = 0; i < relatedObjects.size(); i++) | 697 for (size_t i = 0; i < relatedObjects.size(); i++) |
| 691 nameObjects->append(relatedObjects[i]->object); | 698 nameObjects->append(relatedObjects[i]->object); |
| 692 } | 699 } |
| 693 return text; | 700 return text; |
| 694 } | 701 } |
| 695 | 702 |
| 696 String AXObject::name(NameSources* nameSources) const | 703 String AXObject::name(NameSources* nameSources) const |
| 697 { | 704 { |
| 698 AXObjectSet visited; | 705 AXObjectSet visited; |
| 699 AXNameFrom tmpNameFrom; | 706 AXNameFrom tmpNameFrom; |
| 700 AXRelatedObjectVector tmpRelatedObjects; | 707 AXRelatedObjectVector tmpRelatedObjects; |
| 701 String text = textAlternative(false, false, visited, tmpNameFrom, &tmpRelate
dObjects, nameSources); | 708 String text = textAlternative(false, false, visited, tmpNameFrom, &tmpRelate
dObjects, nameSources); |
| 702 text = text.simplifyWhiteSpace(isHTMLSpace<UChar>); | 709 text = text.simplifyWhiteSpace(isHTMLSpace<UChar>); |
| 703 return text; | 710 return text; |
| 704 } | 711 } |
| 705 | 712 |
| 706 String AXObject::recursiveTextAlternative(const AXObject& axObj, bool inAriaLabe
lledByTraversal, AXObjectSet& visited) | 713 String AXObject::recursiveTextAlternative(const AXObject& axObj, bool inAriaLabe
lledByTraversal, AXObjectSet& visited) |
| 707 { | 714 { |
| 708 AXNameFrom tmpNameFrom; | 715 AXNameFrom tmpNameFrom; |
| 709 return axObj.textAlternative(true, inAriaLabelledByTraversal, visited, tmpNa
meFrom, nullptr, nullptr); | 716 return axObj.textAlternative(true, inAriaLabelledByTraversal, visited, tmpNa
meFrom, nullptr, nullptr); |
| 710 } | 717 } |
| 711 | 718 |
| 719 String AXObject::ariaTextAlternative(bool recursive, bool inAriaLabelledByTraver
sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXRelatedObjectVector* relatedO
bjects, NameSources* nameSources, bool* foundTextAlternative) const |
| 720 { |
| 721 String textAlternative; |
| 722 bool alreadyVisited = visited.contains(this); |
| 723 visited.add(this); |
| 724 |
| 725 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 |
| 726 if (!recursive && layoutObject() |
| 727 && layoutObject()->style()->visibility() != VISIBLE |
| 728 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { |
| 729 return String(); |
| 730 } |
| 731 |
| 732 // Step 2B from: http://www.w3.org/TR/accname-aam-1.1 |
| 733 if (!inAriaLabelledByTraversal && !alreadyVisited) { |
| 734 const QualifiedName& attr = hasAttribute(aria_labeledbyAttr) && !hasAttr
ibute(aria_labelledbyAttr) ? aria_labeledbyAttr : aria_labelledbyAttr; |
| 735 nameFrom = AXNameFromRelatedElement; |
| 736 if (nameSources) { |
| 737 nameSources->append(NameSource(*foundTextAlternative, attr)); |
| 738 nameSources->last().type = nameFrom; |
| 739 } |
| 740 |
| 741 const AtomicString& ariaLabelledby = getAttribute(attr); |
| 742 if (!ariaLabelledby.isNull()) { |
| 743 if (nameSources) |
| 744 nameSources->last().attributeValue = ariaLabelledby; |
| 745 |
| 746 textAlternative = textFromAriaLabelledby(visited, relatedObjects); |
| 747 |
| 748 if (!textAlternative.isNull()) { |
| 749 if (nameSources) { |
| 750 NameSource& source = nameSources->last(); |
| 751 source.type = nameFrom; |
| 752 source.relatedObjects = *relatedObjects; |
| 753 source.text = textAlternative; |
| 754 *foundTextAlternative = true; |
| 755 } else { |
| 756 *foundTextAlternative = true; |
| 757 return textAlternative; |
| 758 } |
| 759 } else if (nameSources) { |
| 760 nameSources->last().invalid = true; |
| 761 } |
| 762 } |
| 763 } |
| 764 |
| 765 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 |
| 766 nameFrom = AXNameFromAttribute; |
| 767 if (nameSources) { |
| 768 nameSources->append(NameSource(*foundTextAlternative, aria_labelAttr)); |
| 769 nameSources->last().type = nameFrom; |
| 770 } |
| 771 const AtomicString& ariaLabel = getAttribute(aria_labelAttr); |
| 772 if (!ariaLabel.isEmpty()) { |
| 773 textAlternative = ariaLabel; |
| 774 |
| 775 if (nameSources) { |
| 776 NameSource& source = nameSources->last(); |
| 777 source.text = textAlternative; |
| 778 source.attributeValue = ariaLabel; |
| 779 *foundTextAlternative = true; |
| 780 } else { |
| 781 *foundTextAlternative = true; |
| 782 return textAlternative; |
| 783 } |
| 784 } |
| 785 |
| 786 return textAlternative; |
| 787 } |
| 788 |
| 789 String AXObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSet& v
isited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXRelatedObject
Vector* relatedObjects) const |
| 790 { |
| 791 StringBuilder accumulatedText; |
| 792 bool foundValidElement = false; |
| 793 AXRelatedObjectVector localRelatedObjects; |
| 794 |
| 795 for (const auto& element : elements) { |
| 796 AXObject* axElement = axObjectCache().getOrCreate(element); |
| 797 if (axElement) { |
| 798 foundValidElement = true; |
| 799 |
| 800 String result = recursiveTextAlternative(*axElement, inAriaLabelledb
yTraversal, visited); |
| 801 localRelatedObjects.append(new NameSourceRelatedObject(axElement, re
sult)); |
| 802 if (!result.isEmpty()) { |
| 803 if (!accumulatedText.isEmpty()) |
| 804 accumulatedText.append(" "); |
| 805 accumulatedText.append(result); |
| 806 } |
| 807 } |
| 808 } |
| 809 if (!foundValidElement) |
| 810 return String(); |
| 811 if (relatedObjects) |
| 812 *relatedObjects = localRelatedObjects; |
| 813 return accumulatedText.toString(); |
| 814 } |
| 815 |
| 816 void AXObject::tokenVectorFromAttribute(Vector<String>& tokens, const QualifiedN
ame& attribute) const |
| 817 { |
| 818 Node* node = this->node(); |
| 819 if (!node || !node->isElementNode()) |
| 820 return; |
| 821 |
| 822 String attributeValue = getAttribute(attribute).string(); |
| 823 if (attributeValue.isEmpty()) |
| 824 return; |
| 825 |
| 826 attributeValue.simplifyWhiteSpace(); |
| 827 attributeValue.split(' ', tokens); |
| 828 } |
| 829 |
| 830 void AXObject::elementsFromAttribute(WillBeHeapVector<RawPtrWillBeMember<Element
>>& elements, const QualifiedName& attribute) const |
| 831 { |
| 832 Vector<String> ids; |
| 833 tokenVectorFromAttribute(ids, attribute); |
| 834 if (ids.isEmpty()) |
| 835 return; |
| 836 |
| 837 TreeScope& scope = node()->treeScope(); |
| 838 for (const auto& id : ids) { |
| 839 if (Element* idElement = scope.getElementById(AtomicString(id))) |
| 840 elements.append(idElement); |
| 841 } |
| 842 } |
| 843 |
| 844 void AXObject::ariaLabelledbyElementVector(WillBeHeapVector<RawPtrWillBeMember<E
lement>>& elements) const |
| 845 { |
| 846 // Try both spellings, but prefer aria-labelledby, which is the official spe
c. |
| 847 elementsFromAttribute(elements, aria_labelledbyAttr); |
| 848 if (!elements.size()) |
| 849 elementsFromAttribute(elements, aria_labeledbyAttr); |
| 850 } |
| 851 |
| 852 String AXObject::textFromAriaLabelledby(AXObjectSet& visited, AXRelatedObjectVec
tor* relatedObjects) const |
| 853 { |
| 854 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; |
| 855 ariaLabelledbyElementVector(elements); |
| 856 return textFromElements(true, visited, elements, relatedObjects); |
| 857 } |
| 858 |
| 859 String AXObject::textFromAriaDescribedby(AXRelatedObjectVector* relatedObjects)
const |
| 860 { |
| 861 AXObjectSet visited; |
| 862 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; |
| 863 elementsFromAttribute(elements, aria_describedbyAttr); |
| 864 return textFromElements(true, visited, elements, relatedObjects); |
| 865 } |
| 866 |
| 712 AccessibilityOrientation AXObject::orientation() const | 867 AccessibilityOrientation AXObject::orientation() const |
| 713 { | 868 { |
| 714 // In ARIA 1.1, the default value for aria-orientation changed from | 869 // In ARIA 1.1, the default value for aria-orientation changed from |
| 715 // horizontal to undefined. | 870 // horizontal to undefined. |
| 716 return AccessibilityOrientationUndefined; | 871 return AccessibilityOrientationUndefined; |
| 717 } | 872 } |
| 718 | 873 |
| 719 static String queryString(WebLocalizedString::Name name) | 874 static String queryString(WebLocalizedString::Name name) |
| 720 { | 875 { |
| 721 return Locale::defaultLocale().queryString(name); | 876 return Locale::defaultLocale().queryString(name); |
| (...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1473 case DisclosureTriangleRole: | 1628 case DisclosureTriangleRole: |
| 1474 case HeadingRole: | 1629 case HeadingRole: |
| 1475 case LineBreakRole: | 1630 case LineBreakRole: |
| 1476 case LinkRole: | 1631 case LinkRole: |
| 1477 case ListBoxOptionRole: | 1632 case ListBoxOptionRole: |
| 1478 case ListItemRole: | 1633 case ListItemRole: |
| 1479 case MenuItemRole: | 1634 case MenuItemRole: |
| 1480 case MenuItemCheckBoxRole: | 1635 case MenuItemCheckBoxRole: |
| 1481 case MenuItemRadioRole: | 1636 case MenuItemRadioRole: |
| 1482 case MenuListOptionRole: | 1637 case MenuListOptionRole: |
| 1638 case PopUpButtonRole: |
| 1483 case RadioButtonRole: | 1639 case RadioButtonRole: |
| 1484 case StaticTextRole: | 1640 case StaticTextRole: |
| 1485 case StatusRole: | 1641 case StatusRole: |
| 1486 case SwitchRole: | 1642 case SwitchRole: |
| 1487 case TabRole: | 1643 case TabRole: |
| 1488 case ToggleButtonRole: | 1644 case ToggleButtonRole: |
| 1489 case TreeItemRole: | |
| 1490 return true; | 1645 return true; |
| 1491 default: | 1646 default: |
| 1492 return false; | 1647 return false; |
| 1493 } | 1648 } |
| 1494 } | 1649 } |
| 1495 | 1650 |
| 1496 AccessibilityRole AXObject::buttonRoleType() const | 1651 AccessibilityRole AXObject::buttonRoleType() const |
| 1497 { | 1652 { |
| 1498 // If aria-pressed is present, then it should be exposed as a toggle button. | 1653 // If aria-pressed is present, then it should be exposed as a toggle button. |
| 1499 // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed | 1654 // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1523 | 1678 |
| 1524 DEFINE_TRACE(AXObject) | 1679 DEFINE_TRACE(AXObject) |
| 1525 { | 1680 { |
| 1526 visitor->trace(m_children); | 1681 visitor->trace(m_children); |
| 1527 visitor->trace(m_parent); | 1682 visitor->trace(m_parent); |
| 1528 visitor->trace(m_cachedLiveRegionRoot); | 1683 visitor->trace(m_cachedLiveRegionRoot); |
| 1529 visitor->trace(m_axObjectCache); | 1684 visitor->trace(m_axObjectCache); |
| 1530 } | 1685 } |
| 1531 | 1686 |
| 1532 } // namespace blink | 1687 } // namespace blink |
| OLD | NEW |