Web Inspector: AXI: clarify button roles (e.g. toggle or popup button)
https://bugs.webkit.org/show_bug.cgi?id=130726
<rdar://problem/16420420>

Patch by Aaron Chu <aaron_chu@apple.com> on 2016-11-10
Reviewed by Brian Burg.

Source/JavaScriptCore:

Add the isPopupButton flag to the AccessibilityProperties type.

* inspector/protocol/DOM.json:

Source/WebCore:

Test: accessibility/ax-differentiate-button-types.html

Added special case logic to make sure PopUpButtonRole and ToggleButtonRole to user ButtonRole as role.
Added an "isPopUpButton" property to be exposed to the Inspector's use.

* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::computedRoleString):
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::buildObjectForAccessibilityProperties):

Source/WebInspectorUI:

Updated Inspector to show the button type using the new mapping information.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Models/DOMNode.js:
(WebInspector.DOMNode.prototype.accessibilityProperties.accessibilityPropertiesCallback):
(WebInspector.DOMNode.prototype.accessibilityProperties):
* UserInterface/Views/DOMNodeDetailsSidebarPanel.js:
(WebInspector.DOMNodeDetailsSidebarPanel.prototype._refreshAccessibility.accessibilityPropertiesCallback):
(WebInspector.DOMNodeDetailsSidebarPanel.prototype._refreshAccessibility):

LayoutTests:

Updated related test cases.

* accessibility/roles-computedRoleString-expected.txt:
* accessibility/roles-computedRoleString.html:
* inspector/dom/getAccessibilityPropertiesForNode-expected.txt:
* inspector/dom/getAccessibilityPropertiesForNode.html:
* platform/mac/accessibility/roles-computedRoleString-expected.txt:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@208540 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index a0057a0..712af90 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,19 @@
+2016-11-10  Aaron Chu  <aaron_chu@apple.com>
+
+        Web Inspector: AXI: clarify button roles (e.g. toggle or popup button)
+        https://bugs.webkit.org/show_bug.cgi?id=130726
+        <rdar://problem/16420420>
+
+        Reviewed by Brian Burg.
+
+        Updated related test cases.
+
+        * accessibility/roles-computedRoleString-expected.txt:
+        * accessibility/roles-computedRoleString.html:
+        * inspector/dom/getAccessibilityPropertiesForNode-expected.txt:
+        * inspector/dom/getAccessibilityPropertiesForNode.html:
+        * platform/mac/accessibility/roles-computedRoleString-expected.txt:
+
 2016-11-10  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
