Bug 786143 - inherit aria-hidden through subtree, r=yzen

This commit is contained in:
Alexander Surkov 2015-02-04 18:33:33 -05:00
parent 729f2d8fe8
commit 8a6810240e
7 changed files with 86 additions and 10 deletions

View File

@ -711,7 +711,7 @@ static const AttrCharacteristics gWAIUnivAttrMap[] = {
{&nsGkAtoms::aria_flowto, ATTR_BYPASSOBJ | ATTR_GLOBAL },
{&nsGkAtoms::aria_grabbed, ATTR_VALTOKEN | ATTR_GLOBAL },
{&nsGkAtoms::aria_haspopup, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
{&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
{&nsGkAtoms::aria_hidden, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL }, /* handled special way */
{&nsGkAtoms::aria_invalid, ATTR_BYPASSOBJ | ATTR_VALTOKEN | ATTR_GLOBAL },
{&nsGkAtoms::aria_label, ATTR_BYPASSOBJ | ATTR_GLOBAL },
{&nsGkAtoms::aria_labelledby, ATTR_BYPASSOBJ | ATTR_GLOBAL },
@ -798,6 +798,15 @@ aria::AttrCharacteristicsFor(nsIAtom* aAtom)
return 0;
}
bool
aria::HasDefinedARIAHidden(nsIContent* aContent)
{
return aContent &&
nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_hidden) &&
!aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_hidden,
nsGkAtoms::_false, eCaseMatters);
}
////////////////////////////////////////////////////////////////////////////////
// AttrIterator class

View File

@ -227,6 +227,11 @@ uint64_t UniversalStatesFor(mozilla::dom::Element* aElement);
*/
uint8_t AttrCharacteristicsFor(nsIAtom* aAtom);
/**
* Return true if the element has defined aria-hidden.
*/
bool HasDefinedARIAHidden(nsIContent* aContent);
/**
* Represents a simple enumerator for iterating through ARIA attributes
* exposed as object attributes on a given accessible.

View File

@ -892,11 +892,7 @@ RuleCache::ApplyFilter(Accessible* aAccessible, uint16_t* aResult)
return NS_OK;
if (nsIAccessibleTraversalRule::PREFILTER_ARIA_HIDDEN & mPreFilter) {
nsIContent* content = aAccessible->GetContent();
if (content &&
nsAccUtils::HasDefinedARIAToken(content, nsGkAtoms::aria_hidden) &&
!content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_hidden,
nsGkAtoms::_false, eCaseMatters)) {
if (aAccessible->IsARIAHidden()) {
*aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
return NS_OK;
}

View File

@ -873,6 +873,11 @@ Accessible::Attributes()
while(attribIter.Next(name, value))
attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, unused);
if (IsARIAHidden()) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
NS_LITERAL_STRING("true"));
}
// If there is no aria-live attribute then expose default value of 'live'
// object attribute used for ARIA role of this accessible.
if (mRoleMapEntry) {
@ -1920,6 +1925,9 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
mContextFlags |= eHasNameDependentParent;
else
mContextFlags &= ~eHasNameDependentParent;
if (mParent->IsARIAHidden() || aria::HasDefinedARIAHidden(mContent))
SetARIAHidden(true);
}
// Accessible protected
@ -2377,6 +2385,20 @@ Accessible::ContainerWidget() const
return nullptr;
}
void
Accessible::SetARIAHidden(bool aIsDefined)
{
if (aIsDefined)
mContextFlags |= eARIAHidden;
else
mContextFlags &= ~eARIAHidden;
uint32_t length = mChildren.Length();
for (uint32_t i = 0; i < length; i++) {
mChildren[i]->SetARIAHidden(aIsDefined);
}
}
////////////////////////////////////////////////////////////////////////////////
// Accessible protected methods

View File

@ -889,6 +889,13 @@ public:
bool HasNameDependentParent() const
{ return mContextFlags & eHasNameDependentParent; }
/**
* Return true if aria-hidden="true" is applied to the accessible or inherited
* from the parent.
*/
bool IsARIAHidden() const { return mContextFlags & eARIAHidden; }
void SetARIAHidden(bool aIsDefined);
protected:
virtual ~Accessible();
@ -975,8 +982,9 @@ protected:
*/
enum ContextFlags {
eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
eARIAHidden = 1 << 1,
eLastContextFlag = eHasNameDependentParent
eLastContextFlag = eARIAHidden
};
protected:
@ -1082,7 +1090,7 @@ protected:
static const uint8_t kChildrenFlagsBits = 2;
static const uint8_t kStateFlagsBits = 9;
static const uint8_t kContextFlagsBits = 1;
static const uint8_t kContextFlagsBits = 2;
static const uint8_t kTypeBits = 6;
static const uint8_t kGenericTypesBits = 13;

View File

@ -955,6 +955,22 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
nsIContent* elm = aAccessible->GetContent();
// Update aria-hidden flag for the whole subtree iff aria-hidden is changed
// on the root, i.e. ignore any affiliated aria-hidden changes in the subtree
// of top aria-hidden.
if (aAttribute == nsGkAtoms::aria_hidden) {
bool isDefined = aria::HasDefinedARIAHidden(elm);
if (isDefined != aAccessible->IsARIAHidden() &&
!aAccessible->Parent()->IsARIAHidden()) {
aAccessible->SetARIAHidden(isDefined);
nsRefPtr<AccEvent> event =
new AccObjectAttrChangedEvent(aAccessible, aAttribute);
FireDelayedEvent(event);
}
return;
}
if (aAttribute == nsGkAtoms::aria_checked ||
(aAccessible->IsButton() &&
aAttribute == nsGkAtoms::aria_pressed)) {

View File

@ -11,6 +11,8 @@
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../attributes.js"></script>
<script type="application/javascript"
src="../events.js"></script>
@ -40,6 +42,23 @@
};
}
function updateARIAHidden(aID, aIsDefined, aChildId)
{
this.__proto__ = new updateAttribute(aID, "aria-hidden",
aIsDefined ? "true" : "false");
this.finalCheck = function updateARIAHidden()
{
if (aIsDefined) {
testAttrs(aID, {"hidden" : "true"}, true);
testAttrs(aChildId, {"hidden" : "true"}, true);
} else {
testAbsentAttrs(aID, { "hidden": "true"});
testAbsentAttrs(aChildId, { "hidden": "true"});
}
}
}
// Debug stuff.
// gA11yEventDumpID = "eventdump";
//gA11yEventDumpToConsole = true;
@ -48,7 +67,8 @@
{
gQueue = new eventQueue();
gQueue.push(new updateAttribute("hideable", "aria-hidden", "true"));
gQueue.push(new updateARIAHidden("hideable", true, "hideable_child"));
gQueue.push(new updateARIAHidden("hideable", false, "hideable_child"));
gQueue.push(new updateAttribute("sortable", "aria-sort", "ascending"));
@ -89,7 +109,7 @@
</pre>
<div id="eventdump"></div>
<div id="hideable"><div>Hi</div><div>there</div></div>
<div id="hideable"><div id="hideable_child">Hi</div><div>there</div></div>
<div id="sortable" role="columnheader" aria-sort="none">aria-sort</div>