diff options
-rw-r--r-- | src/core/browser_accessibility_qt.cpp | 82 | ||||
-rw-r--r-- | src/core/browser_accessibility_qt.h | 3 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp | 70 |
3 files changed, 136 insertions, 19 deletions
diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index d2710b0ea..405bafb94 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 b8cd9e67d..8dfffdcff 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 7668a12ab..c61b5eff7 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() |