[ATK] Expose aria-describedby with ATK_RELATION_DESCRIBED_BY
authork.czech@samsung.com <k.czech@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Jan 2014 13:16:27 +0000 (13:16 +0000)
committerk.czech@samsung.com <k.czech@samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Jan 2014 13:16:27 +0000 (13:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=121684

Reviewed by Mario Sanchez Prada.

Source/WebCore:

Exposed aria-describedby by ATK_RELATION_DESCRIBED_BY.
Moved elementsFromAttribut to AccessibilityObject to have common interface
for AccessibilityNodeObject and AccessibilityRenderObject. Implemented
supportsARIADescribedBy and ariaDescribedByElements to better deal with aria-describedby attribute.

No new tests. Covered by existed one.

* accessibility/AccessibilityNodeObject.cpp:
* accessibility/AccessibilityNodeObject.h:
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::elementsFromAttribute):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::supportsARIADescribedBy):
(WebCore::AccessibilityObject::ariaDescribedByElements):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::supportsARIADescribedBy):
(WebCore::AccessibilityRenderObject::ariaDescribedByElements):
* accessibility/AccessibilityRenderObject.h:
* accessibility/atk/WebKitAccessibleWrapperAtk.cpp:
(setAtkRelationSetFromCoreObject):

Tools:

Implementing helpText by using relation ATK_RELATION_DESCRIBED_BY.

* DumpRenderTree/atk/AccessibilityUIElementAtk.cpp:
(AccessibilityUIElement::helpText):
* WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp:
(WTR::AccessibilityUIElement::helpText):

LayoutTests:

Slightly extended test so that it could test aria-describedby with multiple id references.

* accessibility/aria-describedby-on-input-expected.txt:
* accessibility/aria-describedby-on-input.html:
* platform/efl/TestExpectations:
* platform/gtk/TestExpectations:

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/accessibility/aria-describedby-on-input-expected.txt
LayoutTests/accessibility/aria-describedby-on-input.html
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/gtk/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/accessibility/AccessibilityNodeObject.h
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h
Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
Tools/ChangeLog
Tools/DumpRenderTree/atk/AccessibilityUIElementAtk.cpp
Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp

index b3a8e91..0953c0e 100644 (file)
@@ -1,3 +1,17 @@
+2014-01-29  Krzysztof Czech  <k.czech@samsung.com>
+
+        [ATK] Expose aria-describedby with ATK_RELATION_DESCRIBED_BY
+        https://bugs.webkit.org/show_bug.cgi?id=121684
+
+        Reviewed by Mario Sanchez Prada.
+
+        Slightly extended test so that it could test aria-describedby with multiple id references.
+
+        * accessibility/aria-describedby-on-input-expected.txt:
+        * accessibility/aria-describedby-on-input.html:
+        * platform/efl/TestExpectations:
+        * platform/gtk/TestExpectations:
+
 2014-01-29  Sergio Villar Senin  <svillar@igalia.com>
 
         [CSS Grid Layout] minmax() should be a CSSFunction instead of a CSSValueList
index 136d469..c72e146 100644 (file)
@@ -1,4 +1,5 @@
 This computer will self-destruct in   minutes.
-Allows you to specify the number of minutes after which the computer will self-destruct.
+Allows you to specify the number of minutes after
+which the computer will self-destruct.
 
 The accessibility description is "AXHelp: Allows you to specify the number of minutes after which the computer will self-destruct."
index f6d3279..97fd94a 100644 (file)
@@ -5,9 +5,10 @@
 </script>
 <body>
     <span id="message">This computer will self-destruct in</span>
-    <input id="time" type="text" value="10" aria-describedby="description"/>
+    <input id="time" type="text" value="10" aria-describedby="description1 description2"/>
     <span id="unit"> minutes.</span>
-    <div id="description">Allows you to specify the number of minutes after which the computer will self-destruct.</div>
+    <div id="description1">Allows you to specify the number of minutes after</div>
+    <div id="description2">which the computer will self-destruct.</div>
     <div id="result"></div>
     
     <script>
index 61088e4..d744ce6 100644 (file)
@@ -1433,7 +1433,6 @@ webkit.org/b/106316 accessibility/render-counter-text.html [ Failure ]
 # New accessibility test added in r149155 is failing. Has been moved to the mac port in r155603.
 webkit.org/b/115659 accessibility/meter-element.html [ Missing ]
 
-webkit.org/b/121684 accessibility/aria-describedby-on-input.html [ Failure ]
 webkit.org/b/121593 accessibility/radio-button-title-label.html [ Failure ]
 
 # Newly added test at r139111 is failing.
index 741f148..5930316 100644 (file)
@@ -949,7 +949,6 @@ webkit.org/b/73766 css3/unicode-bidi-isolate-aharon-failing.html [ ImageOnlyFail
 
 webkit.org/b/79757 fast/selectors/selection-window-inactive.html [ ImageOnlyFailure ]
 
-webkit.org/b/121684 accessibility/aria-describedby-on-input.html [ Failure ]
 webkit.org/b/98357 accessibility/aria-readonly.html [ Failure ]
 webkit.org/b/98359 accessibility/aria-text-role.html [ Failure ]
 webkit.org/b/98363 accessibility/canvas-fallback-content-2.html [ Failure ]
index 75caf05..8bb2d15 100644 (file)
@@ -1,3 +1,31 @@
+2014-01-29  Krzysztof Czech  <k.czech@samsung.com>
+
+        [ATK] Expose aria-describedby with ATK_RELATION_DESCRIBED_BY
+        https://bugs.webkit.org/show_bug.cgi?id=121684
+
+        Reviewed by Mario Sanchez Prada.
+
+        Exposed aria-describedby by ATK_RELATION_DESCRIBED_BY.
+        Moved elementsFromAttribut to AccessibilityObject to have common interface
+        for AccessibilityNodeObject and AccessibilityRenderObject. Implemented
+        supportsARIADescribedBy and ariaDescribedByElements to better deal with aria-describedby attribute.
+
+        No new tests. Covered by existed one.
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        * accessibility/AccessibilityNodeObject.h:
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::elementsFromAttribute):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::supportsARIADescribedBy):
+        (WebCore::AccessibilityObject::ariaDescribedByElements):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::supportsARIADescribedBy):
+        (WebCore::AccessibilityRenderObject::ariaDescribedByElements):
+        * accessibility/AccessibilityRenderObject.h:
+        * accessibility/atk/WebKitAccessibleWrapperAtk.cpp:
+        (setAtkRelationSetFromCoreObject):
+
 2014-01-29  Sergio Villar Senin  <svillar@igalia.com>
 
         [CSS Grid Layout] minmax() should be a CSSFunction instead of a CSSValueList
index df3ab87..8969dba 100644 (file)
@@ -1892,32 +1892,6 @@ String AccessibilityNodeObject::ariaDescribedByAttribute() const
     return accessibilityDescriptionForElements(elements);
 }
 
-void AccessibilityNodeObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
-{
-    Node* node = this->node();
-    if (!node || !node->isElementNode())
-        return;
-
-    TreeScope& treeScope = node->treeScope();
-
-    String idList = getAttribute(attribute).string();
-    if (idList.isEmpty())
-        return;
-
-    idList.replace('\n', ' ');
-    Vector<String> idVector;
-    idList.split(' ', idVector);
-
-    unsigned size = idVector.size();
-    for (unsigned i = 0; i < size; ++i) {
-        AtomicString idName(idVector[i]);
-        Element* idElement = treeScope.getElementById(idName);
-        if (idElement)
-            elements.append(idElement);
-    }
-}
-
-
 void AccessibilityNodeObject::ariaLabeledByElements(Vector<Element*>& elements) const
 {
     elementsFromAttribute(elements, aria_labelledbyAttr);
index adab3be..28fad80 100644 (file)
@@ -182,7 +182,6 @@ protected:
     String ariaAccessibilityDescription() const;
     void ariaLabeledByElements(Vector<Element*>& elements) const;
     String accessibilityDescriptionForElements(Vector<Element*> &elements) const;
-    void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName&) const;
     virtual LayoutRect boundingBoxRect() const override;
     virtual String ariaDescribedByAttribute() const override;
     
index 8e6d395..2fdd417 100644 (file)
@@ -2123,4 +2123,26 @@ bool AccessibilityObject::accessibilityIsIgnored() const
     return result;
 }
 
+void AccessibilityObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const
+{
+    Node* node = this->node();
+    if (!node || !node->isElementNode())
+        return;
+
+    TreeScope& treeScope = node->treeScope();
+
+    String idList = getAttribute(attribute).string();
+    if (idList.isEmpty())
+        return;
+
+    idList.replace('\n', ' ');
+    Vector<String> idVector;
+    idList.split(' ', idVector);
+
+    for (auto idName : idVector) {
+        if (Element* idElement = treeScope.getElementById(idName))
+            elements.append(idElement);
+    }
+}
+
 } // namespace WebCore
index 959fbca..390ae2f 100644 (file)
@@ -553,6 +553,8 @@ public:
     virtual void ariaOwnsElements(AccessibilityChildrenVector&) const { }
     virtual bool supportsARIAFlowTo() const { return false; }
     virtual void ariaFlowToElements(AccessibilityChildrenVector&) const { }
+    virtual bool supportsARIADescribedBy() const { return false; }
+    virtual void ariaDescribedByElements(AccessibilityChildrenVector&) const { }
     virtual bool ariaHasPopup() const { return false; }
     virtual bool ariaPressedIsPresent() const;
     bool ariaIsMultiline() const;
@@ -627,6 +629,8 @@ public:
     virtual String ariaDescribedByAttribute() const { return String(); }
     const AtomicString& placeholderValue() const;
 
+    void elementsFromAttribute(Vector<Element*>&, const QualifiedName&) const;
+
     // Only if isColorWell()
     virtual void colorValue(int& r, int& g, int& b) const { r = 0; g = 0; b = 0; }
 
index 60d0899..80e5942 100644 (file)
@@ -1028,7 +1028,24 @@ void AccessibilityRenderObject::ariaFlowToElements(AccessibilityChildrenVector&
     }
         
 }
-    
+
+bool AccessibilityRenderObject::supportsARIADescribedBy() const
+{
+    return !getAttribute(aria_describedbyAttr).isEmpty();
+}
+
+void AccessibilityRenderObject::ariaDescribedByElements(AccessibilityChildrenVector& ariaDescribedBy) const
+{
+    Vector<Element*> elements;
+    elementsFromAttribute(elements, aria_describedbyAttr);
+
+    AXObjectCache* cache = axObjectCache();
+    for (const auto& element : elements) {
+        if (AccessibilityObject* describedByElement = cache->getOrCreate(element))
+            ariaDescribedBy.append(describedByElement);
+    }
+}
+
 bool AccessibilityRenderObject::supportsARIADropping() const 
 {
     const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr);
index 0b020fc..3902fb8 100644 (file)
@@ -180,6 +180,8 @@ public:
     virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const override;
     virtual bool supportsARIAFlowTo() const override;
     virtual void ariaFlowToElements(AccessibilityChildrenVector&) const override;
+    virtual bool supportsARIADescribedBy() const override;
+    virtual void ariaDescribedByElements(AccessibilityChildrenVector&) const override;
     virtual bool ariaHasPopup() const override;
 
     virtual bool supportsARIADropping() const override;
index 3909dac..ece59cc 100644 (file)
@@ -245,6 +245,15 @@ static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, Atk
         for (const auto& accessibilityObject : ariaFlowToElements)
             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, accessibilityObject->wrapper());
     }
+
+    // Check whether object supports aria-describedby. It provides an additional information for the user.
+    if (coreObject->supportsARIADescribedBy()) {
+        removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIBED_BY);
+        AccessibilityObject::AccessibilityChildrenVector ariaDescribedByElements;
+        coreObject->ariaDescribedByElements(ariaDescribedByElements);
+        for (const auto& accessibilityObject : ariaDescribedByElements)
+            atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY, accessibilityObject->wrapper());
+    }
 }
 
 static gpointer webkitAccessibleParentClass = 0;
index 9179e4e..d1e3099 100644 (file)
@@ -1,3 +1,17 @@
+2014-01-29  Krzysztof Czech  <k.czech@samsung.com>
+
+        [ATK] Expose aria-describedby with ATK_RELATION_DESCRIBED_BY
+        https://bugs.webkit.org/show_bug.cgi?id=121684
+
+        Reviewed by Mario Sanchez Prada.
+
+        Implementing helpText by using relation ATK_RELATION_DESCRIBED_BY.
+
+        * DumpRenderTree/atk/AccessibilityUIElementAtk.cpp:
+        (AccessibilityUIElement::helpText):
+        * WebKitTestRunner/InjectedBundle/atk/AccessibilityUIElementAtk.cpp:
+        (WTR::AccessibilityUIElement::helpText):
+
 2014-01-27  Chris Fleizach  <cfleizach@apple.com>
 
         AX: Support @scope in HTML tables
index adc84db..41317bd 100644 (file)
@@ -803,10 +803,37 @@ JSStringRef AccessibilityUIElement::language()
 
 JSStringRef AccessibilityUIElement::helpText() const
 {
-    // FIXME: We need to provide a proper implementation for this that does
-    // not depend on Mac specific concepts such as ATK_RELATION_DESCRIBED_BY,
-    // once it's implemented (see http://webkit.org/b/121684).
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_OBJECT(m_element))
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element));
+    if (!relationSet)
+        return nullptr;
+
+    AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
+    if (!relation)
+        return nullptr;
+
+    GPtrArray* targetList = atk_relation_get_target(relation);
+    if (!targetList || !targetList->len)
+        return nullptr;
+
+    StringBuilder builder;
+    builder.append("AXHelp: ");
+
+    for (int targetCount = 0; targetCount < targetList->len; targetCount++) {
+        if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
+            GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
+            if (!builder.isEmpty())
+                builder.append(" ");
+            builder.append(text.get());
+        }
+    }
+
+    g_object_unref(relationSet);
+
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
+
 }
 
 double AccessibilityUIElement::x()
index 3e6a845..d787dbc 100644 (file)
@@ -972,10 +972,36 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
 {
-    // FIXME: We need to provide a proper implementation for this that does
-    // not depend on Mac specific concepts such as ATK_RELATION_DESCRIBED_BY,
-    // once it's implemented (see http://webkit.org/b/121684).
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
+    if (!relationSet)
+        return nullptr;
+
+    AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
+    if (!relation)
+        return nullptr;
+
+    GPtrArray* targetList = atk_relation_get_target(relation);
+    if (!targetList || !targetList->len)
+        return nullptr;
+
+    StringBuilder builder;
+    builder.append("AXHelp: ");
+
+    for (int targetCount = 0; targetCount < targetList->len; targetCount++) {
+        if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
+            GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
+            if (targetCount)
+                builder.append(" ");
+            builder.append(text.get());
+        }
+    }
+
+    g_object_unref(relationSet);
+
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
 }
 
 double AccessibilityUIElement::x()