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 |