summaryrefslogtreecommitdiff
path: root/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp')
-rw-r--r--Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp659
1 files changed, 306 insertions, 353 deletions
diff --git a/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp b/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
index 79eb46d35..86cee4e25 100644
--- a/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
+++ b/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp
@@ -37,13 +37,17 @@
#include "AXObjectCache.h"
#include "AccessibilityList.h"
#include "AccessibilityListBoxOption.h"
+#include "AccessibilityTable.h"
#include "Document.h"
#include "Frame.h"
#include "FrameView.h"
#include "HTMLNames.h"
#include "HTMLTableElement.h"
#include "HostWindow.h"
+#include "RenderAncestorIterator.h"
+#include "RenderFieldset.h"
#include "RenderObject.h"
+#include "SVGElement.h"
#include "Settings.h"
#include "TextIterator.h"
#include "VisibleUnits.h"
@@ -57,6 +61,7 @@
#include "WebKitAccessibleInterfaceImage.h"
#include "WebKitAccessibleInterfaceSelection.h"
#include "WebKitAccessibleInterfaceTable.h"
+#include "WebKitAccessibleInterfaceTableCell.h"
#include "WebKitAccessibleInterfaceText.h"
#include "WebKitAccessibleInterfaceValue.h"
#include "WebKitAccessibleUtil.h"
@@ -64,10 +69,6 @@
#include <glib/gprintf.h>
#include <wtf/text/CString.h>
-#if PLATFORM(GTK)
-#include <gtk/gtk.h>
-#endif
-
using namespace WebCore;
struct _WebKitAccessiblePrivate {
@@ -93,7 +94,7 @@ struct _WebKitAccessiblePrivate {
static AccessibilityObject* fallbackObject()
{
- static AccessibilityObject* object = AccessibilityListBoxOption::create().leakRef();
+ static AccessibilityObject* object = &AccessibilityListBoxOption::create().leakRef();
return object;
}
@@ -110,58 +111,24 @@ static const gchar* webkitAccessibleGetName(AtkObject* object)
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
- AccessibilityObject* coreObject = core(object);
-
- if (!coreObject->isAccessibilityRenderObject())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, coreObject->stringValue());
+ Vector<AccessibilityText> textOrder;
+ core(object)->accessibilityText(textOrder);
- if (coreObject->isFieldset()) {
- AccessibilityObject* label = coreObject->titleUIElement();
- if (label) {
- AtkObject* atkObject = label->wrapper();
- if (ATK_IS_TEXT(atkObject))
- return atk_text_get_text(ATK_TEXT(atkObject), 0, -1);
- }
- }
-
- if (coreObject->isControl()) {
- AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
- if (label) {
- AtkObject* atkObject = label->wrapper();
- if (ATK_IS_TEXT(atkObject))
- return atk_text_get_text(ATK_TEXT(atkObject), 0, -1);
- }
-
- // Try text under the node.
- String textUnder = coreObject->textUnderElement();
- if (textUnder.length())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, textUnder);
- }
-
- if (coreObject->isImage() || coreObject->isInputImage()) {
- Node* node = coreObject->node();
- if (node && node->isHTMLElement()) {
- // Get the attribute rather than altText String so as not to fall back on title.
- String alt = toHTMLElement(node)->getAttribute(HTMLNames::altAttr);
- if (!alt.isEmpty())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, alt);
- }
- }
+ for (const auto& text : textOrder) {
+ // FIXME: This check is here because AccessibilityNodeObject::titleElementText()
+ // appends an empty String for the LabelByElementText source when there is a
+ // titleUIElement(). Removing this check makes some fieldsets lose their name.
+ if (text.text.isEmpty())
+ continue;
- // Fallback for the webArea object: just return the document's title.
- if (coreObject->isWebArea()) {
- Document* document = coreObject->document();
- if (document)
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, document->title());
+ // WebCore Accessibility should provide us with the text alternative computation
+ // in the order defined by that spec. So take the first thing that our platform
+ // does not expose via the AtkObject description.
+ if (text.textSource != HelpText && text.textSource != SummaryText)
+ return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, text.text);
}
- // Nothing worked so far, try with the AccessibilityObject's
- // title() before going ahead with stringValue().
- String axTitle = accessibilityTitle(coreObject);
- if (!axTitle.isEmpty())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, axTitle);
-
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, coreObject->stringValue());
+ return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, "");
}
static const gchar* webkitAccessibleGetDescription(AtkObject* object)
@@ -169,27 +136,26 @@ static const gchar* webkitAccessibleGetDescription(AtkObject* object)
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
- AccessibilityObject* coreObject = core(object);
- Node* node = 0;
- if (coreObject->isAccessibilityRenderObject())
- node = coreObject->node();
- if (!node || !node->isHTMLElement() || coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isImage())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject));
-
- // atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here.
- if (coreObject->roleValue() == TableRole) {
- String summary = toHTMLTableElement(node)->summary();
- if (!summary.isEmpty())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, summary);
- }
+ Vector<AccessibilityText> textOrder;
+ core(object)->accessibilityText(textOrder);
+
+ bool nameTextAvailable = false;
+ for (const auto& text : textOrder) {
+ // WebCore Accessibility should provide us with the text alternative computation
+ // in the order defined by that spec. So take the first thing that our platform
+ // does not expose via the AtkObject name.
+ if (text.textSource == HelpText || text.textSource == SummaryText)
+ return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
- // The title attribute should be reliably available as the object's descripton.
- // We do not want to fall back on other attributes in its absence. See bug 25524.
- String title = toHTMLElement(node)->title();
- if (!title.isEmpty())
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, title);
+ // If there is no other text alternative, the title tag contents will have been
+ // used for the AtkObject name. We don't want to duplicate it here.
+ if (text.textSource == TitleTagText && nameTextAvailable)
+ return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
- return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject));
+ nameTextAvailable = true;
+ }
+
+ return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, "");
}
static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType)
@@ -206,57 +172,56 @@ static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType
static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
{
- if (coreObject->isFieldset()) {
- AccessibilityObject* label = coreObject->titleUIElement();
- if (label) {
- removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
- atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
- }
- return;
- }
-
- if (coreObject->roleValue() == LegendRole) {
- for (AccessibilityObject* parent = coreObject->parentObjectUnignored(); parent; parent = parent->parentObjectUnignored()) {
- if (parent->isFieldset()) {
- atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, parent->wrapper());
- break;
- }
- }
- return;
- }
+ // FIXME: We're not implementing all the relation types, most notably the inverse/reciprocal
+ // types. Filed as bug 155494.
+ // Elements with aria-labelledby should have the labelled-by relation as per the ARIA AAM spec.
+ // Controls with a label element and fieldsets with a legend element should also use this relation
+ // as per the HTML AAM spec. The reciprocal label-for relation should also be used.
+ removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
if (coreObject->isControl()) {
- AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
- if (label) {
- removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
+ if (AccessibilityObject* label = coreObject->correspondingLabelForControlElement())
atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
+ } else if (coreObject->isFieldset()) {
+ if (AccessibilityObject* label = coreObject->titleUIElement())
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
+ } else if (coreObject->roleValue() == LegendRole) {
+ if (RenderFieldset* renderFieldset = ancestorsOfType<RenderFieldset>(*coreObject->renderer()).first()) {
+ AccessibilityObject* fieldset = coreObject->axObjectCache()->getOrCreate(renderFieldset);
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, fieldset->wrapper());
}
+ } else if (AccessibilityObject* control = coreObject->correspondingControlForLabelElement()) {
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
} else {
- AccessibilityObject* control = coreObject->correspondingControlForLabelElement();
- if (control)
- atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
+ AccessibilityObject::AccessibilityChildrenVector ariaLabelledByElements;
+ coreObject->ariaLabelledByElements(ariaLabelledByElements);
+ for (const auto& accessibilityObject : ariaLabelledByElements)
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, accessibilityObject->wrapper());
}
- // Check whether object supports aria-flowto
- if (coreObject->supportsARIAFlowTo()) {
- removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
- AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
- coreObject->ariaFlowToElements(ariaFlowToElements);
- 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());
- }
+ // Elements with aria-flowto should have the flows-to relation as per the ARIA AAM spec.
+ removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
+ AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
+ coreObject->ariaFlowToElements(ariaFlowToElements);
+ for (const auto& accessibilityObject : ariaFlowToElements)
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, accessibilityObject->wrapper());
+
+ // Elements with aria-describedby should have the described-by relation as per the ARIA AAM spec.
+ 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());
+
+ // Elements with aria-controls should have the controller-for relation as per the ARIA AAM spec.
+ removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLER_FOR);
+ AccessibilityObject::AccessibilityChildrenVector ariaControls;
+ coreObject->ariaControlsElements(ariaControls);
+ for (const auto& accessibilityObject : ariaControls)
+ atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLER_FOR, accessibilityObject->wrapper());
}
-static gpointer webkitAccessibleParentClass = 0;
+static gpointer webkitAccessibleParentClass = nullptr;
static bool isRootObject(AccessibilityObject* coreObject)
{
@@ -284,18 +249,6 @@ static AtkObject* atkParentOfRootObject(AtkObject* object)
Document* document = coreObject->document();
if (!document)
return 0;
-
-#if PLATFORM(GTK)
- HostWindow* hostWindow = document->view()->hostWindow();
- if (hostWindow) {
- PlatformPageClient scrollView = hostWindow->platformPageClient();
- if (scrollView) {
- GtkWidget* scrollViewParent = gtk_widget_get_parent(scrollView);
- if (scrollViewParent)
- return gtk_widget_get_accessible(scrollViewParent);
- }
- }
-#endif // PLATFORM(GTK)
}
if (!coreParent)
@@ -327,31 +280,9 @@ static AtkObject* webkitAccessibleGetParent(AtkObject* object)
if (!coreParent)
return 0;
- // We don't expose table rows to Assistive technologies, but we
- // need to have them anyway in the hierarchy from WebCore to
- // properly perform coordinates calculations when requested.
- if (coreParent->isTableRow() && coreObject->isTableCell())
- coreParent = coreParent->parentObjectUnignored();
-
return coreParent->wrapper();
}
-static gint getNChildrenForTable(AccessibilityObject* coreObject)
-{
- const AccessibilityObject::AccessibilityChildrenVector& tableChildren = coreObject->children();
- size_t cellsCount = 0;
-
- // Look for the actual index of the cell inside the table.
- for (const auto& tableChild : tableChildren) {
- if (tableChild->isTableRow())
- cellsCount += tableChild->children().size();
- else
- cellsCount++;
- }
-
- return cellsCount;
-}
-
static gint webkitAccessibleGetNChildren(AtkObject* object)
{
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
@@ -359,38 +290,9 @@ static gint webkitAccessibleGetNChildren(AtkObject* object)
AccessibilityObject* coreObject = core(object);
- // Tables should be treated in a different way because rows should
- // be bypassed when exposing the accessible hierarchy.
- if (coreObject->isAccessibilityTable())
- return getNChildrenForTable(coreObject);
-
return coreObject->children().size();
}
-static AccessibilityObject* getChildForTable(AccessibilityObject* coreObject, gint index)
-{
- const AccessibilityObject::AccessibilityChildrenVector& tableChildren = coreObject->children();
- size_t cellsCount = 0;
-
- // Look for the actual index of the cell inside the table.
- size_t current = static_cast<size_t>(index);
- for (const auto& tableChild : tableChildren) {
- if (tableChild->isTableRow()) {
- const AccessibilityObject::AccessibilityChildrenVector& rowChildren = tableChild->children();
- size_t rowChildrenCount = rowChildren.size();
- if (current < cellsCount + rowChildrenCount)
- return rowChildren.at(current - cellsCount).get();
- cellsCount += rowChildrenCount;
- } else if (cellsCount == current)
- return tableChild.get();
- else
- cellsCount++;
- }
-
- // Shouldn't reach if the child was found.
- return 0;
-}
-
static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
{
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
@@ -400,18 +302,12 @@ static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
return 0;
AccessibilityObject* coreObject = core(object);
- AccessibilityObject* coreChild = 0;
-
- // Tables are special cases because rows should be bypassed, but
- // still taking their cells into account.
- if (coreObject->isAccessibilityTable())
- coreChild = getChildForTable(coreObject, index);
- else {
- const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
- if (static_cast<unsigned>(index) >= children.size())
- return 0;
- coreChild = children.at(index).get();
- }
+ AccessibilityObject* coreChild = nullptr;
+
+ const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
+ if (static_cast<size_t>(index) >= children.size())
+ return 0;
+ coreChild = children.at(index).get();
if (!coreChild)
return 0;
@@ -423,40 +319,6 @@ static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
return child;
}
-static gint getIndexInParentForCellInRow(AccessibilityObject* coreObject)
-{
- AccessibilityObject* parent = coreObject->parentObjectUnignored();
- if (!parent)
- return -1;
-
- AccessibilityObject* grandParent = parent->parentObjectUnignored();
- if (!grandParent)
- return -1;
-
- const AccessibilityObject::AccessibilityChildrenVector& rows = grandParent->children();
- size_t previousCellsCount = 0;
-
- // Look for the actual index of the cell inside the table.
- for (const auto& row : rows) {
- if (!row->isTableRow())
- continue;
-
- const AccessibilityObject::AccessibilityChildrenVector& cells = row->children();
- size_t cellsCount = cells.size();
-
- if (row == parent) {
- for (unsigned j = 0; j < cellsCount; ++j) {
- if (cells[j] == coreObject)
- return previousCellsCount + j;
- }
- }
-
- previousCellsCount += cellsCount;
- }
-
- return -1;
-}
-
static gint webkitAccessibleGetIndexInParent(AtkObject* object)
{
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), -1);
@@ -480,11 +342,6 @@ static gint webkitAccessibleGetIndexInParent(AtkObject* object)
}
}
- // Need to calculate the index of the cell in the table, as
- // rows won't be exposed to assistive technologies.
- if (parent && parent->isTableRow() && coreObject->isTableCell())
- return getIndexInParentForCellInRow(coreObject);
-
if (!parent)
return -1;
@@ -497,11 +354,9 @@ static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
- AtkAttributeSet* attributeSet = 0;
+ AtkAttributeSet* attributeSet = nullptr;
#if PLATFORM(GTK)
attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
-#elif PLATFORM(EFL)
- attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitEfl");
#endif
AccessibilityObject* coreObject = core(object);
@@ -511,9 +366,12 @@ static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
// Hack needed for WebKit2 tests because obtaining an element by its ID
// cannot be done from the UIProcess. Assistive technologies have no need
// for this information.
- Node* node = coreObject->node();
- if (node && node->isElementNode()) {
- String id = toElement(node)->getIdAttribute().string();
+ Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
+ if (element) {
+ String tagName = element->tagName();
+ if (!tagName.isEmpty())
+ attributeSet = addToAtkAttributeSet(attributeSet, "tag", tagName.convertToASCIILowercase().utf8().data());
+ String id = element->getIdAttribute().string();
if (!id.isEmpty())
attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
}
@@ -524,9 +382,16 @@ static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
}
+ if (coreObject->roleValue() == MathElementRole) {
+ if (coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PreSubscript))
+ attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
+ else if (coreObject->isMathMultiscriptObject(PostSuperscript) || coreObject->isMathMultiscriptObject(PostSubscript))
+ attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
+ }
+
// Set the 'layout-guess' attribute to help Assistive
// Technologies know when an exposed table is not data table.
- if (coreObject->isAccessibilityTable() && !coreObject->isDataTable())
+ if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposableThroughAccessibility() && !coreObject->isDataTable())
attributeSet = addToAtkAttributeSet(attributeSet, "layout-guess", "true");
String placeholder = coreObject->placeholderValue();
@@ -543,32 +408,38 @@ static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
attributeSet = addToAtkAttributeSet(attributeSet, "sort", sortAttribute.string().utf8().data());
}
- // Landmarks will be exposed with xml-roles object attributes, with the exception
- // of LandmarkApplicationRole, which will be exposed with ATK_ROLE_EMBEDDED.
- AccessibilityRole role = coreObject->roleValue();
- switch (role) {
- case LandmarkBannerRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "banner");
- break;
- case LandmarkComplementaryRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "complementary");
- break;
- case LandmarkContentInfoRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "contentinfo");
- break;
- case LandmarkMainRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "main");
- break;
- case LandmarkNavigationRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "navigation");
- break;
- case LandmarkSearchRole:
- attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "search");
- break;
- default:
- break;
+ if (coreObject->supportsARIAPosInSet())
+ attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->ariaPosInSet()).utf8().data());
+
+ if (coreObject->supportsARIASetSize())
+ attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->ariaSetSize()).utf8().data());
+
+ String isReadOnly = coreObject->ariaReadOnlyValue();
+ if (!isReadOnly.isEmpty())
+ attributeSet = addToAtkAttributeSet(attributeSet, "readonly", isReadOnly.utf8().data());
+
+ String valueDescription = coreObject->valueDescription();
+ if (!valueDescription.isEmpty())
+ attributeSet = addToAtkAttributeSet(attributeSet, "valuetext", valueDescription.utf8().data());
+
+ // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
+ // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
+ // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
+ // The computedRoleString is primarily for testing, and not limited to elements with ARIA roles.
+ // Because the computedRoleString currently contains the ARIA role string, we'll use it for
+ // both purposes, as the "computed-role" object attribute for all elements which have a value
+ // and also via the "xml-roles" attribute for elements with ARIA, as well as for landmarks.
+ String roleString = coreObject->computedRoleString();
+ if (!roleString.isEmpty()) {
+ if (coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isLandmark())
+ attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", roleString.utf8().data());
+ attributeSet = addToAtkAttributeSet(attributeSet, "computed-role", roleString.utf8().data());
}
+ String roleDescription = coreObject->roleDescription();
+ if (!roleDescription.isEmpty())
+ attributeSet = addToAtkAttributeSet(attributeSet, "roledescription", roleDescription.utf8().data());
+
return attributeSet;
}
@@ -586,10 +457,17 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
case UnknownRole:
return ATK_ROLE_UNKNOWN;
case AudioRole:
+#if ATK_CHECK_VERSION(2, 11, 3)
+ return ATK_ROLE_AUDIO;
+#endif
case VideoRole:
+#if ATK_CHECK_VERSION(2, 11, 3)
+ return ATK_ROLE_VIDEO;
+#endif
return ATK_ROLE_EMBEDDED;
case ButtonRole:
return ATK_ROLE_PUSH_BUTTON;
+ case SwitchRole:
case ToggleButtonRole:
return ATK_ROLE_TOGGLE_BUTTON;
case RadioButtonRole:
@@ -603,9 +481,14 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
return ATK_ROLE_PAGE_TAB_LIST;
case TextFieldRole:
case TextAreaRole:
+ case SearchFieldRole:
return ATK_ROLE_ENTRY;
case StaticTextRole:
+#if ATK_CHECK_VERSION(2, 15, 2)
+ return ATK_ROLE_STATIC;
+#else
return ATK_ROLE_TEXT;
+#endif
case OutlineRole:
case TreeRole:
return ATK_ROLE_TREE;
@@ -627,15 +510,13 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
// return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
return ATK_ROLE_UNKNOWN; // Matches Mozilla
case RowRole:
- // return ATK_ROLE_TABLE_ROW_HEADER; // Is this right?
- return ATK_ROLE_LIST_ITEM; // Matches Mozilla
+ return ATK_ROLE_TABLE_ROW;
case ToolbarRole:
return ATK_ROLE_TOOL_BAR;
case BusyIndicatorRole:
return ATK_ROLE_PROGRESS_BAR; // Is this right?
case ProgressIndicatorRole:
- // return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp
- return ATK_ROLE_PROGRESS_BAR;
+ return coreObject->isMeter() ? ATK_ROLE_LEVEL_BAR : ATK_ROLE_PROGRESS_BAR;
case WindowRole:
return ATK_ROLE_WINDOW;
case PopUpButtonRole:
@@ -646,31 +527,42 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
case SplitterRole:
return ATK_ROLE_SEPARATOR;
case ColorWellRole:
- return ATK_ROLE_COLOR_CHOOSER;
+#if PLATFORM(GTK)
+ // ATK_ROLE_COLOR_CHOOSER is defined as a dialog (i.e. it's what appears when you push the button).
+ return ATK_ROLE_PUSH_BUTTON;
+#endif
case ListRole:
return ATK_ROLE_LIST;
case ScrollBarRole:
return ATK_ROLE_SCROLL_BAR;
case ScrollAreaRole:
return ATK_ROLE_SCROLL_PANE;
- case GridRole: // Is this right?
+ case GridRole:
case TableRole:
return ATK_ROLE_TABLE;
case ApplicationRole:
return ATK_ROLE_APPLICATION;
- case GroupRole:
case RadioGroupRole:
+ case SVGRootRole:
case TabPanelRole:
return ATK_ROLE_PANEL;
- case RowHeaderRole: // Row headers are cells after all.
- case ColumnHeaderRole: // Column headers are cells after all.
+ case GroupRole:
+ return coreObject->isStyleFormatGroup() ? ATK_ROLE_SECTION : ATK_ROLE_PANEL;
+ case RowHeaderRole:
+ return ATK_ROLE_ROW_HEADER;
+ case ColumnHeaderRole:
+ return ATK_ROLE_COLUMN_HEADER;
+ case CaptionRole:
+ return ATK_ROLE_CAPTION;
case CellRole:
- return ATK_ROLE_TABLE_CELL;
+ case GridCellRole:
+ return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
case LinkRole:
case WebCoreLinkRole:
case ImageMapLinkRole:
return ATK_ROLE_LINK;
case ImageMapRole:
+ return ATK_ROLE_IMAGE_MAP;
case ImageRole:
return ATK_ROLE_IMAGE;
case ListMarkerRole:
@@ -686,17 +578,27 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
case HeadingRole:
return ATK_ROLE_HEADING;
case ListBoxRole:
- return ATK_ROLE_LIST;
+ // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-listbox
+ return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU : ATK_ROLE_LIST_BOX;
case ListItemRole:
+ return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
case ListBoxOptionRole:
- return ATK_ROLE_LIST_ITEM;
+ return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU_ITEM : ATK_ROLE_LIST_ITEM;
case ParagraphRole:
return ATK_ROLE_PARAGRAPH;
case LabelRole:
case LegendRole:
return ATK_ROLE_LABEL;
+ case BlockquoteRole:
+#if ATK_CHECK_VERSION(2, 11, 3)
+ return ATK_ROLE_BLOCK_QUOTE;
+#endif
case DivRole:
+ case PreRole:
+ case SVGTextRole:
return ATK_ROLE_SECTION;
+ case FooterRole:
+ return ATK_ROLE_FOOTER;
case FormRole:
return ATK_ROLE_FORM;
case CanvasRole:
@@ -711,7 +613,7 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
return ATK_ROLE_TOOL_TIP;
case WebAreaRole:
return ATK_ROLE_DOCUMENT_WEB;
- case LandmarkApplicationRole:
+ case WebApplicationRole:
return ATK_ROLE_EMBEDDED;
#if ATK_CHECK_VERSION(2, 11, 3)
case ApplicationLogRole:
@@ -724,11 +626,40 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
return ATK_ROLE_DEFINITION;
case DocumentMathRole:
return ATK_ROLE_MATH;
+ case MathElementRole:
+ if (coreObject->isMathRow())
+ return ATK_ROLE_PANEL;
+ if (coreObject->isMathTable())
+ return ATK_ROLE_TABLE;
+ if (coreObject->isMathTableRow())
+ return ATK_ROLE_TABLE_ROW;
+ if (coreObject->isMathTableCell())
+ return ATK_ROLE_TABLE_CELL;
+ if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
+ return ATK_ROLE_SECTION;
+#if ATK_CHECK_VERSION(2, 15, 4)
+ if (coreObject->isMathFraction())
+ return ATK_ROLE_MATH_FRACTION;
+ if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
+ return ATK_ROLE_MATH_ROOT;
+ if (coreObject->isMathScriptObject(Subscript)
+ || coreObject->isMathMultiscriptObject(PreSubscript) || coreObject->isMathMultiscriptObject(PostSubscript))
+ return ATK_ROLE_SUBSCRIPT;
+ if (coreObject->isMathScriptObject(Superscript)
+ || coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PostSuperscript))
+ return ATK_ROLE_SUPERSCRIPT;
+#endif
+#if ATK_CHECK_VERSION(2, 15, 2)
+ if (coreObject->isMathToken())
+ return ATK_ROLE_STATIC;
+#endif
+ return ATK_ROLE_UNKNOWN;
case LandmarkBannerRole:
case LandmarkComplementaryRole:
case LandmarkContentInfoRole:
case LandmarkMainRole:
case LandmarkNavigationRole:
+ case LandmarkRegionRole:
case LandmarkSearchRole:
return ATK_ROLE_LANDMARK;
#endif
@@ -740,6 +671,19 @@ static AtkRole atkRole(AccessibilityObject* coreObject)
case DescriptionListDetailRole:
return ATK_ROLE_DESCRIPTION_VALUE;
#endif
+ case InlineRole:
+#if ATK_CHECK_VERSION(2, 15, 4)
+ if (coreObject->isSubscriptStyleGroup())
+ return ATK_ROLE_SUBSCRIPT;
+ if (coreObject->isSuperscriptStyleGroup())
+ return ATK_ROLE_SUPERSCRIPT;
+#endif
+#if ATK_CHECK_VERSION(2, 15, 2)
+ return ATK_ROLE_STATIC;
+ case SVGTextPathRole:
+ case SVGTSpanRole:
+ return ATK_ROLE_STATIC;
+#endif
default:
return ATK_ROLE_UNKNOWN;
}
@@ -803,16 +747,18 @@ static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkSta
if (isListBoxOption && coreObject->isSelectedOptionActive())
atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
+ if (coreObject->isBusy())
+ atk_state_set_add_state(stateSet, ATK_STATE_BUSY);
+
+#if ATK_CHECK_VERSION(2,11,2)
+ if (coreObject->supportsChecked() && coreObject->canSetValueAttribute())
+ atk_state_set_add_state(stateSet, ATK_STATE_CHECKABLE);
+#endif
+
if (coreObject->isChecked())
atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
- // FIXME: isReadOnly does not seem to do the right thing for
- // controls, so check explicitly for them. In addition, because
- // isReadOnly is false for listBoxOptions, we need to add one
- // more check so that we do not present them as being "editable".
- if ((!coreObject->isReadOnly()
- || (coreObject->isControl() && coreObject->canSetValueAttribute()))
- && !isListBoxOption)
+ if ((coreObject->isTextControl() || coreObject->isNonNativeTextControl()) && coreObject->canSetValueAttribute())
atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
// FIXME: Put both ENABLED and SENSITIVE together here for now
@@ -857,6 +803,11 @@ static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkSta
if (coreObject->isPressed())
atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
+#if ATK_CHECK_VERSION(2,15,3)
+ if (!coreObject->canSetValueAttribute() && (coreObject->supportsARIAReadOnly()))
+ atk_state_set_add_state(stateSet, ATK_STATE_READ_ONLY);
+#endif
+
if (coreObject->isRequired())
atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
@@ -890,10 +841,10 @@ static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkSta
}
// Mutually exclusive, so we group these two
- if (coreObject->roleValue() == TextFieldRole)
- atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
- else if (coreObject->roleValue() == TextAreaRole)
+ if (coreObject->roleValue() == TextAreaRole || coreObject->ariaIsMultiline())
atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
+ else if (coreObject->roleValue() == TextFieldRole || coreObject->roleValue() == SearchFieldRole)
+ atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
// TODO: ATK_STATE_SENSITIVE
@@ -965,7 +916,7 @@ static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
return cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, language);
} else if (ATK_IS_TEXT(object)) {
- const gchar* locale = 0;
+ const gchar* locale = nullptr;
AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
for (AtkAttributeSet* attributes = textAttributes; attributes; attributes = attributes->next) {
@@ -1046,6 +997,9 @@ static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleComponentInterfaceInit), 0, 0},
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleImageInterfaceInit), 0, 0},
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableInterfaceInit), 0, 0},
+#if ATK_CHECK_VERSION(2,11,90)
+ {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableCellInterfaceInit), 0, 0},
+#endif
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHypertextInterfaceInit), 0, 0},
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHyperlinkImplInterfaceInit), 0, 0},
{reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleDocumentInterfaceInit), 0, 0},
@@ -1053,43 +1007,50 @@ static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
};
enum WAIType {
- WAI_ACTION,
- WAI_SELECTION,
- WAI_EDITABLE_TEXT,
- WAI_TEXT,
- WAI_COMPONENT,
- WAI_IMAGE,
- WAI_TABLE,
- WAI_HYPERTEXT,
- WAI_HYPERLINK,
- WAI_DOCUMENT,
- WAI_VALUE,
+ WAIAction,
+ WAISelection,
+ WAIEditableText,
+ WAIText,
+ WAIComponent,
+ WAIImage,
+ WAITable,
+#if ATK_CHECK_VERSION(2,11,90)
+ WAITableCell,
+#endif
+ WAIHypertext,
+ WAIHyperlink,
+ WAIDocument,
+ WAIValue,
};
static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
{
switch (type) {
- case WAI_ACTION:
+ case WAIAction:
return ATK_TYPE_ACTION;
- case WAI_SELECTION:
+ case WAISelection:
return ATK_TYPE_SELECTION;
- case WAI_EDITABLE_TEXT:
+ case WAIEditableText:
return ATK_TYPE_EDITABLE_TEXT;
- case WAI_TEXT:
+ case WAIText:
return ATK_TYPE_TEXT;
- case WAI_COMPONENT:
+ case WAIComponent:
return ATK_TYPE_COMPONENT;
- case WAI_IMAGE:
+ case WAIImage:
return ATK_TYPE_IMAGE;
- case WAI_TABLE:
+ case WAITable:
return ATK_TYPE_TABLE;
- case WAI_HYPERTEXT:
+#if ATK_CHECK_VERSION(2,11,90)
+ case WAITableCell:
+ return ATK_TYPE_TABLE_CELL;
+#endif
+ case WAIHypertext:
return ATK_TYPE_HYPERTEXT;
- case WAI_HYPERLINK:
+ case WAIHyperlink:
return ATK_TYPE_HYPERLINK_IMPL;
- case WAI_DOCUMENT:
+ case WAIDocument:
return ATK_TYPE_DOCUMENT;
- case WAI_VALUE:
+ case WAIValue:
return ATK_TYPE_VALUE;
}
@@ -1099,7 +1060,8 @@ static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
static bool roleIsTextType(AccessibilityRole role)
{
return role == ParagraphRole || role == HeadingRole || role == DivRole || role == CellRole
- || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole;
+ || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole || role == PreRole
+ || role == GridCellRole;
}
static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
@@ -1107,7 +1069,7 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
guint16 interfaceMask = 0;
// Component interface is always supported
- interfaceMask |= 1 << WAI_COMPONENT;
+ interfaceMask |= 1 << WAIComponent;
AccessibilityRole role = coreObject->roleValue();
@@ -1117,68 +1079,71 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
// object, and only supports having one action per object), it is
// better just to implement this interface for every instance of
// the WebKitAccessible class and let WebCore decide what to do.
- interfaceMask |= 1 << WAI_ACTION;
+ interfaceMask |= 1 << WAIAction;
// Selection
- if (coreObject->isListBox() || coreObject->isMenuList())
- interfaceMask |= 1 << WAI_SELECTION;
+ if (coreObject->canHaveSelectedChildren() || coreObject->isMenuList())
+ interfaceMask |= 1 << WAISelection;
// Get renderer if available.
- RenderObject* renderer = 0;
+ RenderObject* renderer = nullptr;
if (coreObject->isAccessibilityRenderObject())
renderer = coreObject->renderer();
// Hyperlink (links and embedded objects).
if (coreObject->isLink() || (renderer && renderer->isReplaced()))
- interfaceMask |= 1 << WAI_HYPERLINK;
+ interfaceMask |= 1 << WAIHyperlink;
- // Text & Editable Text
+ // Text, Editable Text & Hypertext
if (role == StaticTextRole || coreObject->isMenuListOption())
- interfaceMask |= 1 << WAI_TEXT;
- else {
- if (coreObject->isTextControl()) {
- interfaceMask |= 1 << WAI_TEXT;
- if (!coreObject->isReadOnly())
- interfaceMask |= 1 << WAI_EDITABLE_TEXT;
- } else {
- if (role != TableRole) {
- interfaceMask |= 1 << WAI_HYPERTEXT;
- if ((renderer && renderer->childrenInline()) || roleIsTextType(role))
- interfaceMask |= 1 << WAI_TEXT;
- }
+ interfaceMask |= 1 << WAIText;
+ else if (coreObject->isTextControl() || coreObject->isNonNativeTextControl()) {
+ interfaceMask |= 1 << WAIText;
+ if (coreObject->canSetValueAttribute())
+ interfaceMask |= 1 << WAIEditableText;
+ } else if (!coreObject->isWebArea()) {
+ if (role != TableRole) {
+ interfaceMask |= 1 << WAIHypertext;
+ if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
+ interfaceMask |= 1 << WAIText;
+ }
- // Add the TEXT interface for list items whose
- // first accessible child has a text renderer
- if (role == ListItemRole) {
- const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
- if (children.size()) {
- AccessibilityObject* axRenderChild = children.at(0).get();
- interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
- }
+ // Add the TEXT interface for list items whose
+ // first accessible child has a text renderer
+ if (role == ListItemRole) {
+ const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
+ if (children.size()) {
+ AccessibilityObject* axRenderChild = children.at(0).get();
+ interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
}
}
}
// Image
if (coreObject->isImage())
- interfaceMask |= 1 << WAI_IMAGE;
+ interfaceMask |= 1 << WAIImage;
// Table
- if (role == TableRole)
- interfaceMask |= 1 << WAI_TABLE;
+ if (role == TableRole || role == GridRole)
+ interfaceMask |= 1 << WAITable;
+
+#if ATK_CHECK_VERSION(2,11,90)
+ if (role == CellRole || role == ColumnHeaderRole || role == RowHeaderRole)
+ interfaceMask |= 1 << WAITableCell;
+#endif
// Document
if (role == WebAreaRole)
- interfaceMask |= 1 << WAI_DOCUMENT;
+ interfaceMask |= 1 << WAIDocument;
// Value
if (role == SliderRole || role == SpinButtonRole || role == ScrollBarRole || role == ProgressIndicatorRole)
- interfaceMask |= 1 << WAI_VALUE;
+ interfaceMask |= 1 << WAIValue;
#if ENABLE(INPUT_TYPE_COLOR)
// Color type.
if (role == ColorWellRole)
- interfaceMask |= 1 << WAI_TEXT;
+ interfaceMask |= 1 << WAIText;
#endif
return interfaceMask;
@@ -1261,18 +1226,6 @@ bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
return accessible->m_object == fallbackObject();
}
-AtkObject* webkitAccessibleGetFocusedElement(WebKitAccessible* accessible)
-{
- if (!accessible->m_object)
- return 0;
-
- RefPtr<AccessibilityObject> focusedObj = accessible->m_object->focusedUIElement();
- if (!focusedObj)
- return 0;
-
- return focusedObj->wrapper();
-}
-
AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* referenceObject, int& offset)
{
// Indication that something bogus has transpired.
@@ -1314,7 +1267,7 @@ AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* r
if (referenceObject->isDescendantOfObject(firstUnignoredParent))
referenceObject = firstUnignoredParent;
- Node* startNode = 0;
+ Node* startNode = nullptr;
if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
// We need to use the first child's node of the reference
// object as the start point to calculate the caret offset
@@ -1356,7 +1309,7 @@ AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* r
const char* cacheAndReturnAtkProperty(AtkObject* object, AtkCachedProperty property, String value)
{
WebKitAccessiblePrivate* priv = WEBKIT_ACCESSIBLE(object)->priv;
- CString* propertyPtr = 0;
+ CString* propertyPtr = nullptr;
switch (property) {
case AtkCachedAccessibleName: