⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 294878 in webkit


Ignore:
Timestamp:
May 26, 2022, 9:01:38 AM (4 years ago)
Author:
Andres Gonzalez
Message:

AX: Refactor implementation of AX object relationships.
​https://bugs.webkit.org/show_bug.cgi?id=240842

Reviewed by Chris Fleizach and Tyler Wilcock.

Test: accessibility/grid-with-aria-owned-cells.html

Relationships between AX objects were being computed by the methods
AccessibilityObject::ariaElementsFromAttribute and
ariaElementsReferencedByAttribute, both of which performed walks of the DOM tree
to match ids between origin and target of a specific relationship, having a
significant performance impact when called repeatedly.
With this patch, these two methods are replaced with a single method,
AccessibilityObject::relatedObjects, that in turn calls
AXObjectCache::relatedObjectsFor. This AXObjectCache method computes and caches
all relationships in one walk of the DoM tree. The cache is updated when
relevant event notifications are received. This makes support of relationships between objects more efficient, and the code clearer.
The test added exercises this implementation of relationships via the aria-owns
attribute to relate table rows to their cells. The execution time of this test
before this change was estimated in one system at about 1.91s, and after the
change was reduced to 1.87s.

  • Source/WebCore/accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::objectsForIDs const):
(WebCore::AXObjectCache::handleActiveDescendantChanged):
(WebCore::AXObjectCache::handleAttributeChange):
(WebCore::AXObjectCache::relationAttributes):
(WebCore::AXObjectCache::symmetricRelation):
(WebCore::AXObjectCache::attributeToRelationType):
(WebCore::AXObjectCache::addRelation):
(WebCore::AXObjectCache::updateRelationsIfNeeded):
(WebCore::AXObjectCache::relatedObjectsFor):

  • Source/WebCore/accessibility/AXObjectCache.h:

(WebCore::AXObjectCache::relationsNeedUpdate):

  • Source/WebCore/accessibility/AccessibilityObject.cpp:

(WebCore::AccessibilityObject::relatedObjects const):
(WebCore::AccessibilityObject::activeDescendantOfObjects const):
(WebCore::AccessibilityObject::controlledObjects const):
(WebCore::AccessibilityObject::controllers const):
(WebCore::AccessibilityObject::describedByObjects const):
(WebCore::AccessibilityObject::descriptionForObjects const):
(WebCore::AccessibilityObject::detailedByObjects const):
(WebCore::AccessibilityObject::detailsForObjects const):
(WebCore::AccessibilityObject::errorMessageObjects const):
(WebCore::AccessibilityObject::errorMessageForObjects const):
(WebCore::AccessibilityObject::flowToObjects const):
(WebCore::AccessibilityObject::flowFromObjects const):
(WebCore::AccessibilityObject::labelledByObjects const):
(WebCore::AccessibilityObject::labelForObjects const):
(WebCore::AccessibilityObject::ownedObjects const):
(WebCore::AccessibilityObject::owners const):
(WebCore::AccessibilityObject::ariaElementsFromAttribute const): Deleted.
(WebCore::AccessibilityObject::ariaElementsReferencedByAttribute const): Deleted.

  • Source/WebCore/accessibility/AccessibilityObject.h:
  • Source/WebCore/accessibility/AccessibilityObjectInterface.h:

(WebCore::Accessibility::findRelatedObjectInAncestry):

  • Source/WebCore/accessibility/AccessibilityRenderObject.cpp:

(WebCore::AccessibilityRenderObject::activeDescendant const):

  • Source/WebCore/accessibility/AccessibilityTableCell.cpp:

(WebCore::AccessibilityTableCell::columnHeaders):

  • Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp:

(WebCore::AccessibilityObjectAtspi::relationMap const):

  • Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm:

