Changeset 294878 in webkit
- Timestamp:
- May 26, 2022, 9:01:38 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 10 edited
-
LayoutTests/accessibility/grid-with-aria-owned-cells-expected.txt (added)
-
LayoutTests/accessibility/grid-with-aria-owned-cells.html (added)
-
LayoutTests/platform/win/TestExpectations (modified) (1 diff)
-
Source/WebCore/accessibility/AXObjectCache.cpp (modified) (7 diffs)
-
Source/WebCore/accessibility/AXObjectCache.h (modified) (3 diffs)
-
Source/WebCore/accessibility/AccessibilityObject.cpp (modified) (2 diffs)
-
Source/WebCore/accessibility/AccessibilityObject.h (modified) (1 diff)
-
Source/WebCore/accessibility/AccessibilityObjectInterface.h (modified) (2 diffs)
-
Source/WebCore/accessibility/AccessibilityRenderObject.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/AccessibilityTableCell.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/platform/win/TestExpectations
r294875 r294878 944 944 webkit.org/b/148967 accessibility/aria-table-attributes.html [ Skip ] 945 945 accessibility/aria-grid-with-aria-owns-rows.html [ Skip ] 946 accessibility/grid-with-aria-owned-cells.html [ Skip ] 946 947 947 948 # TODO webkit-font-smoothing is not supported. -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r294875 r294878 117 117 #include <utility> 118 118 #include <wtf/DataLog.h> 119 #include <wtf/NeverDestroyed.h> 119 120 #include <wtf/SetForScope.h> 121 #include <wtf/text/AtomString.h> 120 122 121 123 #if COMPILER(MSVC) … … 949 951 ASSERT(isMainThread()); 950 952 951 return axIDs.map([this] ( AXIDaxID) -> RefPtr<AXCoreObject> {953 return axIDs.map([this] (const auto& axID) -> RefPtr<AXCoreObject> { 952 954 ASSERT(axID.isValid()); 953 955 return objectFromAXID(axID); … … 1840 1842 // If the combobox's activeDescendant is inside a descendant owned or controlled by the combobox, that descendant should be the target of the notification and not the combobox itself. 1841 1843 if (object->isComboBox()) { 1842 if (auto* ownedObject = Accessibility::findRelatedObjectInAncestry(*object, aria_ownsAttr, *activeDescendant))1844 if (auto* ownedObject = Accessibility::findRelatedObjectInAncestry(*object, AXRelationType::OwnerFor, *activeDescendant)) 1843 1845 target = ownedObject; 1844 else if (auto* controlledObject = Accessibility::findRelatedObjectInAncestry(*object, aria_controlsAttr, *activeDescendant))1846 else if (auto* controlledObject = Accessibility::findRelatedObjectInAncestry(*object, AXRelationType::ControllerFor, *activeDescendant)) 1845 1847 target = controlledObject; 1846 1848 } … … 1890 1892 return false; 1891 1893 } 1892 1894 1893 1895 void AXObjectCache::handleAttributeChange(const QualifiedName& attrName, Element* element) 1894 1896 { 1895 1897 if (!shouldProcessAttributeChange(attrName, element)) 1896 1898 return; 1899 1900 if (relationAttributes().contains(attrName)) 1901 relationsNeedUpdate(true); 1897 1902 1898 1903 if (attrName == roleAttr) { … … 1911 1916 else if (attrName == langAttr) 1912 1917 updateIsolatedTree(get(element), AXObjectCache::AXLanguageChanged); 1913 else if (attrName == idAttr) 1918 else if (attrName == idAttr) { 1919 relationsNeedUpdate(true); 1914 1920 updateIsolatedTree(get(element), AXObjectCache::AXIdAttributeChanged); 1921 } 1915 1922 #endif 1916 1923 else if (attrName == openAttr && is<HTMLDialogElement>(*element)) { … … 3431 3438 { 3432 3439 AXTRACE("AXObjectCache::updateIsolatedTree"_s); 3433 AXLOG(*this);3434 3440 3435 3441 if (!m_pageID) { … … 3658 3664 } 3659 3665 3666 Vector<QualifiedName>& AXObjectCache::relationAttributes() 3667 { 3668 static NeverDestroyed<Vector<QualifiedName>> relationAttributes = Vector<QualifiedName> { 3669 aria_activedescendantAttr, 3670 aria_controlsAttr, 3671 aria_describedbyAttr, 3672 aria_detailsAttr, 3673 aria_errormessageAttr, 3674 aria_flowtoAttr, 3675 aria_labelledbyAttr, 3676 aria_labeledbyAttr, 3677 aria_ownsAttr, 3678 headersAttr, 3679 }; 3680 return relationAttributes; 3681 } 3682 3683 AXRelationType AXObjectCache::symmetricRelation(AXRelationType relationType) 3684 { 3685 switch (relationType) { 3686 case AXRelationType::ActiveDescendant: 3687 return AXRelationType::ActiveDescendantOf; 3688 case AXRelationType::ActiveDescendantOf: 3689 return AXRelationType::ActiveDescendant; 3690 case AXRelationType::ControlledBy: 3691 return AXRelationType::ControllerFor; 3692 case AXRelationType::ControllerFor: 3693 return AXRelationType::ControlledBy; 3694 case AXRelationType::DescribedBy: 3695 return AXRelationType::DescriptionFor; 3696 case AXRelationType::DescriptionFor: 3697 return AXRelationType::DescribedBy; 3698 case AXRelationType::Details: 3699 return AXRelationType::DetailsFor; 3700 case AXRelationType::DetailsFor: 3701 return AXRelationType::Details; 3702 case AXRelationType::ErrorMessage: 3703 return AXRelationType::ErrorMessageFor; 3704 case AXRelationType::ErrorMessageFor: 3705 return AXRelationType::ErrorMessage; 3706 case AXRelationType::FlowsFrom: 3707 return AXRelationType::FlowsTo; 3708 case AXRelationType::FlowsTo: 3709 return AXRelationType::FlowsFrom; 3710 case AXRelationType::Headers: 3711 return AXRelationType::HeaderFor; 3712 case AXRelationType::HeaderFor: 3713 return AXRelationType::Headers; 3714 case AXRelationType::LabelledBy: 3715 return AXRelationType::LabelFor; 3716 case AXRelationType::LabelFor: 3717 return AXRelationType::LabelledBy; 3718 case AXRelationType::OwnedBy: 3719 return AXRelationType::OwnerFor; 3720 case AXRelationType::OwnerFor: 3721 return AXRelationType::OwnedBy; 3722 case AXRelationType::None: 3723 return AXRelationType::None; 3724 } 3725 } 3726 3727 AXRelationType AXObjectCache::attributeToRelationType(const QualifiedName& attribute) 3728 { 3729 if (attribute == aria_activedescendantAttr) 3730 return AXRelationType::ActiveDescendant; 3731 if (attribute == aria_controlsAttr) 3732 return AXRelationType::ControllerFor; 3733 if (attribute == aria_describedbyAttr) 3734 return AXRelationType::DescribedBy; 3735 if (attribute == aria_detailsAttr) 3736 return AXRelationType::Details; 3737 if (attribute == aria_errormessageAttr) 3738 return AXRelationType::ErrorMessage; 3739 if (attribute == aria_flowtoAttr) 3740 return AXRelationType::FlowsTo; 3741 if (attribute == aria_labelledbyAttr || attribute == aria_labeledbyAttr) 3742 return AXRelationType::LabelledBy; 3743 if (attribute == aria_ownsAttr) 3744 return AXRelationType::OwnerFor; 3745 if (attribute == headersAttr) 3746 return AXRelationType::Headers; 3747 return AXRelationType::None; 3748 } 3749 3750 void AXObjectCache::addRelation(Element* origin, Element* target, AXRelationType relationType) 3751 { 3752 if (!origin || !target || origin == target || relationType == AXRelationType::None) { 3753 ASSERT_NOT_REACHED(); 3754 return; 3755 } 3756 addRelation(getOrCreate(origin), getOrCreate(target), relationType); 3757 } 3758 3759 void AXObjectCache::addRelation(AccessibilityObject* origin, AccessibilityObject* target, AXRelationType relationType, AddingSymmetricRelation addingSymmetricRelation) 3760 { 3761 if (!origin || !target || origin == target || relationType == AXRelationType::None) 3762 return; 3763 3764 auto relationsIterator = m_relations.find(origin->objectID()); 3765 if (relationsIterator == m_relations.end()) { 3766 // No relations for this object, add the first one. 3767 m_relations.add(origin->objectID(), Relations { { static_cast<uint8_t>(relationType), { target->objectID() } } }); 3768 } else if (auto targetsIterator = relationsIterator->value.find(static_cast<uint8_t>(relationType)); targetsIterator == relationsIterator->value.end()) { 3769 // No relation of this type for this object, add the first one. 3770 relationsIterator->value.add(static_cast<uint8_t>(relationType), Vector<AXID> { target->objectID() }); 3771 } else { 3772 // There are already relations of this type for the object. Add the new relation. 3773 if (relationType == AXRelationType::ActiveDescendant 3774 || relationType == AXRelationType::OwnedBy) { 3775 // There should be only one active descendant and only one owner. Enforce that by removing any existing targets. 3776 targetsIterator->value.clear(); 3777 } 3778 targetsIterator->value.append(target->objectID()); 3779 } 3780 3781 if (addingSymmetricRelation == AddingSymmetricRelation::No) { 3782 if (auto symmetric = symmetricRelation(relationType); symmetric != AXRelationType::None) 3783 addRelation(target, origin, symmetric, AddingSymmetricRelation::Yes); 3784 } 3785 } 3786 3787 void AXObjectCache::updateRelationsIfNeeded() 3788 { 3789 AXTRACE("AXObjectCache::updateRelationsIfNeeded"_s); 3790 3791 if (!m_relationsNeedUpdate) 3792 return; 3793 relationsNeedUpdate(false); 3794 AXLOG("Updating relations."); 3795 m_relations.clear(); 3796 3797 struct RelationOrigin { 3798 Element* originElement { nullptr }; 3799 AtomString targetID; 3800 AXRelationType relationType; 3801 }; 3802 3803 struct RelationTarget { 3804 Element* targetElement { nullptr }; 3805 AtomString targetID; 3806 }; 3807 3808 Vector<RelationOrigin> origins; 3809 Vector<RelationTarget> targets; 3810 for (auto& element : descendantsOfType<Element>(m_document.rootNode())) { 3811 // Collect all possible origins, i.e., elements with non-empty relation attributes. 3812 for (const auto& attribute : relationAttributes()) { 3813 auto& idsString = element.attributeWithoutSynchronization(attribute); 3814 SpaceSplitString ids(idsString, SpaceSplitString::ShouldFoldCase::No); 3815 for (size_t i = 0; i < ids.size(); ++i) 3816 origins.append({ &element, ids[i], attributeToRelationType(attribute) }); 3817 } 3818 3819 // Collect all possible targets, i.e., elements with a non-empty id attribute. 3820 auto elementID = element.attributeWithoutSynchronization(idAttr); 3821 if (!elementID.isEmpty()) 3822 targets.append({ &element, elementID }); 3823 } 3824 3825 for (const auto& origin : origins) { 3826 for (const auto& target : targets) { 3827 if (origin.originElement == target.targetElement) { 3828 // Relationship should be between different elements. 3829 continue; 3830 } 3831 3832 if (origin.targetID == target.targetID) 3833 addRelation(origin.originElement, target.targetElement, origin.relationType); 3834 } 3835 } 3836 } 3837 3838 std::optional<Vector<AXID>> AXObjectCache::relatedObjectsFor(const AXCoreObject& object, AXRelationType relationType) 3839 { 3840 updateRelationsIfNeeded(); 3841 auto relationsIterator = m_relations.find(object.objectID()); 3842 if (relationsIterator == m_relations.end()) 3843 return std::nullopt; 3844 3845 auto targetsIterator = relationsIterator->value.find(static_cast<uint8_t>(relationType)); 3846 if (targetsIterator == relationsIterator->value.end()) 3847 return std::nullopt; 3848 return targetsIterator->value; 3849 } 3850 3660 3851 AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache) 3661 3852 : m_cache(cache) -
trunk/Source/WebCore/accessibility/AXObjectCache.h
r294875 r294878 378 378 AXTreeData treeData(); 379 379 380 // Returns the IDs of the objects that relate to the given object with the specified relationship. 381 std::optional<Vector<AXID>> relatedObjectsFor(const AXCoreObject&, AXRelationType); 382 380 383 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) 381 384 WEBCORE_EXPORT static bool isIsolatedTreeEnabled(); … … 488 491 bool modalElementHasAccessibleContent(Element&); 489 492 493 // Relationships between objects. 494 static Vector<QualifiedName>& relationAttributes(); 495 static AXRelationType attributeToRelationType(const QualifiedName&); 496 enum class AddingSymmetricRelation : bool { No, Yes }; 497 static AXRelationType symmetricRelation(AXRelationType); 498 void addRelation(Element*, Element*, AXRelationType); 499 void addRelation(AccessibilityObject*, AccessibilityObject*, AXRelationType, AddingSymmetricRelation = AddingSymmetricRelation::No); 500 void updateRelationsIfNeeded(); 501 void relationsNeedUpdate(bool needUpdate) { m_relationsNeedUpdate = needUpdate; } 502 490 503 Document& m_document; 491 504 const std::optional<PageIdentifier> m_pageID; // constant for object's lifetime. … … 542 555 bool m_performingDeferredCacheUpdate { false }; 543 556 double m_loadingProgress { 0 }; 557 558 // Relationships between objects. 559 using Relations = HashMap<AXRelationType, Vector<AXID>, DefaultHash<uint8_t>, WTF::UnsignedWithZeroKeyHashTraits<uint8_t>>; 560 HashMap<AXID, Relations> m_relations; 561 bool m_relationsNeedUpdate { true }; 544 562 545 563 #if USE(ATSPI) -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r294611 r294878 3923 3923 } 3924 3924 3925 AXCoreObject::AccessibilityChildrenVector AccessibilityObject:: ariaElementsFromAttribute(const QualifiedName& attribute) const3925 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::relatedObjects(AXRelationType relationType) const 3926 3926 { 3927 3927 auto* cache = axObjectCache(); 3928 3928 if (!cache) 3929 3929 return { }; 3930 return elementsFromAttribute(attribute).map([cache] (auto* element) -> RefPtr<AXCoreObject> { 3931 return cache->getOrCreate(element); 3932 }); 3933 } 3934 3935 // FIXME: This function iterates the whole DOM tree and tries to match every Element in the tree, which is very expensive. 3936 // We should find a better way to achieve this. 3937 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::ariaElementsReferencedByAttribute(const QualifiedName& attribute) const 3938 { 3939 auto id = identifierAttribute(); 3940 if (id.isEmpty()) 3930 3931 auto relatedObjectIDs = cache->relatedObjectsFor(*this, relationType); 3932 if (!relatedObjectIDs) 3941 3933 return { }; 3942 3943 auto* cache = axObjectCache(); 3944 if (!cache) 3945 return { }; 3946 3947 AccessibilityChildrenVector objects; 3948 for (auto& element : descendantsOfType<Element>(node()->treeScope().rootNode())) { 3949 auto& idList = element.attributeWithoutSynchronization(attribute); 3950 if (!SpaceSplitString::spaceSplitStringContainsValue(idList, id, SpaceSplitString::ShouldFoldCase::No)) 3951 continue; 3952 3953 if (auto* object = cache->getOrCreate(&element)) 3954 objects.append(object); 3955 } 3956 return objects; 3934 return cache->objectsForIDs(*relatedObjectIDs); 3957 3935 } 3958 3936 … … 3970 3948 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::activeDescendantOfObjects() const 3971 3949 { 3972 return ariaElementsReferencedByAttribute(aria_activedescendantAttr);3950 return relatedObjects(AXRelationType::ActiveDescendantOf); 3973 3951 } 3974 3952 3975 3953 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::controlledObjects() const 3976 3954 { 3977 return ariaElementsFromAttribute(aria_controlsAttr);3955 return relatedObjects(AXRelationType::ControllerFor); 3978 3956 } 3979 3957 3980 3958 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::controllers() const 3981 3959 { 3982 return ariaElementsReferencedByAttribute(aria_controlsAttr);3960 return relatedObjects(AXRelationType::ControlledBy); 3983 3961 } 3984 3962 3985 3963 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::describedByObjects() const 3986 3964 { 3987 return ariaElementsFromAttribute(aria_describedbyAttr);3965 return relatedObjects(AXRelationType::DescribedBy); 3988 3966 } 3989 3967 3990 3968 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::descriptionForObjects() const 3991 3969 { 3992 return ariaElementsReferencedByAttribute(aria_describedbyAttr);3970 return relatedObjects(AXRelationType::DescriptionFor); 3993 3971 } 3994 3972 3995 3973 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::detailedByObjects() const 3996 3974 { 3997 return ariaElementsFromAttribute(aria_detailsAttr);3975 return relatedObjects(AXRelationType::Details); 3998 3976 } 3999 3977 4000 3978 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::detailsForObjects() const 4001 3979 { 4002 return ariaElementsReferencedByAttribute(aria_detailsAttr);3980 return relatedObjects(AXRelationType::DetailsFor); 4003 3981 } 4004 3982 4005 3983 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::errorMessageObjects() const 4006 3984 { 4007 return ariaElementsFromAttribute(aria_errormessageAttr);3985 return relatedObjects(AXRelationType::ErrorMessage); 4008 3986 } 4009 3987 4010 3988 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::errorMessageForObjects() const 4011 3989 { 4012 return ariaElementsReferencedByAttribute(aria_errormessageAttr);3990 return relatedObjects(AXRelationType::ErrorMessageFor); 4013 3991 } 4014 3992 4015 3993 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::flowToObjects() const 4016 3994 { 4017 return ariaElementsFromAttribute(aria_flowtoAttr);3995 return relatedObjects(AXRelationType::FlowsTo); 4018 3996 } 4019 3997 4020 3998 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::flowFromObjects() const 4021 3999 { 4022 return ariaElementsReferencedByAttribute(aria_flowtoAttr);4000 return relatedObjects(AXRelationType::FlowsFrom); 4023 4001 } 4024 4002 4025 4003 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::labelledByObjects() const 4026 4004 { 4027 auto labelledByObjects = ariaElementsFromAttribute(aria_labelledbyAttr); 4028 if (labelledByObjects.isEmpty()) 4029 labelledByObjects = ariaElementsFromAttribute(aria_labeledbyAttr); 4030 return labelledByObjects; 4005 return relatedObjects(AXRelationType::LabelledBy); 4031 4006 } 4032 4007 4033 4008 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::labelForObjects() const 4034 4009 { 4035 auto objects = ariaElementsReferencedByAttribute(aria_labelledbyAttr); 4036 if (objects.isEmpty()) 4037 objects = ariaElementsReferencedByAttribute(aria_labeledbyAttr); 4038 return objects; 4010 return relatedObjects(AXRelationType::LabelFor); 4039 4011 } 4040 4012 4041 4013 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::ownedObjects() const 4042 4014 { 4043 return ariaElementsFromAttribute(aria_ownsAttr);4015 return relatedObjects(AXRelationType::OwnerFor); 4044 4016 } 4045 4017 4046 4018 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::owners() const 4047 4019 { 4048 return ariaElementsReferencedByAttribute(aria_ownsAttr);4020 return relatedObjects(AXRelationType::OwnedBy); 4049 4021 } 4050 4022 -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r294167 r294878 786 786 AccessibilityChildrenVector documentLinks() override { return AccessibilityChildrenVector(); } 787 787 788 AccessibilityChildrenVector ariaElementsFromAttribute(const QualifiedName&) const; 789 AccessibilityChildrenVector ariaElementsReferencedByAttribute(const QualifiedName&) const; 788 AccessibilityChildrenVector relatedObjects(AXRelationType) const; 790 789 protected: 791 790 AccessibilityObject() = default; -
trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h
r294167 r294878 777 777 enum class AccessibilityMathMultiscriptObjectType { PreSubscript, PreSuperscript, PostSubscript, PostSuperscript }; 778 778 779 // Relationships between AX objects. 780 enum class AXRelationType : uint8_t { 781 None, 782 ActiveDescendant, 783 ActiveDescendantOf, 784 ControlledBy, 785 ControllerFor, 786 DescribedBy, 787 DescriptionFor, 788 Details, 789 DetailsFor, 790 ErrorMessage, 791 ErrorMessageFor, 792 FlowsFrom, 793 FlowsTo, 794 Headers, 795 HeaderFor, 796 LabelledBy, 797 LabelFor, 798 OwnedBy, 799 OwnerFor, 800 }; 801 779 802 // Use this struct to store the isIgnored data that depends on the parents, so that in addChildren() 780 803 // we avoid going up the parent chain for each element while traversing the tree with useful information already. … … 1618 1641 1619 1642 template<typename T> 1620 T* findRelatedObjectInAncestry(const T& object, const QualifiedName& relationAttribute, const T& descendant)1643 T* findRelatedObjectInAncestry(const T& object, AXRelationType relationType, const T& descendant) 1621 1644 { 1622 auto relatedObjects = object. ariaElementsFromAttribute(relationAttribute);1645 auto relatedObjects = object.relatedObjects(relationType); 1623 1646 for (const auto& object : relatedObjects) { 1624 1647 auto* ancestor = findAncestor(descendant, false, [&object] (const auto& ancestor) { -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
r294167 r294878 2682 2682 AccessibilityObject* AccessibilityRenderObject::activeDescendant() const 2683 2683 { 2684 auto activeDescendants = ariaElementsFromAttribute(aria_activedescendantAttr);2684 auto activeDescendants = relatedObjects(AXRelationType::ActiveDescendant); 2685 2685 ASSERT(activeDescendants.size() <= 1); 2686 2686 if (!activeDescendants.isEmpty()) -
trunk/Source/WebCore/accessibility/AccessibilityTableCell.cpp
r293650 r294878 245 245 246 246 // Choose columnHeaders as the place where the "headers" attribute is reported. 247 auto headers = ariaElementsFromAttribute(headersAttr);247 auto headers = relatedObjects(AXRelationType::Headers); 248 248 // If the headers attribute returned valid values, then do not further search for column headers. 249 249 if (!headers.isEmpty()) -
trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
r293650 r294878 1050 1050 if (!wrappers.isEmpty()) 1051 1051 map.add(relation, WTFMove(wrappers)); 1052 1053 1052 }; 1054 1053 -
trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
r294552 r294878 1933 1933 1934 1934 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) { 1935 1936 1935 // This will return the parent of the AXWebArea, if this is a web area. 1937 1936 id scrollViewParent = [self scrollViewParent]; … … 4139 4138 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute 4140 4139 { 4140 AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityArrayAttributeCount:", String(attribute))); 4141 4141 4142 auto* backingObject = self.updateObjectBackingStore; 4142 4143 if (!backingObject)
Note:
See TracChangeset
for help on using the changeset viewer.