Bug 1239051 - Labels should expose labeled controllers action. r=tbsaunde
authorEitan Isaacson <eitan@monotonous.org>
Thu, 14 Jan 2016 12:37:15 -0800
changeset 317064 152e692692f59d5d5eddeb6fc7214ce081397b6d
parent 317063 349d3d8a41d9ef387919f02d82174ae50ce7c3bd
child 317065 85224fb4d75ba1adb0e45ab44ef390aacd6af3d7
push id1079
push userjlund@mozilla.com
push dateFri, 15 Apr 2016 21:02:33 +0000
treeherdermozilla-release@575fbf6786d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs1239051
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1239051 - Labels should expose labeled controllers action. r=tbsaunde
accessible/base/nsCoreUtils.cpp
accessible/base/nsCoreUtils.h
accessible/generic/BaseAccessibles.cpp
accessible/generic/BaseAccessibles.h
accessible/html/HTMLElementAccessibles.cpp
accessible/html/HTMLElementAccessibles.h
accessible/tests/mochitest/actions/test_general.html
accessible/tests/mochitest/actions/test_general.xul
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -29,24 +29,35 @@
 #include "nsView.h"
 #include "nsGkAtoms.h"
 
 #include "nsComponentManagerUtils.h"
 
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLLabelElement.h"
 
 using namespace mozilla;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsCoreUtils
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
+nsCoreUtils::IsLabelWithControl(nsIContent* aContent)
+{
+  dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(aContent);
+  if (label && label->GetControl())
+    return true;
+
+  return false;
+}
+
+bool
 nsCoreUtils::HasClickListener(nsIContent *aContent)
 {
   NS_ENSURE_TRUE(aContent, false);
   EventListenerManager* listenerManager =
     aContent->GetExistingListenerManager();
 
   return listenerManager &&
     (listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -24,16 +24,21 @@ class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils
 {
 public:
   /**
+   * Return true if the given node is a label of a control.
+   */
+  static bool IsLabelWithControl(nsIContent *aContent);
+
+  /**
    * Return true if the given node has registered click, mousedown or mouseup
    * event listeners.
    */
   static bool HasClickListener(nsIContent *aContent);
 
   /**
    * Dispatch click event to XUL tree cell.
    *
--- a/accessible/generic/BaseAccessibles.cpp
+++ b/accessible/generic/BaseAccessibles.cpp
@@ -110,30 +110,34 @@ LinkableAccessible::Value(nsString& aVal
   if (isLink) {
     actionAcc->Value(aValue);
   }
 }
 
 uint8_t
 LinkableAccessible::ActionCount()
 {
-  bool isLink, isOnclick;
-  ActionWalk(&isLink, &isOnclick);
-  return (isLink || isOnclick) ? 1 : 0;
+  bool isLink, isOnclick, isLabelWithControl;
+  ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
+  return (isLink || isOnclick || isLabelWithControl) ? 1 : 0;
 }
 
 Accessible*
-LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
+LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick,
+                               bool* aIsLabelWithControl)
 {
   if (aIsOnclick) {
     *aIsOnclick = false;
   }
   if (aIsLink) {
     *aIsLink = false;
   }
+  if (aIsLabelWithControl) {
+    *aIsLabelWithControl = false;
+  }
 
   if (nsCoreUtils::HasClickListener(mContent)) {
     if (aIsOnclick) {
       *aIsOnclick = true;
     }
     return nullptr;
   }
 
@@ -150,32 +154,39 @@ LinkableAccessible::ActionWalk(bool* aIs
     }
 
     if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
       if (aIsOnclick) {
         *aIsOnclick = true;
       }
       return walkUpAcc;
     }
+
+    if (nsCoreUtils::IsLabelWithControl(walkUpAcc->GetContent())) {
+      if (aIsLabelWithControl) {
+        *aIsLabelWithControl = true;
+      }
+      return walkUpAcc;
+    }
   }
   return nullptr;
 }
 
 void
 LinkableAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 {
   aName.Truncate();
 
   // Action 0 (default action): Jump to link
   if (aIndex == eAction_Jump) {
-    bool isOnclick, isLink;
-    ActionWalk(&isLink, &isOnclick);
+    bool isOnclick, isLink, isLabelWithControl;
+    ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
     if (isLink) {
       aName.AssignLiteral("jump");
-    } else if (isOnclick) {
+    } else if (isOnclick || isLabelWithControl) {
       aName.AssignLiteral("click");
     }
   }
 }
 
 bool
 LinkableAccessible::DoAction(uint8_t aIndex)
 {
--- a/accessible/generic/BaseAccessibles.h
+++ b/accessible/generic/BaseAccessibles.h
@@ -71,17 +71,18 @@ public:
   // ActionAccessible
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t index) override;
   virtual KeyBinding AccessKey() const override;
 
   // ActionAccessible helpers
   Accessible* ActionWalk(bool* aIsLink = nullptr,
-                          bool* aIsOnclick = nullptr);
+                         bool* aIsOnclick = nullptr,
+                         bool* aIsLabelWithControl = nullptr);
   // HyperLinkAccessible
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex) override;
 
 protected:
   virtual ~LinkableAccessible() {}
 
 };
 
--- a/accessible/html/HTMLElementAccessibles.cpp
+++ b/accessible/html/HTMLElementAccessibles.cpp
@@ -70,16 +70,42 @@ HTMLLabelAccessible::RelationByType(Rela
   if (aType == RelationType::LABEL_FOR) {
     dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(mContent);
     rel.AppendTarget(mDoc, label->GetControl());
   }
 
   return rel;
 }
 
+uint8_t
+HTMLLabelAccessible::ActionCount()
+{
+  return nsCoreUtils::IsLabelWithControl(mContent) ? 1 : 0;
+}
+
+void
+HTMLLabelAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
+{
+  if (aIndex == 0) {
+    if (nsCoreUtils::IsLabelWithControl(mContent))
+      aName.AssignLiteral("click");
+  }
+}
+
+bool
+HTMLLabelAccessible::DoAction(uint8_t aIndex)
+{
+  if (aIndex != 0)
+    return false;
+
+  DoCommand();
+  return true;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLOuputAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS_INHERITED0(HTMLOutputAccessible, HyperTextAccessible)
 
 Relation
 HTMLOutputAccessible::RelationByType(RelationType aType)
--- a/accessible/html/HTMLElementAccessibles.h
+++ b/accessible/html/HTMLElementAccessibles.h
@@ -57,16 +57,21 @@ public:
   HTMLLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) :
     HyperTextAccessibleWrap(aContent, aDoc) {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
   virtual Relation RelationByType(RelationType aType) override;
 
+  // ActionAccessible
+  virtual uint8_t ActionCount() override;
+  virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
+  virtual bool DoAction(uint8_t aIndex) override;
+
 protected:
   virtual ~HTMLLabelAccessible() {}
   virtual ENameValueFlag NativeName(nsString& aName) override;
 };
 
 /**
  * Used for HTML output element.
  */
--- a/accessible/tests/mochitest/actions/test_general.html
+++ b/accessible/tests/mochitest/actions/test_general.html
@@ -34,21 +34,29 @@
           ID: "li_clickable3",
           actionName: "click",
           events: CLICK_EVENTS
         },
         {
           ID: "onclick_img",
           actionName: "click",
           events: CLICK_EVENTS
+        },
+        {
+          ID: "label1",
+          actionName: "click",
+          events: CLICK_EVENTS
         }
+
       ];
 
       testActions(actionsArray);
 
+      is(getAccessible("label1").firstChild.actionCount, 1, "label text should have 1 action");
+
       getAccessible("onclick_img").takeFocus();
       is(getAccessible("link1").actionCount, 1, "links should have one action");
       is(getAccessible("link2").actionCount, 1, "link with onclick handler should have 1 action");
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
@@ -82,10 +90,18 @@
     <li id="li_clickable3" onmouseup="">Clickable list item</li>
   </ul>
 
   <!-- linkable accessibles -->
   <img id="onclick_img" onclick="" src="../moz.png">
 
   <a id="link1" href="www">linkable textleaf accessible</a>
   <div id="link2" onclick="">linkable textleaf accessible</div>
+
+  <div>
+    <label for="TextBox_t2" id="label1">
+      <span>Explicit</span>
+    </label>
+    <input name="in2" id="TextBox_t2" type="text" maxlength="17">
+  </div>
+
 </body>
 </html>
--- a/accessible/tests/mochitest/actions/test_general.xul
+++ b/accessible/tests/mochitest/actions/test_general.xul
@@ -56,27 +56,34 @@
           events: XUL_EVENTS
         },
         {
           ID: "buttonmenu",
           actionName: "press",
           events: CLICK_EVENTS
         },
         {
+          ID: "name_entry_label",
+          actionName: "click",
+          events: CLICK_EVENTS
+        },
+        {
           ID: "labelWithPopup",
           actionName: "click",
           events: CLICK_EVENTS
         }/*, // XXX: bug 490288
         {
           ID: "buttonmenu_item",
           actionName: "click",
           events: CLICK_EVENTS
         }*/
       ];
 
+      is(getAccessible("name_entry_label").firstChild.actionCount, 1, "label text should have 1 action");
+
       testActions(actionsArray);
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
@@ -120,12 +127,16 @@
           <menuitem label="item1" id="buttonmenu_item"/>
           <menuitem label="item1"/>
         </menupopup>
       </button>
 
       <label id="labelWithPopup" value="file name"
              popup="fileContext"
              tabindex="0"/>
+      <hbox>
+        <label id="name_entry_label" value="Name" control="name_entry"/>
+        <textbox id="name_entry"/>
+      </hbox>
     </vbox>
   </hbox>
 </window>