Commit f3ae656a authored by Nektarios Paisios's avatar Nektarios Paisios Committed by Commit Bot

Expose anonymous editable blocks to a11y

Anonymous blocks were not correctly marked as editable and richly editable in Blink and thus unnecessarily ignored affecting selection on Windows.

R=dmazzoni@chromium.org

Bug: 831179
Change-Id: Ic53ad29e63d7e9bbfd775ce5f933f20e7ea656f5
Tested: Layout test
Reviewed-on: https://chromium-review.googlesource.com/1004925
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561308}
parent 85a03bc2
<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<div id="editable" contenteditable="true">
Hello
<div>there</div>
</div>
<script>
test(() => {
let editable = accessibilityController.accessibleElementById('editable');
assert_not_equals(editable, null);
assert_equals(editable.childrenCount, 2);
let anonymousBlock = editable.childAtIndex(0);
assert_not_equals(anonymousBlock, null);
assert_equals(anonymousBlock.childrenCount, 1);
assert_equals(anonymousBlock.childAtIndex(0).role, 'AXRole: AXStaticText');
assert_equals(anonymousBlock.childAtIndex(0).name, 'Hello');
assert_true(anonymousBlock.isEditable);
assert_true(anonymousBlock.isRichlyEditable);
}, 'Ensure that anonymous blocks inside content editables are not ignored and are marked as editable.');
</script>
PASS NonGroupDescendants(accessibilityController.focusedElement) is 6
PASS successfullyParsed is true
TEST COMPLETE
Inline continuations - accessibility tree linkage
This test checks that the right accessibility tree is generated in the presence of inline continuations. Each of the five numbers below should be visited only ones traversing the accessibility tree.
1
2
34
3 4
5
PASS nonGroupDescendants(accessibilityController.focusedElement) is 5
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<head>
<title>Inline continuations - accessibility tree linkage</title>
<script src="../resources/js-test.js"></script>
<script>
if (window.testRunner)
testRunner.dumpAsText();
</script>
<title>Inline continuations - accessibility tree linkage</title>
<script src="../resources/js-test.js"></script>
<script>
if (window.testRunner)
testRunner.dumpAsText();
</script>
</head>
<body>
<h2>Inline continuations - accessibility tree linkage</h2>
<p>This test checks that the right accessibility tree is generated in
the presence of inline continuations. Each of the five numbers
below should be visited only ones traversing the accessibility
tree.</p>
<h2>Inline continuations - accessibility tree linkage</h2>
<div contentEditable="true" id="test"><span>1<div role="group">2</div>3</span><span>4</span><div role="group">5</div></div>
<p>This test checks that the right accessibility tree is generated in the
presence of inline continuations. Each of the five numbers below should
be visited only ones traversing the accessibility tree.
</p>
<div id="console"></div>
<div contentEditable="true">
<span>1<div role="group">2</div>3</span>
<span>4</span>
<div role="group">5</div>
</div>
<script>
function nonGroupDescendants(elt)
{
var result = 0;
var count = elt.childrenCount;
for (var i = 0; i < count; ++i) {
var child = elt.childAtIndex(i);
if (child.role != 'AXRole: AXGroup' && child.role != 'AXRole: AXInlineTextBox')
result++;
result += nonGroupDescendants(child);
function NonGroupDescendants(elt) {
let result = 0;
let count = elt.childrenCount;
for (let i = 0; i < count; ++i) {
child = elt.childAtIndex(i);
if (child.role != 'AXRole: AXGroup' &&
child.role != 'AXRole: AXInlineTextBox' &&
child.role != 'AXRole: AXGenericContainer') {
result++;
}
return result;
result += NonGroupDescendants(child);
}
return result;
}
if (window.accessibilityController) {
var result = document.getElementById("result");
document.getElementById("test").focus();
shouldBe("nonGroupDescendants(accessibilityController.focusedElement)", "5");
// This should pass (and is a simpler test than above) if anonymous blocks were not in the AX tree
// shouldBe("accessibilityController.focusedElement.childrenCount", "5");
document.querySelector('[contenteditable]').focus();
// The layout engine inserts an additional static text element containing a
// space between "3" and "4".
shouldBe('NonGroupDescendants(accessibilityController.focusedElement)', '6');
}
</script>
</body>
......@@ -333,10 +333,17 @@ static bool IsLinkable(const AXObject& object) {
// Requires layoutObject to be present because it relies on style
// user-modify. Don't move this logic to AXNodeObject.
bool AXLayoutObject::IsEditable() const {
if (GetLayoutObject() && GetLayoutObject()->IsTextControl())
if (IsDetached())
return false;
if (GetLayoutObject()->IsTextControl())
return true;
if (GetNode() && HasEditableStyle(*GetNode()))
const Node* node = GetNodeOrContainingBlockNode();
if (!node)
return false;
if (HasEditableStyle(*node))
return true;
if (IsWebArea()) {
......@@ -356,7 +363,14 @@ bool AXLayoutObject::IsEditable() const {
// Requires layoutObject to be present because it relies on style
// user-modify. Don't move this logic to AXNodeObject.
bool AXLayoutObject::IsRichlyEditable() const {
if (GetNode() && HasRichlyEditableStyle(*GetNode()))
if (IsDetached())
return false;
const Node* node = GetNodeOrContainingBlockNode();
if (!node)
return false;
if (HasRichlyEditableStyle(*node))
return true;
if (IsWebArea()) {
......@@ -1749,6 +1763,16 @@ Node* AXLayoutObject::GetNode() const {
return GetLayoutObject() ? GetLayoutObject()->GetNode() : nullptr;
}
Node* AXLayoutObject::GetNodeOrContainingBlockNode() const {
if (IsDetached())
return nullptr;
if (GetLayoutObject()->IsAnonymousBlock() &&
GetLayoutObject()->ContainingBlock()) {
return GetLayoutObject()->ContainingBlock()->GetNode();
}
return GetNode();
}
Document* AXLayoutObject::GetDocument() const {
if (!GetLayoutObject())
return nullptr;
......
......@@ -169,6 +169,9 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// DOM and layout tree access.
Node* GetNode() const override;
// If this is an anonymous block, returns the node of its containing layout
// block, otherwise returns the node of this layout object.
Node* GetNodeOrContainingBlockNode() const;
Document* GetDocument() const override;
LocalFrameView* DocumentFrameView() const override;
Element* AnchorElement() const override;
......
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