(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
(-[WebAccessibilityObjectWrapper accessibilityArrayAttributeCount:]):

  • LayoutTests/accessibility/grid-with-aria-owned-cells-expected.txt: Added.
  • LayoutTests/accessibility/grid-with-aria-owned-cells.html: Added.

Canonical link: ​https://commits.webkit.org/251008@main

Location:
trunk
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/platform/win/TestExpectations

    r294875 r294878  
    944944webkit.org/b/148967 accessibility/aria-table-attributes.html [ Skip ]
    945945accessibility/aria-grid-with-aria-owns-rows.html [ Skip ]
     946accessibility/grid-with-aria-owned-cells.html [ Skip ]
    946947
    947948# TODO webkit-font-smoothing is not supported.
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r294875 r294878  
    117117#include <utility>
    118118#include <wtf/DataLog.h>
     119#include <wtf/NeverDestroyed.h>
    119120#include <wtf/SetForScope.h>
     121#include <wtf/text/AtomString.h>
    120122
    121123#if COMPILER(MSVC)
    … …  
    949951    ASSERT(isMainThread());
    950952
    951     return axIDs.map([this] (AXID axID) -> RefPtr<AXCoreObject> {
     953    return axIDs.map([this] (const auto& axID) -> RefPtr<AXCoreObject> {
    952954        ASSERT(axID.isValid());
    953955        return objectFromAXID(axID);
    … …  
    18401842        // 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.
    18411843        if (object->isComboBox()) {
    1842             if (auto* ownedObject = Accessibility::findRelatedObjectInAncestry(*object, aria_ownsAttr, *activeDescendant))
     1844            if (auto* ownedObject = Accessibility::findRelatedObjectInAncestry(*object, AXRelationType::OwnerFor, *activeDescendant))
    18431845                target = ownedObject;
    1844             else if (auto* controlledObject = Accessibility::findRelatedObjectInAncestry(*object, aria_controlsAttr, *activeDescendant))
     1846            else if (auto* controlledObject = Accessibility::findRelatedObjectInAncestry(*object, AXRelationType::ControllerFor, *activeDescendant))
    18451847                target = controlledObject;
    18461848        }
    … …  
    18901892    return false;
    18911893}
    1892    
     1894
    18931895void AXObjectCache::handleAttributeChange(const QualifiedName& attrName, Element* element)
    18941896{
    18951897    if (!shouldProcessAttributeChange(attrName, element))
    18961898        return;
     1899
     1900    if (relationAttributes().contains(attrName))
     1901        relationsNeedUpdate(true);
    18971902
    18981903    if (attrName == roleAttr) {
    … …  
    19111916    else if (attrName == langAttr)
    19121917        updateIsolatedTree(get(element), AXObjectCache::AXLanguageChanged);
    1913     else if (attrName == idAttr)
     1918    else if (attrName == idAttr) {
     1919        relationsNeedUpdate(true);
    19141920        updateIsolatedTree(get(element), AXObjectCache::AXIdAttributeChanged);
     1921    }
    19151922#endif
    19161923    else if (attrName == openAttr && is<HTMLDialogElement>(*element)) {
    … …  
    34313438{
    34323439    AXTRACE("AXObjectCache::updateIsolatedTree"_s);
    3433     AXLOG(*this);
    34343440
    34353441    if (!m_pageID) {
    … …  
    36583664}
    36593665
     3666Vector<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
     3683AXRelationType 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
     3727AXRelationType 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
     3750void 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
     3759void 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
     3787void 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
     3838std::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
    36603851AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache)
    36613852    : m_cache(cache)
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

    r294875 r294878  
    378378    AXTreeData treeData();
    379379
     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
    380383#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
    381384    WEBCORE_EXPORT static bool isIsolatedTreeEnabled();
    … …  
    488491    bool modalElementHasAccessibleContent(Element&);
    489492
     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
    490503    Document& m_document;
    491504    const std::optional<PageIdentifier> m_pageID; // constant for object's lifetime.
    … …  
    542555    bool m_performingDeferredCacheUpdate { false };
    543556    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 };
    544562
    545563#if USE(ATSPI)
  • trunk/Source/WebCore/accessibility/AccessibilityObject.cpp

    r294611 r294878  
    39233923}
    39243924
    3925 AXCoreObject::AccessibilityChildrenVector AccessibilityObject::ariaElementsFromAttribute(const QualifiedName& attribute) const
     3925AXCoreObject::AccessibilityChildrenVector AccessibilityObject::relatedObjects(AXRelationType relationType) const
    39263926{
    39273927    auto* cache = axObjectCache();
    39283928    if (!cache)
    39293929        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)
    39413933        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);
    39573935}
    39583936
    … …  
    39703948AXCoreObject::AccessibilityChildrenVector AccessibilityObject::activeDescendantOfObjects() const
    39713949{
    3972     return ariaElementsReferencedByAttribute(aria_activedescendantAttr);
     3950    return relatedObjects(AXRelationType::ActiveDescendantOf);
    39733951}
    39743952
    39753953AXCoreObject::AccessibilityChildrenVector AccessibilityObject::controlledObjects() const
    39763954{
    3977     return ariaElementsFromAttribute(aria_controlsAttr);
     3955    return relatedObjects(AXRelationType::ControllerFor);
    39783956}
    39793957
    39803958AXCoreObject::AccessibilityChildrenVector AccessibilityObject::controllers() const
    39813959{
    3982     return ariaElementsReferencedByAttribute(aria_controlsAttr);
     3960    return relatedObjects(AXRelationType::ControlledBy);
    39833961}
    39843962
    39853963AXCoreObject::AccessibilityChildrenVector AccessibilityObject::describedByObjects() const
    39863964{
    3987     return ariaElementsFromAttribute(aria_describedbyAttr);
     3965    return relatedObjects(AXRelationType::DescribedBy);
    39883966}
    39893967
    39903968AXCoreObject::AccessibilityChildrenVector AccessibilityObject::descriptionForObjects() const
    39913969{
    3992     return ariaElementsReferencedByAttribute(aria_describedbyAttr);
     3970    return relatedObjects(AXRelationType::DescriptionFor);
    39933971}
    39943972
    39953973AXCoreObject::AccessibilityChildrenVector AccessibilityObject::detailedByObjects() const
    39963974{
    3997     return ariaElementsFromAttribute(aria_detailsAttr);
     3975    return relatedObjects(AXRelationType::Details);
    39983976}
    39993977
    40003978AXCoreObject::AccessibilityChildrenVector AccessibilityObject::detailsForObjects() const
    40013979{
    4002     return ariaElementsReferencedByAttribute(aria_detailsAttr);
     3980    return relatedObjects(AXRelationType::DetailsFor);
    40033981}
    40043982
    40053983AXCoreObject::AccessibilityChildrenVector AccessibilityObject::errorMessageObjects() const
    40063984{
    4007     return ariaElementsFromAttribute(aria_errormessageAttr);
     3985    return relatedObjects(AXRelationType::ErrorMessage);
    40083986}
    40093987
    40103988AXCoreObject::AccessibilityChildrenVector AccessibilityObject::errorMessageForObjects() const
    40113989{
    4012     return ariaElementsReferencedByAttribute(aria_errormessageAttr);
     3990    return relatedObjects(AXRelationType::ErrorMessageFor);
    40133991}
    40143992
    40153993AXCoreObject::AccessibilityChildrenVector AccessibilityObject::flowToObjects() const
    40163994{
    4017     return ariaElementsFromAttribute(aria_flowtoAttr);
     3995    return relatedObjects(AXRelationType::FlowsTo);
    40183996}
    40193997
    40203998AXCoreObject::AccessibilityChildrenVector AccessibilityObject::flowFromObjects() const
    40213999{
    4022     return ariaElementsReferencedByAttribute(aria_flowtoAttr);
     4000    return relatedObjects(AXRelationType::FlowsFrom);
    40234001}
    40244002
    40254003AXCoreObject::AccessibilityChildrenVector AccessibilityObject::labelledByObjects() const
    40264004{
    4027     auto labelledByObjects = ariaElementsFromAttribute(aria_labelledbyAttr);
    4028     if (labelledByObjects.isEmpty())
    4029         labelledByObjects = ariaElementsFromAttribute(aria_labeledbyAttr);
    4030     return labelledByObjects;
     4005    return relatedObjects(AXRelationType::LabelledBy);
    40314006}
    40324007
    40334008AXCoreObject::AccessibilityChildrenVector AccessibilityObject::labelForObjects() const
    40344009{
    4035     auto objects = ariaElementsReferencedByAttribute(aria_labelledbyAttr);
    4036     if (objects.isEmpty())
    4037         objects = ariaElementsReferencedByAttribute(aria_labeledbyAttr);
    4038     return objects;
     4010    return relatedObjects(AXRelationType::LabelFor);
    40394011}
    40404012
    40414013AXCoreObject::AccessibilityChildrenVector AccessibilityObject::ownedObjects() const
    40424014{
    4043     return ariaElementsFromAttribute(aria_ownsAttr);
     4015    return relatedObjects(AXRelationType::OwnerFor);
    40444016}
    40454017
    40464018AXCoreObject::AccessibilityChildrenVector AccessibilityObject::owners() const
    40474019{
    4048     return ariaElementsReferencedByAttribute(aria_ownsAttr);
     4020    return relatedObjects(AXRelationType::OwnedBy);
    40494021}
    40504022
  • trunk/Source/WebCore/accessibility/AccessibilityObject.h

    r294167 r294878  
    786786    AccessibilityChildrenVector documentLinks() override { return AccessibilityChildrenVector(); }
    787787
    788     AccessibilityChildrenVector ariaElementsFromAttribute(const QualifiedName&) const;
    789     AccessibilityChildrenVector ariaElementsReferencedByAttribute(const QualifiedName&) const;
     788    AccessibilityChildrenVector relatedObjects(AXRelationType) const;
    790789protected:
    791790    AccessibilityObject() = default;
  • trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h

    r294167 r294878  
    777777enum class AccessibilityMathMultiscriptObjectType { PreSubscript, PreSuperscript, PostSubscript, PostSuperscript };
    778778
     779// Relationships between AX objects.
     780enum 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
    779802// Use this struct to store the isIgnored data that depends on the parents, so that in addChildren()
    780803// we avoid going up the parent chain for each element while traversing the tree with useful information already.
    … …  
    16181641
    16191642template<typename T>
    1620 T* findRelatedObjectInAncestry(const T& object, const QualifiedName& relationAttribute, const T& descendant)
     1643T* findRelatedObjectInAncestry(const T& object, AXRelationType relationType, const T& descendant)
    16211644{
    1622     auto relatedObjects = object.ariaElementsFromAttribute(relationAttribute);
     1645    auto relatedObjects = object.relatedObjects(relationType);
    16231646    for (const auto& object : relatedObjects) {
    16241647        auto* ancestor = findAncestor(descendant, false, [&object] (const auto& ancestor) {
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r294167 r294878  
    26822682AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
    26832683{
    2684     auto activeDescendants = ariaElementsFromAttribute(aria_activedescendantAttr);
     2684    auto activeDescendants = relatedObjects(AXRelationType::ActiveDescendant);
    26852685    ASSERT(activeDescendants.size() <= 1);
    26862686    if (!activeDescendants.isEmpty())
  • trunk/Source/WebCore/accessibility/AccessibilityTableCell.cpp

    r293650 r294878  
    245245
    246246    // Choose columnHeaders as the place where the "headers" attribute is reported.
    247     auto headers = ariaElementsFromAttribute(headersAttr);
     247    auto headers = relatedObjects(AXRelationType::Headers);
    248248    // If the headers attribute returned valid values, then do not further search for column headers.
    249249    if (!headers.isEmpty())
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp

    r293650 r294878  
    10501050        if (!wrappers.isEmpty())
    10511051            map.add(relation, WTFMove(wrappers));
    1052 
    10531052    };
    10541053
  • trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm

    r294552 r294878  
    19331933
    19341934    if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
    1935 
    19361935        // This will return the parent of the AXWebArea, if this is a web area.
    19371936        id scrollViewParent = [self scrollViewParent];
    … …  
    41394138- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
    41404139{
     4140    AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityArrayAttributeCount:", String(attribute)));
     4141
    41414142    auto* backingObject = self.updateObjectBackingStore;
    41424143    if (!backingObject)
Note: See TracChangeset for help on using the changeset viewer.