Commit 6f53c4d2 authored by Joanmarie Diggs's avatar Joanmarie Diggs Committed by Commit Bot

Don't emit accessible text events from non-text or invisible objects

Fixes three dcheck failures, each of which is related to attempting to
emit AtkText events on objects which should not emit them. Therefore
add checks to EmitsAtkTextEvents to ensure AtkText is implemented for
the object, and that the object is not invisible or ignored.

In addition:

* For an HTMLMediaElement whose sole content is text (i.e. no player
  and no source), do not expose any children and treat as included
  but ignored.
* Always include Role::kVideo and Role::kAudio in the internal
  accessibility tree, even when ignored, for consistency.

AX-Relnotes: N/A as there is no change in end-user experience.

Bug: 1041414, 1104047, 1104048
Change-Id: Id643f148fdaba3c865c6cefe8f20151c3181135b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2297431
Commit-Queue: Joanmarie Diggs <jdiggs@igalia.com>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791541}
parent 2edf00f8
......@@ -810,6 +810,16 @@ IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("text-selection-changed.html"));
}
IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
AccessibilityEventsTextSelectionInsideHiddenElement) {
RunEventTest(FILE_PATH_LITERAL("text-selection-inside-hidden-element.html"));
}
IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
AccessibilityEventsTextSelectionInsideVideo) {
RunEventTest(FILE_PATH_LITERAL("text-selection-inside-video.html"));
}
IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
AccessibilityEventsAriaCheckedChanged) {
RunEventTest(FILE_PATH_LITERAL("aria-checked-changed.html"));
......
......@@ -2326,6 +2326,10 @@ IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, DISABLED_AccessibilityVideo) {
RunHtmlTest(FILE_PATH_LITERAL("video.html"));
}
IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityVideoTextOnly) {
RunHtmlTest(FILE_PATH_LITERAL("video-text-only.html"));
}
IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
AccessibilityNodeChangedCrashInEditableText) {
RunHtmlTest(FILE_PATH_LITERAL("node-changed-crash-in-editable-text.html"));
......
CHILDREN-CHANGED index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
TEXT-CARET-MOVED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
<!--
@AURALINUX-DENY:STATE-CHANGE:DEFUNCT*
-->
<!DOCTYPE html>
<html>
<body>
<div>
<div id="unclosed-div">
<div tabindex="0"></div>
</div>
<select></select>
<div aria-hidden="true"><div id="empty"></div></div>
<script>
function go() {
document.getElementById("empty").appendChild(document.getElementById("unclosed-div"));
document.execCommand("selectAll", false);
}
</script>
</body>
</html>
TEXT-CARET-MOVED role=ROLE_SECTION name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE
TEXT-SELECTION-CHANGED role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
<!DOCTYPE html>
<html>
<body>1<video id="video">2</video><div id="div">3</div>
<script>
function go() {
document.execCommand("selectAll", false);
document.getSelection().extend(document.getElementById("video"), 0);
document.getSelection().extend(document.getElementById("div"), 0);
}
</script>
</body>
</html>
rootWebArea
++genericContainer ignored
++++genericContainer
++++++video ignored name='Unable to play media.' restriction=disabled
++++++staticText name=' '
++++++++inlineTextBox name=' '
++++++video ignored name='Unable to play media.' restriction=disabled
<!DOCTYPE html>
<html>
<body>
<video>text</video>
<video></video>
</body>
</html>
......@@ -41,6 +41,15 @@ String AccessibilityMediaElement::TextAlternative(
related_objects, name_sources);
}
bool AccessibilityMediaElement::CanHaveChildren() const {
return HasControls();
}
bool AccessibilityMediaElement::ComputeAccessibilityIsIgnored(
IgnoredReasons* ignored_reasons) const {
return !HasControls() && HasEmptySource();
}
AXRestriction AccessibilityMediaElement::Restriction() const {
if (IsUnplayable())
return kRestrictionDisabled;
......@@ -48,6 +57,15 @@ AXRestriction AccessibilityMediaElement::Restriction() const {
return AXNodeObject::Restriction();
}
bool AccessibilityMediaElement::HasControls() const {
return To<HTMLMediaElement>(GetNode())->ShouldShowControls();
}
bool AccessibilityMediaElement::HasEmptySource() const {
return To<HTMLMediaElement>(GetNode())->getNetworkState() ==
HTMLMediaElement::kNetworkEmpty;
}
bool AccessibilityMediaElement::IsUnplayable() const {
HTMLMediaElement* element =
static_cast<HTMLMediaElement*>(layout_object_->GetNode());
......
......@@ -29,9 +29,13 @@ class AccessibilityMediaElement : public AXLayoutObject {
NameSources*) const override;
// AXNodeObject overrides.
bool CanHaveChildren() const override;
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const override;
AXRestriction Restriction() const override;
protected:
bool HasControls() const;
bool HasEmptySource() const;
bool IsUnplayable() const;
DISALLOW_COPY_AND_ASSIGN(AccessibilityMediaElement);
......
......@@ -1501,6 +1501,13 @@ bool AXObject::ComputeAccessibilityIsIgnoredButIncludedInTree() const {
return false;
}
// Keep the internal accessibility tree consistent for videos which lack
// a player and also inner text.
if (RoleValue() == ax::mojom::blink::Role::kVideo ||
RoleValue() == ax::mojom::blink::Role::kAudio) {
return true;
}
// Always pass through Line Breaking objects, this is necessary to
// detect paragraph edges, which are defined as hard-line breaks.
if (IsLineBreakingObject())
......
......@@ -3644,6 +3644,15 @@ bool AXPlatformNodeAuraLinux::SelectionAndFocusAreTheSame() {
}
bool AXPlatformNodeAuraLinux::EmitsAtkTextEvents() const {
// Objects which do not implement AtkText cannot emit AtkText events.
if (!atk_object_ || !ATK_IS_TEXT(atk_object_))
return false;
// Objects which do implement AtkText, but are ignored or invisible should not
// emit AtkText events.
if (IsInvisibleOrIgnored())
return false;
// If this node is not a static text node, it supports the full AtkText
// interface.
if (GetAtkRole() != kStaticRole)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment