AX: Meter: [Mac] Content in label element should be used as AXTitle or AXDescription
authorn_wang@apple.com <n_wang@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Sep 2016 15:13:00 +0000 (15:13 +0000)
committern_wang@apple.com <n_wang@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Sep 2016 15:13:00 +0000 (15:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162586

Reviewed by Chris Fleizach.

Source/WebCore:

Exposed the label element's text as AXDescription for meter elements.
Also refactored the code for fetching the label element's text and taken care of
the case where aria-label and aria-labelledby attributes are used on label elements.

Test: accessibility/mac/meter-with-label-element.html

* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::isLabelable):
(WebCore::AccessibilityNodeObject::textForLabelElement):
(WebCore::AccessibilityNodeObject::titleElementText):
(WebCore::AccessibilityNodeObject::title):
(WebCore::AccessibilityNodeObject::usesAltTagForTextComputation): Deleted.
* accessibility/AccessibilityNodeObject.h:
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::exposesTitleUIElement):

LayoutTests:

* accessibility/mac/aria-label-on-label-element-expected.txt:
* accessibility/mac/aria-label-on-label-element.html:
* accessibility/mac/meter-with-label-element-expected.txt: Added.
* accessibility/mac/meter-with-label-element.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@206581 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/accessibility/mac/aria-label-on-label-element-expected.txt
LayoutTests/accessibility/mac/aria-label-on-label-element.html
LayoutTests/accessibility/mac/meter-with-label-element-expected.txt [new file with mode: 0644]
LayoutTests/accessibility/mac/meter-with-label-element.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/accessibility/AccessibilityNodeObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp

index 6cb0141..1e2ffb7 100644 (file)
@@ -1,3 +1,15 @@
+2016-09-29  Nan Wang  <n_wang@apple.com>
+
+        AX: Meter: [Mac] Content in label element should be used as AXTitle or AXDescription
+        https://bugs.webkit.org/show_bug.cgi?id=162586
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/mac/aria-label-on-label-element-expected.txt:
+        * accessibility/mac/aria-label-on-label-element.html:
+        * accessibility/mac/meter-with-label-element-expected.txt: Added.
+        * accessibility/mac/meter-with-label-element.html: Added.
+
 2016-09-28  Chris Dumez  <cdumez@apple.com>
 
         Import touch-events web-platform-tests
index b2cd6d3..98e8ace 100644 (file)
@@ -1,4 +1,9 @@
 Some text  Some other text   
+aria
+
+labelledby
+
+Some text 
 This tests that the aria-label attribute works on element.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -8,6 +13,7 @@ PASS !titleUIElement1 is true
 PASS input1.title is 'AXTitle: aria label'
 PASS titleUIElement2.isEqual(accessibilityController.accessibleElementById('label2')) is true
 PASS input3.title is 'AXTitle: hidden aria label'
+PASS input4.title is 'AXTitle: aria labelledby'
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 5a91181..e8c3908 100644 (file)
 <label id="label3" for="input3" hidden aria-label="hidden aria label">hidden text</label>
 <input id="input3" type="text">
 
+<p id="p1">aria</p>
+<p id="p2">labelledby</p>
+<label for="input4" aria-labelledby="p1 p2">Some text</label>
+<input id="input4" type="text" size=20>
+
 <p id="description"></p>
 <div id="console"></div>
 
         // Make sure when the input element has no rendered label, it won't cause crash.
         var input3 = accessibilityController.accessibleElementById("input3");
         shouldBe("input3.title", "'AXTitle: hidden aria label'");
+        
+        // aria-labelledby also works.
+        var input4 = accessibilityController.accessibleElementById("input4");
+        shouldBe("input4.title", "'AXTitle: aria labelledby'");
     }
 
 </script>
diff --git a/LayoutTests/accessibility/mac/meter-with-label-element-expected.txt b/LayoutTests/accessibility/mac/meter-with-label-element-expected.txt
new file mode 100644 (file)
index 0000000..2f348ab
--- /dev/null
@@ -0,0 +1,19 @@
+label  label wrapping meter label 
+aria
+
+labelledby
+
+label
+This tests that for meter elements, the label element should be used as accessible name.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS meter1.description is 'AXDescription: label'
+PASS meter2.description is 'AXDescription: label wrapping meter'
+PASS meter3.description is 'AXDescription: aria label'
+PASS meter4.description is 'AXDescription: aria labelledby'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/accessibility/mac/meter-with-label-element.html b/LayoutTests/accessibility/mac/meter-with-label-element.html
new file mode 100644 (file)
index 0000000..0861c59
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<label for="meter">label</label>
+<meter id="meter" min="0" max="100" value="83.5"></meter>
+
+<label>label wrapping meter<meter id="meter2" min="0" max="100" value="83.5"></meter></label>
+
+<label for="meter3" aria-label="aria label">label</label>
+<meter id="meter3" min="0" max="100" value="83.5"></meter>
+
+<p id="p1">aria</p>
+<p id="p2">labelledby</p>
+<label aria-labelledby="p1 p2">label<meter id="meter4" min="0" max="100" value="83.5"></meter></label>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+    description("This tests that for meter elements, the label element should be used as accessible name.");
+
+    if (window.accessibilityController) {
+
+          var meter1 = accessibilityController.accessibleElementById("meter");
+          shouldBe("meter1.description", "'AXDescription: label'");
+
+          var meter2 = accessibilityController.accessibleElementById("meter2");
+          shouldBe("meter2.description", "'AXDescription: label wrapping meter'");
+          
+          var meter3 = accessibilityController.accessibleElementById("meter3");
+          shouldBe("meter3.description", "'AXDescription: aria label'");
+          
+          var meter4 = accessibilityController.accessibleElementById("meter4");
+          shouldBe("meter4.description", "'AXDescription: aria labelledby'");
+    }
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index b52797d..e10465f 100644 (file)
@@ -1,3 +1,26 @@
+2016-09-29  Nan Wang  <n_wang@apple.com>
+
+        AX: Meter: [Mac] Content in label element should be used as AXTitle or AXDescription
+        https://bugs.webkit.org/show_bug.cgi?id=162586
+
+        Reviewed by Chris Fleizach.
+
+        Exposed the label element's text as AXDescription for meter elements.
+        Also refactored the code for fetching the label element's text and taken care of 
+        the case where aria-label and aria-labelledby attributes are used on label elements. 
+
+        Test: accessibility/mac/meter-with-label-element.html
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::isLabelable):
+        (WebCore::AccessibilityNodeObject::textForLabelElement):
+        (WebCore::AccessibilityNodeObject::titleElementText):
+        (WebCore::AccessibilityNodeObject::title):
+        (WebCore::AccessibilityNodeObject::usesAltTagForTextComputation): Deleted.
+        * accessibility/AccessibilityNodeObject.h:
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::exposesTitleUIElement):
+
 2016-09-29  Romain Bellessort  <romain.bellessort@crf.canon.fr>
 
         [Streams API] Improve ReadableStreamDefaultController.h/cpp
index 86cf6ab..e10ec15 100644 (file)
@@ -1230,6 +1230,33 @@ bool AccessibilityNodeObject::usesAltTagForTextComputation() const
 {
     return isImage() || isInputImage() || isNativeImage() || isCanvas() || (node() && node()->hasTagName(imgTag));
 }
+
+bool AccessibilityNodeObject::isLabelable() const
+{
+    Node* node = this->node();
+    if (!node)
+        return false;
+    
+    return is<HTMLInputElement>(*node) || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl() || isProgressIndicator() || isMeter();
+}
+
+String AccessibilityNodeObject::textForLabelElement(Element* element) const
+{
+    String result = String();
+    if (!is<HTMLLabelElement>(*element))
+        return result;
+    
+    HTMLLabelElement* label = downcast<HTMLLabelElement>(element);
+    // Check to see if there's aria-labelledby attribute on the label element.
+    if (AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label))
+        result = labelObject->ariaLabeledByAttribute();
+    
+    // Then check for aria-label attribute.
+    if (result.isEmpty())
+        result = label->attributeWithoutSynchronization(aria_labelAttr);
+    
+    return !result.isEmpty() ? result : label->innerText();
+}
     
 void AccessibilityNodeObject::titleElementText(Vector<AccessibilityText>& textOrder) const
 {
@@ -1237,19 +1264,14 @@ void AccessibilityNodeObject::titleElementText(Vector<AccessibilityText>& textOr
     if (!node)
         return;
     
-    bool isInputTag = is<HTMLInputElement>(*node);
-    if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl() || isProgressIndicator()) {
+    if (isLabelable()) {
         if (HTMLLabelElement* label = labelForElement(downcast<Element>(node))) {
             AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label);
-            String innerText = label->innerText();
-            
-            const AtomicString& ariaLabel = label->attributeWithoutSynchronization(aria_labelAttr);
-            if (!ariaLabel.isEmpty())
-                innerText = ariaLabel;
+            String innerText = textForLabelElement(label);
             
             // Only use the <label> text if there's no ARIA override.
             if (!innerText.isEmpty() && !ariaAccessibilityDescription())
-                textOrder.append(AccessibilityText(innerText, LabelByElementText, labelObject));
+                textOrder.append(AccessibilityText(innerText, isMeter() ? AlternativeText : LabelByElementText, labelObject));
             return;
         }
     }
@@ -1710,11 +1732,11 @@ String AccessibilityNodeObject::title() const
             return input.valueWithDefault();
     }
 
-    if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl() || isProgressIndicator()) {
+    if (isLabelable()) {
         HTMLLabelElement* label = labelForElement(downcast<Element>(node));
         // Use the label text as the title if 1) the title element is NOT an exposed element and 2) there's no ARIA override.
         if (label && !exposesTitleUIElement() && !ariaAccessibilityDescription().length())
-            return label->innerText();
+            return textForLabelElement(label);
     }
 
     // If this node isn't rendered, there's no inner text we can extract from a select element.
index 6fe7143..28ec1f0 100644 (file)
@@ -183,7 +183,9 @@ protected:
     void changeValueByStep(bool increase);
     // This returns true if it's focusable but it's not content editable and it's not a control or ARIA control.
     bool isGenericFocusableElement() const;
+    bool isLabelable() const;
     HTMLLabelElement* labelForElement(Element*) const;
+    String textForLabelElement(Element*) const;
     String ariaAccessibilityDescription() const;
     void ariaLabeledByElements(Vector<Element*>& elements) const;
     String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
index 466c52f..96fd240 100644 (file)
@@ -1057,12 +1057,16 @@ bool AccessibilityRenderObject::exposesTitleUIElement() const
     if (hasTextAlternative())
         return false;
     
-    // When <label> element has aria-label on it, we shouldn't expose it as the titleUIElement,
-    // otherwise its inner text will be announced by a screenreader.
-    if (is<HTMLInputElement>(*this->node()) || AccessibilityObject::isARIAInput(ariaRoleAttribute())) {
+    // When <label> element has aria-label or aria-labelledby on it, we shouldn't expose it as the
+    // titleUIElement, otherwise its inner text will be announced by a screenreader.
+    if (isLabelable()) {
         if (HTMLLabelElement* label = labelForElement(downcast<Element>(node()))) {
             if (!label->attributeWithoutSynchronization(aria_labelAttr).isEmpty())
                 return false;
+            if (AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label)) {
+                if (!labelObject->ariaLabeledByAttribute().isEmpty())
+                    return false;
+            }
         }
     }