Bug 1056803 - added nsiAccessibleObjectAttributeChangedEvent interface. Tests included. r=tbsaunde
authorYura Zenevich <yzenevich@mozilla.com>
Thu, 28 Aug 2014 08:42:06 -0400
changeset 216528 ad8901b59cd04d3bf6b2cec0cc2dc994cdae3a61
parent 216527 688501a435ac6439b26baf02a560b102e50d91b1
child 216529 688a1864cd588fd6d63e98f9239878bd2797834b
push idunknown
push userunknown
push dateunknown
reviewerstbsaunde
bugs1056803, 100644
milestone34.0a1
Bug 1056803 - added nsiAccessibleObjectAttributeChangedEvent interface. Tests included. r=tbsaunde --- accessible/base/AccEvent.cpp | 8 +++++ accessible/base/AccEvent.h | 29 ++++++++++++++++- accessible/generic/DocAccessible.cpp | 8 +++-- accessible/interfaces/moz.build | 1 + .../nsIAccessibleObjectAttributeChangedEvent.idl | 21 ++++++++++++ accessible/tests/mochitest/common.js | 2 ++ accessible/tests/mochitest/events.js | 37 ++++++++++++++++++++++ .../tests/mochitest/events/test_aria_objattr.html | 7 ++-- accessible/xpcom/AccEvents.conf | 1 + 9 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl
accessible/base/AccEvent.cpp
accessible/base/AccEvent.h
accessible/generic/DocAccessible.cpp
accessible/interfaces/moz.build
accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl
accessible/tests/mochitest/common.js
accessible/tests/mochitest/events.js
accessible/tests/mochitest/events/test_aria_objattr.html
accessible/xpcom/AccEvents.conf
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -246,11 +246,19 @@ a11y::MakeXPCEvent(AccEvent* aEvent)
     xpEvent = new xpcAccVirtualCursorChangeEvent(type, acc, doc, domNode, fromUser,
                                                  vcc->OldAccessible(),
                                                  vcc->OldStartOffset(),
                                                  vcc->OldEndOffset(),
                                                  vcc->Reason());
     return xpEvent.forget();
   }
 
+  if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) {
+    AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent);
+    xpEvent = new xpcAccObjectAttributeChangedEvent(type, acc, doc, domNode,
+                                                    fromUser,
+                                                    oac->GetAttribute());
+    return xpEvent.forget();
+  }
+
   xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser);
   return xpEvent.forget();
   }
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -100,17 +100,18 @@ public:
     eMutationEvent,
     eReorderEvent,
     eHideEvent,
     eShowEvent,
     eCaretMoveEvent,
     eTextSelChangeEvent,
     eSelectionChangeEvent,
     eTableChangeEvent,
-    eVirtualCursorChangeEvent
+    eVirtualCursorChangeEvent,
+    eObjectAttrChangedEvent
   };
 
   static const EventGroup kEventGroup = eGenericEvent;
   virtual unsigned int GetEventGroups() const
   {
     return 1U << eGenericEvent;
   }
 
@@ -490,16 +491,42 @@ public:
 private:
   nsRefPtr<nsIAccessible> mOldAccessible;
   int32_t mOldStart;
   int32_t mOldEnd;
   int16_t mReason;
 };
 
 /**
+ * Accessible object attribute changed event.
+ */
+class AccObjectAttrChangedEvent: public AccEvent
+{
+public:
+  AccObjectAttrChangedEvent(Accessible* aAccessible, nsIAtom* aAttribute) :
+    AccEvent(::nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, aAccessible),
+    mAttribute(aAttribute) { }
+
+  // AccEvent
+  static const EventGroup kEventGroup = eObjectAttrChangedEvent;
+  virtual unsigned int GetEventGroups() const
+  {
+    return AccEvent::GetEventGroups() | (1U << eObjectAttrChangedEvent);
+  }
+
+  // AccObjectAttrChangedEvent
+  nsIAtom* GetAttribute() const { return mAttribute; }
+
+private:
+  nsCOMPtr<nsIAtom> mAttribute;
+
+  virtual ~AccObjectAttrChangedEvent() { }
+};
+
+/**
  * Downcast the generic accessible event object to derived type.
  */
 class downcast_accEvent
 {
 public:
   explicit downcast_accEvent(AccEvent* e) : mRawPtr(e) { }
 
   template<class Destination>
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1089,19 +1089,21 @@ DocAccessible::ARIAAttributeChanged(Acce
       new AccStateChangeEvent(aAccessible, states::EXPANDED);
     FireDelayedEvent(event);
     return;
   }
 
   // For aria attributes like drag and drop changes we fire a generic attribute
   // change event; at least until native API comes up with a more meaningful event.
   uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute);