diff --git a/LayoutTests/accessibility/roles-computedRoleString-expected.txt b/LayoutTests/accessibility/roles-computedRoleString-expected.txt
index d8b66cc..6e004f5 100644
--- a/LayoutTests/accessibility/roles-computedRoleString-expected.txt
+++ b/LayoutTests/accessibility/roles-computedRoleString-expected.txt
@@ -54,7 +54,7 @@
 PASS: section:not([aria-label]:not([aria-labelledby]) -> group. 
 PASS: section[aria-label] -> region. 
 PASS: section[aria-labelledby] -> region. 
-PASS: select:not([multiple]) -> . 
+PASS: select:not([multiple]) -> button. 
 PASS: select[multiple] -> listbox. 
 PASS: option -> option. 
 PASS: optgroup -> option. 
diff --git a/LayoutTests/accessibility/roles-computedRoleString.html b/LayoutTests/accessibility/roles-computedRoleString.html
index 856d56bd..daf14eb 100644
--- a/LayoutTests/accessibility/roles-computedRoleString.html
+++ b/LayoutTests/accessibility/roles-computedRoleString.html
@@ -82,7 +82,7 @@
 <section data-role="region" class="ex" aria-labelledby="section-label" data-note="[aria-labelledby]">
     <h2 id="section-label">X</h2>
 </section>
-<select data-role="" class="ex" data-note=":not([multiple])">
+<select data-role="button" class="ex" data-note=":not([multiple])">
     <option data-role="" class="ex">X</option>
     <optgroup data-role="" class="ex" label="more">
         <option data-role="" class="ex">X</option>
diff --git a/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode-expected.txt b/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode-expected.txt
index a26d66f..ec76a51 100644
--- a/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode-expected.txt
+++ b/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode-expected.txt
@@ -4,10 +4,10 @@
     exists: true
     label: 
     role: 
-    childNodeIds.length: 52
+    childNodeIds.length: 54
 
 
-Total elements to be tested: 81.
+Total elements to be tested: 83.
 
 <div onclick="void(0);">click</div>
     exists: true
@@ -296,6 +296,16 @@
     ownedNodeIds.length: 1
     required: false
 
+<select>
+    <option>FOO</option>
+</select>
+    exists: true
+    label: 
+    role: button
+    focused: false
+    required: false
+    isPopUpButton: true
+
 <option>not selected</option>
     exists: false
     label: 
@@ -527,6 +537,15 @@
     focused: false
     required: false
 
+<div role="button" tabindex="0" aria-haspopup="true">Popup Button.</div>
+    exists: true
+    label: Popup Button.
+    role: button
+    focused: false
+    parentNodeId: exists
+    required: false
+    isPopUpButton: true
+
 <input type="button">
     exists: true
     label: 
@@ -542,7 +561,7 @@
 <div role="button" tabindex="0" aria-pressed="false">Not Pressed.</div>
     exists: true
     label: Not Pressed.
-    role: 
+    role: button
     focused: false
     parentNodeId: exists
     pressed: false
@@ -551,7 +570,7 @@
 <div role="button" tabindex="0" aria-pressed="true">Pressed.</div>
     exists: true
     label: Pressed.
-    role: 
+    role: button
     focused: false
     parentNodeId: exists
     pressed: true
diff --git a/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode.html b/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode.html
index dce655a..5e4853e5 100644
--- a/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode.html
+++ b/LayoutTests/inspector/dom/getAccessibilityPropertiesForNode.html
@@ -45,6 +45,7 @@
 <div class="ex" role="button" tabindex="0" aria-pressed="false">Not Pressed.</div>
 <button class="ex"></button>
 <input class="ex" type="button">
+<div role="button" class="ex" tabindex="0" aria-haspopup="true">Popup Button.</div>
 
 <!-- FIXME: Inputs missing parentNodeId http://webkit.org/b/130181 -->
 <input class="ex">
@@ -90,6 +91,10 @@
     <option class="ex">not selected</option>
 </select>
 
+<select class="ex">
+    <option>FOO</option>
+</select>
+
 <input class="ex" role="combobox" aria-owns="ownedlistbox invalidIdRef" aria-controls="ownedlistbox invalidIdRef">
 <div role="listbox" class="ex" id="ownedlistbox">
     <div class="ex" role="option" aria-selected="true">selected</div>
diff --git a/LayoutTests/platform/mac/accessibility/roles-computedRoleString-expected.txt b/LayoutTests/platform/mac/accessibility/roles-computedRoleString-expected.txt
index 9c629f2..d581018 100644
--- a/LayoutTests/platform/mac/accessibility/roles-computedRoleString-expected.txt
+++ b/LayoutTests/platform/mac/accessibility/roles-computedRoleString-expected.txt
@@ -55,7 +55,7 @@
 PASS: section:not([aria-label]:not([aria-labelledby]) -> group. 
 PASS: section[aria-label] -> region. 
 PASS: section[aria-labelledby] -> region. 
-PASS: select:not([multiple]) -> . 
+PASS: select:not([multiple]) -> button. 
 PASS: select[multiple] -> listbox. 
 PASS: option -> option. 
 PASS: optgroup -> option. 
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 405a8da..afb07c6 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,15 @@
+2016-11-10  Aaron Chu  <aaron_chu@apple.com>
+
+        Web Inspector: AXI: clarify button roles (e.g. toggle or popup button)
+        https://bugs.webkit.org/show_bug.cgi?id=130726
+        <rdar://problem/16420420>
+
+        Reviewed by Brian Burg.
+
+        Add the isPopupButton flag to the AccessibilityProperties type.
+
+        * inspector/protocol/DOM.json:
+
 2016-11-10  Csaba Osztrogonác  <ossy@webkit.org>
 
         [ARM] Unreviewed buildfix after r208450.
diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json
index d44a977..a246336 100644
--- a/Source/JavaScriptCore/inspector/protocol/DOM.json
+++ b/Source/JavaScriptCore/inspector/protocol/DOM.json
@@ -98,6 +98,7 @@
                 { "name": "disabled", "type": "boolean", "optional": true, "description": "Disabled state of form controls." },
                 { "name": "headingLevel", "type": "number", "optional": true, "description": "Heading level of a heading element." },
                 { "name": "hierarchyLevel", "type": "number", "optional": true, "description": "The hierarchical level of an element." },
+                { "name": "isPopUpButton", "type": "boolean", "optional": true, "description": "Whether an element is a popup button." },
                 { "name": "exists", "type": "boolean", "description": "Indicates whether there is an existing AX object for the DOM node. If this is false, all the other properties will be default values." },
                 { "name": "expanded", "type": "boolean", "optional": true, "description": "Expanded state." },
                 { "name": "flowedNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of any nodes referenced via @aria-flowto." },
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index cb3e386..8120798 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,21 @@
+2016-11-10  Aaron Chu  <aaron_chu@apple.com>
+
+        Web Inspector: AXI: clarify button roles (e.g. toggle or popup button)
+        https://bugs.webkit.org/show_bug.cgi?id=130726
+        <rdar://problem/16420420>
+
+        Reviewed by Brian Burg.
+
+        Test: accessibility/ax-differentiate-button-types.html
+
+        Added special case logic to make sure PopUpButtonRole and ToggleButtonRole to user ButtonRole as role.
+        Added an "isPopUpButton" property to be exposed to the Inspector's use.
+
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::computedRoleString):
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::buildObjectForAccessibilityProperties):
+
 2016-11-10  Zan Dobersek  <zdobersek@igalia.com>
 
         [EME] Add no-op Web-facing APIs
diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp
index d794dc4..9a555a4 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityObject.cpp
@@ -2197,7 +2197,9 @@
     AccessibilityRole role = roleValue();
     if (role == HorizontalRuleRole)
         role = SplitterRole;
-    
+    if (role == PopUpButtonRole || role == ToggleButtonRole)
+        role = ButtonRole;
+
     return reverseAriaRoleMap().get(role);
 }
 
diff --git a/Source/WebCore/inspector/InspectorDOMAgent.cpp b/Source/WebCore/inspector/InspectorDOMAgent.cpp
index 0f8cbaf..d516a6a 100644
--- a/Source/WebCore/inspector/InspectorDOMAgent.cpp
+++ b/Source/WebCore/inspector/InspectorDOMAgent.cpp
@@ -1613,6 +1613,7 @@
     bool supportsPressed = false;
     bool supportsRequired = false;
     bool supportsFocused = false;
+    bool isPopupButton = false;
     int headingLevel = 0;
     unsigned hierarchicalLevel = 0;
     unsigned level = 0;
@@ -1794,6 +1795,7 @@
             hierarchicalLevel = axObject->hierarchicalLevel();
             
             level = hierarchicalLevel ? hierarchicalLevel : headingLevel;
+            isPopupButton = axObject->isPopUpButton() || axObject->ariaHasPopup();
         }
     }
     
@@ -1864,6 +1866,8 @@
             value->setHeadingLevel(level);
         else if (level)
             value->setHierarchyLevel(level);
+        if (isPopupButton)
+            value->setIsPopUpButton(isPopupButton);
     }
 
     return WTFMove(value);
diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog
index c8796e4..60838e0 100644
--- a/Source/WebInspectorUI/ChangeLog
+++ b/Source/WebInspectorUI/ChangeLog
@@ -1,3 +1,21 @@
+2016-11-10  Aaron Chu  <aaron_chu@apple.com>
+
+        Web Inspector: AXI: clarify button roles (e.g. toggle or popup button)
+        https://bugs.webkit.org/show_bug.cgi?id=130726
+        <rdar://problem/16420420>
+
+        Reviewed by Brian Burg.
+
+        Updated Inspector to show the button type using the new mapping information.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Models/DOMNode.js:
+        (WebInspector.DOMNode.prototype.accessibilityProperties.accessibilityPropertiesCallback):
+        (WebInspector.DOMNode.prototype.accessibilityProperties):
+        * UserInterface/Views/DOMNodeDetailsSidebarPanel.js:
+        (WebInspector.DOMNodeDetailsSidebarPanel.prototype._refreshAccessibility.accessibilityPropertiesCallback):
+        (WebInspector.DOMNodeDetailsSidebarPanel.prototype._refreshAccessibility):
+
 2016-11-09  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: DebuggerManager.Event.Resumed introduces test flakiness
diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
index 623ecff..002b757 100644
--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
@@ -28,8 +28,8 @@
 localizedStrings["%d matches"] = "%d matches";
 localizedStrings["%dpx"] = "%dpx";
 localizedStrings["%dpx²"] = "%dpx²";
-localizedStrings["%s (computed)"] = "%s (computed)";
-localizedStrings["%s (default)"] = "%s (default)";
+localizedStrings["%s (%s)"] = "%s (%s)";
+localizedStrings["%s (%s, %s)"] = "%s (%s, %s)";
 localizedStrings["%s (hidden)"] = "%s (hidden)";
 localizedStrings["%s Event Dispatched"] = "%s Event Dispatched";
 localizedStrings["%s Prototype"] = "%s Prototype";
@@ -183,6 +183,7 @@
 localizedStrings["Composite"] = "Composite";
 localizedStrings["Compressed"] = "Compressed";
 localizedStrings["Compression"] = "Compression";
+localizedStrings["computed"] = "computed";
 localizedStrings["Condition"] = "Condition";
 localizedStrings["Conditional expression"] = "Conditional expression";
 localizedStrings["Connection"] = "Connection";
@@ -238,6 +239,7 @@
 localizedStrings["Decoded"] = "Decoded";
 localizedStrings["Decoration"] = "Decoration";
 localizedStrings["Default"] = "Default";
+localizedStrings["default"] = "default";
 localizedStrings["Delay"] = "Delay";
 localizedStrings["Delete"] = "Delete";
 localizedStrings["Delete Breakpoint"] = "Delete Breakpoint";
@@ -577,6 +579,8 @@
 localizedStrings["Pause script execution (%s or %s)"] = "Pause script execution (%s or %s)";
 localizedStrings["Play Sound"] = "Play Sound";
 localizedStrings["Polite"] = "Polite";
+localizedStrings["popup"] = "popup";
+localizedStrings["popup, toggle"] = "popup, toggle";
 localizedStrings["Port"] = "Port";
 localizedStrings["Position"] = "Position";
 localizedStrings["Position X"] = "Position X";
@@ -778,6 +782,7 @@
 localizedStrings["Timer Removed"] = "Timer Removed";
 localizedStrings["Timestamp \u2014 %s"] = "Timestamp \u2014 %s";
 localizedStrings["Timing"] = "Timing";
+localizedStrings["toggle"] = "toggle";
 localizedStrings["Toggle Classes"] = "Toggle Classes";
 localizedStrings["Top"] = "Top";
 localizedStrings["Top Functions"] = "Top Functions";
diff --git a/Source/WebInspectorUI/UserInterface/Models/DOMNode.js b/Source/WebInspectorUI/UserInterface/Models/DOMNode.js
index 07da398..4e6f2cd 100644
--- a/Source/WebInspectorUI/UserInterface/Models/DOMNode.js
+++ b/Source/WebInspectorUI/UserInterface/Models/DOMNode.js
@@ -532,6 +532,7 @@
                     ignored: accessibilityProperties.ignored,
                     ignoredByDefault: accessibilityProperties.ignoredByDefault,
                     invalid: accessibilityProperties.invalid,
+                    isPopupButton: accessibilityProperties.isPopUpButton,
                     headingLevel: accessibilityProperties.headingLevel,
                     hierarchyLevel: accessibilityProperties.hierarchyLevel,
                     hidden: accessibilityProperties.hidden,
diff --git a/Source/WebInspectorUI/UserInterface/Views/DOMNodeDetailsSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/DOMNodeDetailsSidebarPanel.js
index b36cee4..8d95307 100644
--- a/Source/WebInspectorUI/UserInterface/Views/DOMNodeDetailsSidebarPanel.js
+++ b/Source/WebInspectorUI/UserInterface/Views/DOMNodeDetailsSidebarPanel.js
@@ -496,13 +496,38 @@
                 var required = booleanValueToLocalizedStringIfPropertyDefined("required");
 
                 var role = accessibilityProperties.role;
+                let hasPopup = accessibilityProperties.isPopupButton;
+                let roleType = null;
+                let buttonType = null;
+                let buttonTypePopupString = WebInspector.UIString("popup");
+                let buttonTypeToggleString = WebInspector.UIString("toggle")
+                let buttonTypePopupToggleString = WebInspector.UIString("popup, toggle")
+
                 if (role === "" || role === "unknown")
                     role = WebInspector.UIString("No exact ARIA role match.");
                 else if (role) {
+                    if (role === "button") {
+                        if (pressed)
+                            buttonType = buttonTypeToggleString;
+
+                        // In cases where an element is a toggle button, but it also has
+                        // aria-haspopup, we concatenate the button types. If it is just
+                        // a popup button, we only include "popup".
+                        if (hasPopup)
+                            buttonType = buttonType ? buttonTypePopupToggleString : buttonTypePopupString;
+                    }
+
                     if (!domNode.getAttribute("role"))
-                        role = WebInspector.UIString("%s (default)").format(role);
-                    else if (domNode.getAttribute("role") !== role)
-                        role = WebInspector.UIString("%s (computed)").format(role);
+                        roleType = WebInspector.UIString("default");
+                    else if (buttonType || domNode.getAttribute("role") !== role)
+                        roleType = WebInspector.UIString("computed");
+
+                    if (buttonType && roleType)
+                        role = WebInspector.UIString("%s (%s, %s)").format(role, buttonType, roleType);
+                    else if (roleType || buttonType) {
+                        let extraInfo = roleType || buttonType;
+                        role = WebInspector.UIString("%s (%s)").format(role, extraInfo);
+                    }
                 }
 
                 var selected = booleanValueToLocalizedStringIfTrue("selected");