Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityList.cpp
index 327d2a1..f90cecb 100644 (file)
@@ -32,9 +32,9 @@
 #include "AXObjectCache.h"
 #include "HTMLElement.h"
 #include "HTMLNames.h"
+#include "PseudoElement.h"
 #include "RenderListItem.h"
 #include "RenderObject.h"
-#include "RenderStyle.h"
 
 namespace WebCore {
     
@@ -45,13 +45,11 @@ AccessibilityList::AccessibilityList(RenderObject* renderer)
 {
 }
 
-AccessibilityList::~AccessibilityList()
-{
-}
+AccessibilityList::~AccessibilityList() = default;
 
-PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer)
+Ref<AccessibilityList> AccessibilityList::create(RenderObject* renderer)
 {
-    return adoptRef(new AccessibilityList(renderer));
+    return adoptRef(*new AccessibilityList(renderer));
 }
 
 bool AccessibilityList::computeAccessibilityIsIgnored() const
@@ -97,6 +95,35 @@ bool AccessibilityList::isDescriptionList() const
     return node && node->hasTagName(dlTag);
 }
 
+bool AccessibilityList::childHasPseudoVisibleListItemMarkers(RenderObject* listItem)
+{
+    // Check if the list item has a pseudo-element that should be accessible (e.g. an image or text)
+    Element* listItemElement = downcast<Element>(listItem->node());
+    if (!listItemElement || !listItemElement->beforePseudoElement())
+        return false;
+
+    AccessibilityObject* axObj = axObjectCache()->getOrCreate(listItemElement->beforePseudoElement()->renderer());
+    if (!axObj)
+        return false;
+    
+    if (!axObj->accessibilityIsIgnored())
+        return true;
+    
+    for (const auto& child : axObj->children()) {
+        if (!child->accessibilityIsIgnored())
+            return true;
+    }
+    
+    // Platforms which expose rendered text content through the parent element will treat
+    // those renderers as "ignored" objects.
+#if PLATFORM(GTK)
+    String text = axObj->textUnderElement();
+    return !text.isEmpty() && !text.containsOnlyWhitespace();
+#else
+    return false;
+#endif
+}
+    
 AccessibilityRole AccessibilityList::determineAccessibilityRole()
 {
     m_ariaRole = determineAriaRoleAttribute();
@@ -131,21 +158,33 @@ AccessibilityRole AccessibilityList::determineAccessibilityRole()
             listItemCount++;
         else if (child->roleValue() == ListItemRole) {
             RenderObject* listItem = child->renderer();
-            if (listItem && listItem->isListItem()) {
-                if (listItem->style().listStyleType() != NoneListStyle || listItem->style().listStyleImage())
+            if (!listItem)
+                continue;
+            
+            // Rendered list items always count.
+            if (listItem->isListItem()) {
+                if (!hasVisibleMarkers && (listItem->style().listStyleType() != NoneListStyle || listItem->style().listStyleImage() || childHasPseudoVisibleListItemMarkers(listItem)))
                     hasVisibleMarkers = true;
                 listItemCount++;
+            } else if (listItem->node() && listItem->node()->hasTagName(liTag)) {
+                // Inline elements that are in a list with an explicit role should also count.
+                if (m_ariaRole == ListRole)
+                    listItemCount++;
+
+                if (childHasPseudoVisibleListItemMarkers(listItem)) {
+                    hasVisibleMarkers = true;
+                    listItemCount++;
+                }
             }
         }
     }
     
-    bool unorderedList = isUnorderedList();
     // Non <ul> lists and ARIA lists only need to have one child.
-    // <ul> lists need to have 1 child, or visible markers.
-    if (!unorderedList || ariaRoleAttribute() != UnknownRole) {
+    // <ul>, <ol> lists need to have visible markers.
+    if (ariaRoleAttribute() != UnknownRole) {
         if (!listItemCount)
-            role = GroupRole;
-    } else if (unorderedList && listItemCount <= 1 && !hasVisibleMarkers)
+            role = ApplicationGroupRole;
+    } else if (!hasVisibleMarkers)
         role = GroupRole;
 
     return role;