summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-07-21 15:11:35 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-09-01 17:39:56 +0200
commitc6c1da2f4c71e523213aa8ee961d8fec779f62e2 (patch)
tree897aeedf27454e94d0dd7602207fbae55349dbac
parentb88a0e84dddbaa978eaed0ed8eb09ec39b6283bc (diff)
Try harder to return accessible names
Always check if there is another accessible set as title for the one queried. For text fields also return the placeholder property if nothing else is set. Change-Id: I3f10ff04338a405ad8de00e75e15dded4aaeed3b Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
-rw-r--r--src/core/browser_accessibility_qt.cpp82
-rw-r--r--src/core/browser_accessibility_qt.h3
-rw-r--r--tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp70
3 files changed, 136 insertions, 19 deletions
diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp
index d2710b0e..405bafb9 100644
--- a/src/core/browser_accessibility_qt.cpp
+++ b/src/core/browser_accessibility_qt.cpp
@@ -34,6 +34,10 @@
**
****************************************************************************/
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include "browser_accessibility_qt.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
@@ -52,6 +56,82 @@ BrowserAccessibilityQt::BrowserAccessibilityQt()
QAccessible::registerAccessibleInterface(this);
}
+// This function is taken from chromium/content/browser/accessibility/browser_accessibility_win.cc
+// see also http://www.w3.org/TR/html-aapi
+void BrowserAccessibilityQt::OnDataChanged()
+{
+ BrowserAccessibility::OnDataChanged();
+
+ // The calculation of the accessible name of an element has been
+ // standardized in the HTML to Platform Accessibility APIs Implementation
+ // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
+ // appropriate accessible name on Windows, we need to apply some logic
+ // to the fields we get from WebKit.
+ //
+ // TODO(dmazzoni): move most of this logic into WebKit.
+ //
+ // WebKit gives us:
+ //
+ // name: the default name, e.g. inner text
+ // title ui element: a reference to a <label> element on the same
+ // page that labels this node.
+ // description: accessible labels that override the default name:
+ // aria-label or aria-labelledby or aria-describedby
+ // help: the value of the "title" attribute
+ //
+ // On Windows, the logic we apply lets some fields take precedence and
+ // always returns the primary name in "name" and the secondary name,
+ // if any, in "description".
+
+ int title_elem_id = GetIntAttribute(
+ ui::AX_ATTR_TITLE_UI_ELEMENT);
+ std::string help = GetStringAttribute(ui::AX_ATTR_HELP);
+ std::string description = GetStringAttribute(
+ ui::AX_ATTR_DESCRIPTION);
+
+ // WebKit annoyingly puts the title in the description if there's no other
+ // description, which just confuses the rest of the logic. Put it back.
+ // Now "help" is always the value of the "title" attribute, if present.
+ std::string title_attr;
+ if (GetHtmlAttribute("title", &title_attr) &&
+ description == title_attr &&
+ help.empty()) {
+ help = description;
+ description.clear();
+ }
+
+ // Now implement the main logic: the descripion should become the name if
+ // it's nonempty, and the help should become the description if
+ // there's no description - or the name if there's no name or description.
+ if (!description.empty()) {
+ set_name(description);
+ description.clear();
+ }
+ if (!help.empty() && description.empty()) {
+ description = help;
+ help.clear();
+ }
+ if (!description.empty() && name().empty() && !title_elem_id) {
+ set_name(description);
+ description.clear();
+ }
+
+ // If it's a text field, also consider the placeholder.
+ std::string placeholder;
+ if (GetRole() == ui::AX_ROLE_TEXT_FIELD &&
+ HasState(ui::AX_STATE_FOCUSABLE) &&
+ GetHtmlAttribute("placeholder", &placeholder)) {
+ if (name().empty() && !title_elem_id) {
+ set_name(placeholder);
+ } else if (description.empty()) {
+ description = placeholder;
+ }
+ }
+
+ SetStringAttribute(ui::AX_ATTR_DESCRIPTION, description);
+ SetStringAttribute(ui::AX_ATTR_HELP, help);
+}
+
bool BrowserAccessibilityQt::isValid() const
{
return true;
@@ -128,7 +208,7 @@ QString BrowserAccessibilityQt::text(QAccessible::Text t) const
{
switch (t) {
case QAccessible::Name:
- return toQt(GetStringAttribute(ui::AX_ATTR_NAME));
+ return toQt(name());
case QAccessible::Description:
return toQt(GetStringAttribute(ui::AX_ATTR_DESCRIPTION));
case QAccessible::Help:
diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h
index b8cd9e67..8dfffdcf 100644
--- a/src/core/browser_accessibility_qt.h
+++ b/src/core/browser_accessibility_qt.h
@@ -52,6 +52,9 @@ class BrowserAccessibilityQt
public:
BrowserAccessibilityQt();
+ // BrowserAccessibility
+ virtual void OnDataChanged() Q_DECL_OVERRIDE;
+
// QAccessibleInterface
virtual bool isValid() const Q_DECL_OVERRIDE;
virtual QObject *object() const Q_DECL_OVERRIDE;
diff --git a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
index 7668a12a..c61b5eff 100644
--- a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
+++ b/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp
@@ -144,33 +144,67 @@ void tst_QWebEngineView::text()
QWebEngineView webView;
webView.setHtml("<html><body>" \
"<input type='text' value='Good morning!'></input>" \
+ "<p id='labelName'>Enter your name here:</p>" \
+ "<input type='text' value='my name' aria-labelledby='labelName' aria-describedby='explanation'></input>" \
+ "<p id='explanation'>Provide both first and last name.</p>" \
+ "<input type='text' value='Good day!' placeholder='day'></input>" \
"</body></html>");
webView.show();
::waitForSignal(&webView, SIGNAL(loadFinished(bool)));
QAccessibleInterface *view = QAccessible::queryAccessibleInterface(&webView);
// Wait for accessibility to be fully initialized
- QTRY_VERIFY(view->child(0)->childCount() == 1);
- QAccessibleInterface *document = view->child(0);
- QAccessibleInterface *grouping = document->child(0);
- QVERIFY(grouping);
- QAccessibleInterface *input = grouping->child(0);
- QCOMPARE(input->role(), QAccessible::EditableText);
- QCOMPARE(input->text(QAccessible::Name), QString());
- QCOMPARE(input->text(QAccessible::Description), QString());
- QCOMPARE(input->text(QAccessible::Value), QStringLiteral("Good morning!"));
-
- QAccessibleTextInterface *textInterface = input->textInterface();
- QVERIFY(textInterface);
- QCOMPARE(textInterface->characterCount(), 13);
- QCOMPARE(textInterface->selectionCount(), 0);
- QCOMPARE(textInterface->text(2, 9), QStringLiteral("od morn"));
+ QTRY_VERIFY(view->child(0)->childCount() == 5);
+ QAccessibleInterface *document = view->child(0);
+ QVERIFY(document);
+
+ // Good morning! [edit]
+ QAccessibleInterface *grouping1 = document->child(0);
+ QAccessibleInterface *input1 = grouping1->child(0);
+ QCOMPARE(input1->role(), QAccessible::EditableText);
+ QCOMPARE(input1->text(QAccessible::Name), QString());
+ QCOMPARE(input1->text(QAccessible::Description), QString());
+ QCOMPARE(input1->text(QAccessible::Value), QStringLiteral("Good morning!"));
+
+ QAccessibleTextInterface *textInterface1 = input1->textInterface();
+ QVERIFY(textInterface1);
+ QCOMPARE(textInterface1->characterCount(), 13);
+ QCOMPARE(textInterface1->selectionCount(), 0);
+ QCOMPARE(textInterface1->text(2, 9), QStringLiteral("od morn"));
int start = -1;
int end = -1;
- QCOMPARE(textInterface->textAtOffset(8, QAccessible::WordBoundary, &start, &end), QStringLiteral("morning"));
- textInterface->setCursorPosition(3);
- QTRY_COMPARE(textInterface->cursorPosition(), 3);
+ QCOMPARE(textInterface1->textAtOffset(8, QAccessible::WordBoundary, &start, &end), QStringLiteral("morning"));
+
+ // Enter your name here:
+ // my name [edit]
+ // Provide both first and last name here.
+ QAccessibleInterface *grouping2 = document->child(1);
+ QAccessibleInterface *label1 = grouping2->child(0);
+ QCOMPARE(label1->role(), QAccessible::StaticText);
+ QCOMPARE(label1->text(QAccessible::Name), QString());
+ QCOMPARE(label1->text(QAccessible::Description), QString());
+ QCOMPARE(label1->text(QAccessible::Value), QStringLiteral("Enter your name here:"));
+ QAccessibleInterface *grouping3 = document->child(2);
+ QAccessibleInterface *input2 = grouping3->child(0);
+ QCOMPARE(input2->role(), QAccessible::EditableText);
+ QCOMPARE(input2->text(QAccessible::Name), QStringLiteral("Enter your name here:"));
+ QCOMPARE(input2->text(QAccessible::Description), QStringLiteral("Provide both first and last name."));
+ QCOMPARE(input2->text(QAccessible::Value), QStringLiteral("my name"));
+ QAccessibleInterface *grouping4 = document->child(3);
+ QAccessibleInterface *label2 = grouping4->child(0);
+ QCOMPARE(label2->role(), QAccessible::StaticText);
+ QCOMPARE(label2->text(QAccessible::Name), QString());
+ QCOMPARE(label2->text(QAccessible::Description), QString());
+ QCOMPARE(label2->text(QAccessible::Value), QStringLiteral("Provide both first and last name."));
+
+ // Good day! [edit]
+ QAccessibleInterface *grouping5 = document->child(4);
+ QAccessibleInterface *input3 = grouping5->child(0);
+ QCOMPARE(input3->role(), QAccessible::EditableText);
+ QCOMPARE(input3->text(QAccessible::Name), QStringLiteral("day"));
+ QCOMPARE(input3->text(QAccessible::Description), QString());
+ QCOMPARE(input3->text(QAccessible::Value), QStringLiteral("Good day!"));
}
void tst_QWebEngineView::value()