From 51a40576c1e72012097b8b5becc845983d635ded Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Wed, 20 Nov 2013 13:24:30 -0500 Subject: [PATCH] Bug 926812 - State change event not fired when both disabled and aria-disabled are toggled, r=tbsaunde --- accessible/src/generic/Accessible.h | 10 +++++ accessible/src/generic/DocAccessible.cpp | 25 +++++++---- accessible/src/generic/DocAccessible.h | 12 +++-- accessible/tests/mochitest/events.js | 7 ++- .../mochitest/events/test_statechange.html | 44 ++++++++++++++++++- 5 files changed, 83 insertions(+), 15 deletions(-) diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 61468f9abfdd..279745603305 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -244,6 +244,16 @@ public: return state; } + /** + * Return if accessible is unavailable. + */ + bool Unavailable() const + { + uint64_t state = NativelyUnavailable() ? states::UNAVAILABLE : 0; + ApplyARIAState(&state); + return state & states::UNAVAILABLE; + } + /** * Return the states of accessible, not taking into account ARIA states. * Use State() to get complete set of states. diff --git a/accessible/src/generic/DocAccessible.cpp b/accessible/src/generic/DocAccessible.cpp index 909c41ab1ba7..ad16ceef5bde 100644 --- a/accessible/src/generic/DocAccessible.cpp +++ b/accessible/src/generic/DocAccessible.cpp @@ -870,7 +870,12 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument, aAttribute == nsGkAtoms::aria_pressed) { mARIAAttrOldValue = (aModType != nsIDOMMutationEvent::ADDITION) ? nsAccUtils::GetARIAToken(aElement, aAttribute) : nullptr; + return; } + + if (aAttribute == nsGkAtoms::aria_disabled || + aAttribute == nsGkAtoms::disabled) + mStateBitWasOn = accessible->Unavailable(); } void @@ -938,22 +943,24 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible, // Universal boolean properties that don't require a role. Fire the state // change when disabled or aria-disabled attribute is set. + // Note. Checking the XUL or HTML namespace would not seem to gain us + // anything, because disabled attribute really is going to mean the same + // thing in any namespace. + // Note. We use the attribute instead of the disabled state bit because + // ARIA's aria-disabled does not affect the disabled state bit. if (aAttribute == nsGkAtoms::disabled || aAttribute == nsGkAtoms::aria_disabled) { - - // Note. Checking the XUL or HTML namespace would not seem to gain us - // anything, because disabled attribute really is going to mean the same - // thing in any namespace. - - // Note. We use the attribute instead of the disabled state bit because - // ARIA's aria-disabled does not affect the disabled state bit. + // Do nothing if state wasn't changed (like @aria-disabled was removed but + // @disabled is still presented). + if (aAccessible->Unavailable() == mStateBitWasOn) + return; nsRefPtr enabledChangeEvent = - new AccStateChangeEvent(aAccessible, states::ENABLED); + new AccStateChangeEvent(aAccessible, states::ENABLED, mStateBitWasOn); FireDelayedEvent(enabledChangeEvent); nsRefPtr sensitiveChangeEvent = - new AccStateChangeEvent(aAccessible, states::SENSITIVE); + new AccStateChangeEvent(aAccessible, states::SENSITIVE, mStateBitWasOn); FireDelayedEvent(sensitiveChangeEvent); return; } diff --git a/accessible/src/generic/DocAccessible.h b/accessible/src/generic/DocAccessible.h index 6de2c3d7cc2e..b17737d43077 100644 --- a/accessible/src/generic/DocAccessible.h +++ b/accessible/src/generic/DocAccessible.h @@ -533,10 +533,16 @@ protected: nsCOMPtr mAnchorJumpElm; /** - * Keep the ARIA attribute old value that is initialized by - * AttributeWillChange and used by AttributeChanged notifications. + * A generic state (see items below) before the attribute value was changed. + * @see AttributeWillChange and AttributeChanged notifications. */ - nsIAtom* mARIAAttrOldValue; + union { + // ARIA attribute value + nsIAtom* mARIAAttrOldValue; + + // True if the accessible state bit was on + bool mStateBitWasOn; + }; nsTArray > mChildDocuments; diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js index 2676a8187826..525d56d6631d 100644 --- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -1959,7 +1959,12 @@ var gA11yEventObserver = var type = eventTypeToString(event.eventType); var info = "Event type: " + type; - if (event instanceof nsIAccessibleTextChangeEvent) { + if (event instanceof nsIAccessibleStateChangeEvent) { + var stateStr = statesToString(event.isExtraState ? 0 : event.state, + event.isExtraState ? event.state : 0); + info += ", state: " + stateStr + ", is enabled: " + event.isEnabled; + + } else if (event instanceof nsIAccessibleTextChangeEvent) { info += ", start: " + event.start + ", length: " + event.length + ", " + (event.isInserted ? "inserted" : "removed") + " text: " + event.modifiedText; diff --git a/accessible/tests/mochitest/events/test_statechange.html b/accessible/tests/mochitest/events/test_statechange.html index d877f6dd4b86..f4557376b548 100644 --- a/accessible/tests/mochitest/events/test_statechange.html +++ b/accessible/tests/mochitest/events/test_statechange.html @@ -143,18 +143,46 @@ new stateChangeChecker(aState, aIsExtraState, true, getNode(aID)) ]; - this.invoke = function dupeStateChange_invoke() + this.invoke = function oppositeStateChange_invoke() { getNode(aID).setAttribute(aAttr, "false"); getNode(aID).setAttribute(aAttr, "true"); } - this.getID = function dupeStateChange_getID() + this.getID = function oppositeStateChange_getID() { return "opposite state change events"; } } + /** + * Change concomitant ARIA and native attribute at once. + */ + function echoingStateChange(aID, aARIAAttr, aAttr, aValue, + aState, aIsExtraState, aIsEnabled) + { + this.eventSeq = [ + new stateChangeChecker(aState, aIsExtraState, aIsEnabled, getNode(aID)) + ]; + + this.invoke = function echoingStateChange_invoke() + { + if (aValue == null) { + getNode(aID).removeAttribute(aARIAAttr); + getNode(aID).removeAttribute(aAttr); + + } else { + getNode(aID).setAttribute(aARIAAttr, aValue); + getNode(aID).setAttribute(aAttr, aValue); + } + } + + this.getID = function echoingStateChange_getID() + { + return "enchoing ARIA and native attributes change"; + } + } + //////////////////////////////////////////////////////////////////////////// // Do tests @@ -193,6 +221,11 @@ gQueue.push(new oppositeStateChange("div", "aria-busy", STATE_BUSY, false)); + gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", "true", + EXT_STATE_ENABLED, true, false)); + gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", null, + EXT_STATE_ENABLED, true, true)); + gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -223,6 +256,11 @@ title="Fire statechange event whenever checked state is changed not depending on focused state"> Bug 788389 + + Bug 926812 +

@@ -242,6 +280,8 @@
+ +