-  if (!(attrFlags & ATTR_BYPASSOBJ))
-    FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
-                     aAccessible);
+  if (!(attrFlags & ATTR_BYPASSOBJ)) {
+    nsRefPtr<AccEvent> event =
+      new AccObjectAttrChangedEvent(aAccessible, aAttribute);
+    FireDelayedEvent(event);
+  }
 
   nsIContent* elm = aAccessible->GetContent();
 
   if (aAttribute == nsGkAtoms::aria_checked ||
       (aAccessible->IsButton() &&
        aAttribute == nsGkAtoms::aria_pressed)) {
     const uint64_t kState = (aAttribute == nsGkAtoms::aria_checked) ?
                             states::CHECKED : states::PRESSED;
--- a/accessible/interfaces/moz.build
+++ b/accessible/interfaces/moz.build
@@ -13,16 +13,17 @@ XPIDL_SOURCES += [
     'nsIAccessibleCaretMoveEvent.idl',
     'nsIAccessibleDocument.idl',
     'nsIAccessibleEditableText.idl',
     'nsIAccessibleEvent.idl',
     'nsIAccessibleHideEvent.idl',
     'nsIAccessibleHyperLink.idl',
     'nsIAccessibleHyperText.idl',
     'nsIAccessibleImage.idl',
+    'nsIAccessibleObjectAttributeChangedEvent.idl',
     'nsIAccessiblePivot.idl',
     'nsIAccessibleRelation.idl',
     'nsIAccessibleRetrieval.idl',
     'nsIAccessibleRole.idl',
     'nsIAccessibleSelectable.idl',
     'nsIAccessibleStateChangeEvent.idl',
     'nsIAccessibleStates.idl',
     'nsIAccessibleTable.idl',
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/nsIAccessibleObjectAttributeChangedEvent.idl
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIAccessibleEvent.idl"
+
+interface nsIAtom;
+
+/**
+ * Fired when an attribute of an accessible changes.
+ */
+[scriptable, builtinclass, uuid(4CA96609-23C8-4771-86E7-77C8B651CA24)]
+interface nsIAccessibleObjectAttributeChangedEvent : nsIAccessibleEvent
+{
+  /**
+   * Return the accessible attribute that changed.
+   */
+  readonly attribute nsIAtom changedAttribute;
+};
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -7,16 +7,18 @@ const nsIAccessibleEvent = Components.in
 const nsIAccessibleStateChangeEvent =
   Components.interfaces.nsIAccessibleStateChangeEvent;
 const nsIAccessibleCaretMoveEvent =
   Components.interfaces.nsIAccessibleCaretMoveEvent;
 const nsIAccessibleTextChangeEvent =
   Components.interfaces.nsIAccessibleTextChangeEvent;
 const nsIAccessibleVirtualCursorChangeEvent =
   Components.interfaces.nsIAccessibleVirtualCursorChangeEvent;
+const nsIAccessibleObjectAttributeChangedEvent =
+  Components.interfaces.nsIAccessibleObjectAttributeChangedEvent;
 
 const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
 const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
 const nsIAccessibleScrollType = Components.interfaces.nsIAccessibleScrollType;
 const nsIAccessibleCoordinateType = Components.interfaces.nsIAccessibleCoordinateType;
 
 const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation;
 const nsIAccessibleTextRange = Components.interfaces.nsIAccessibleTextRange;
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1769,16 +1769,53 @@ function textSelectionChecker(aID, aStar
       ok(true, "Collapsed selection triggered text selection change event.");
     } else {
       testTextGetSelection(aID, aStartOffset, aEndOffset, 0);
     }
   }
 }
 
 /**
+ * Object attribute changed checker
+ */
+function objAttrChangedChecker(aID, aAttr)
+{
+  this.__proto__ = new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, aID);
+
+  this.check = function objAttrChangedChecker_check(aEvent)
+  {
+    var event = null;
+    try {
+      var event = aEvent.QueryInterface(
+        nsIAccessibleObjectAttributeChangedEvent);
+    } catch (e) {
+      ok(false, "Object attribute changed event was expected");
+    }
+
+    if (!event) {
+      return;
+    }
+
+    is(event.changedAttribute.toString(), aAttr,
+      "Wrong attribute name of the object attribute changed event.");
+  };
+
+  this.match = function objAttrChangedChecker_match(aEvent)
+  {
+    if (aEvent instanceof nsIAccessibleObjectAttributeChangedEvent) {
+      var scEvent = aEvent.QueryInterface(
+        nsIAccessibleObjectAttributeChangedEvent);
+      return (aEvent.accessible == getAccessible(this.target)) &&
+        (scEvent.changedAttribute.toString() == aAttr);
+    }
+    return false;
+  };
+}
+
+/**
  * State change checker.
  */
 function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
                             aTargetOrFunc, aTargetFuncArg, aIsAsync,
                             aSkipCurrentStateCheck)
 {
   this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
                                       aTargetFuncArg, aIsAsync);
--- a/accessible/tests/mochitest/events/test_aria_objattr.html
+++ b/accessible/tests/mochitest/events/test_aria_objattr.html
@@ -15,35 +15,34 @@
           src="../events.js"></script>
 
   <script type="application/javascript">
 
     /**
      * Do tests.
      */
     var gQueue = null;
-
     function updateAttribute(aID, aAttr, aValue)
     {
       this.node = getNode(aID);
       this.accessible = getAccessible(this.node);
 
       this.eventSeq = [
-        new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, this.accessible),
+        new objAttrChangedChecker(aID, aAttr),
       ];
 
       this.invoke = function updateAttribute_invoke()
       {
         this.node.setAttribute(aAttr, aValue);
-      }
+      };
 
       this.getID = function updateAttribute_getID()
       {
         return aAttr + " for " + aID + " " + aValue;
-      }
+      };
     }
 
     // Debug stuff.
     // gA11yEventDumpID = "eventdump";
     //gA11yEventDumpToConsole = true;
 
     function doTests()
     {
--- a/accessible/xpcom/AccEvents.conf
+++ b/accessible/xpcom/AccEvents.conf
@@ -7,11 +7,12 @@
  and should be in nsIAccessible<name>.idl file"""
 
 simple_events = [
     'Event',
     'StateChangeEvent',
     'TextChangeEvent',
     'HideEvent',
     'CaretMoveEvent',
+    'ObjectAttributeChangedEvent',
     'TableChangeEvent',
     'VirtualCursorChangeEvent'
   ]