diff options
Diffstat (limited to 'accessible/generic/LocalAccessible.cpp')
-rw-r--r-- | accessible/generic/LocalAccessible.cpp | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp index f02f68faa6..a758164e2b 100644 --- a/accessible/generic/LocalAccessible.cpp +++ b/accessible/generic/LocalAccessible.cpp @@ -127,6 +127,7 @@ ENameValueFlag LocalAccessible::Name(nsString& aName) const { if (!aName.IsEmpty()) return eNameOK; ENameValueFlag nameFlag = NativeName(aName); + nsCoreUtils::TrimNonBreakingSpaces(aName); if (!aName.IsEmpty()) return nameFlag; // In the end get the name from tooltip. @@ -1840,10 +1841,40 @@ bool LocalAccessible::SetCurValue(double aValue) { kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true)); } +role LocalAccessible::FindNextValidARIARole( + std::initializer_list<nsStaticAtom*> aRolesToSkip) const { + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + if (roleMapEntry && mContent && mContent->IsElement()) { + dom::Element* elem = mContent->AsElement(); + if (!nsAccUtils::ARIAAttrValueIs(elem, nsGkAtoms::role, + roleMapEntry->roleAtom, eIgnoreCase)) { + // Get the next valid token that isn't in the list of roles to skip. + uint8_t roleMapIndex = + aria::GetFirstValidRoleMapIndexExcluding(elem, aRolesToSkip); + // If we don't find a valid token, fall back to the native role. + if (roleMapIndex == aria::NO_ROLE_MAP_ENTRY_INDEX || + roleMapIndex == aria::LANDMARK_ROLE_MAP_ENTRY_INDEX) { + return NativeRole(); + } + const nsRoleMapEntry* fallbackRoleMapEntry = + aria::GetRoleMapFromIndex(roleMapIndex); + if (!fallbackRoleMapEntry) { + return NativeRole(); + } + // Return the next valid role, but validate that first, too. + return ARIATransformRole(fallbackRoleMapEntry->role); + } + } + // Fall back to the native role. + return NativeRole(); +} + role LocalAccessible::ARIATransformRole(role aRole) const { // Beginning with ARIA 1.1, user agents are expected to use the native host - // language role of the element when the region role is used without a name. - // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-region + // language role of the element when the form or region roles are used without + // a name. Says the spec, "the user agent MUST treat such elements as if no + // role had been provided." + // https://w3c.github.io/aria/#document-handling_author-errors_roles // // XXX: While the name computation algorithm can be non-trivial in the general // case, it should not be especially bad here: If the author hasn't used the @@ -1851,10 +1882,18 @@ role LocalAccessible::ARIATransformRole(role aRole) const { // calculation rule excludes name from content. That said, this use case is // another example of why we should consider caching the accessible name. See: // https://bugzilla.mozilla.org/show_bug.cgi?id=1378235. - if (aRole == roles::REGION) { - nsAutoString name; - Name(name); - return name.IsEmpty() ? NativeRole() : aRole; + if (aRole == roles::REGION || aRole == roles::FORM) { + if (NameIsEmpty()) { + // If we have a "form" or "region" role, but no accessible name, we need + // to search for the next valid role. First, we search through the role + // attribute value string - there might be a valid fallback there. Skip + // all "form" or "region" attributes; we know they're not valid since + // there's no accessible name. If we find a valid role that's not "form" + // or "region", fall back to it (but run it through ARIATransformRole + // first). Otherwise, fall back to the element's native role. + return FindNextValidARIARole({nsGkAtoms::region, nsGkAtoms::form}); + } + return aRole; } // XXX: these unfortunate exceptions don't fit into the ARIA table. This is @@ -2510,6 +2549,10 @@ void LocalAccessible::Shutdown() { // LocalAccessible protected void LocalAccessible::ARIAName(nsString& aName) const { + // 'slot' elements should ignore aria-label and aria-labelledby. + if (mContent->IsHTMLElement(nsGkAtoms::slot)) { + return; + } // aria-labelledby now takes precedence over aria-label nsresult rv = nsTextEquivUtils::GetTextEquivFromIDRefs( this, nsGkAtoms::aria_labelledby, aName); @@ -3010,11 +3053,10 @@ LocalAccessible* LocalAccessible::CurrentItem() const { // For activedescendant, the ARIA spec does not require that the user agent // checks whether pointed node is actually a DOM descendant of the element // with the aria-activedescendant attribute. - nsAutoString id; - if (HasOwnContent() && mContent->IsElement() && - mContent->AsElement()->GetAttr(nsGkAtoms::aria_activedescendant, id)) { - dom::Element* activeDescendantElm = IDRefsIterator::GetElem(mContent, id); - if (activeDescendantElm) { + if (HasOwnContent() && mContent->IsElement()) { + if (dom::Element* activeDescendantElm = + nsCoreUtils::GetAriaActiveDescendantElement( + mContent->AsElement())) { if (mContent->IsInclusiveDescendantOf(activeDescendantElm)) { // Don't want a cyclical descendant relationship. That would be bad. return nullptr; @@ -3043,8 +3085,8 @@ LocalAccessible* LocalAccessible::ContainerWidget() const { parent = parent->LocalParent()) { nsIContent* parentContent = parent->GetContent(); if (parentContent && parentContent->IsElement() && - parentContent->AsElement()->HasAttr( - nsGkAtoms::aria_activedescendant)) { + nsCoreUtils::GetAriaActiveDescendantElement( + parentContent->AsElement())) { return parent; } @@ -3055,7 +3097,7 @@ LocalAccessible* LocalAccessible::ContainerWidget() const { return nullptr; } -bool LocalAccessible::IsActiveDescendant(LocalAccessible** aWidget) const { +bool LocalAccessible::IsActiveDescendantId(LocalAccessible** aWidget) const { if (!HasOwnContent() || !mContent->HasID()) { return false; } |