Commit 8b8a2033 authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Commit Bot

Reuse BrowserAccessibility when reparenting so that events are correct

When a node is reparented we currently destroy it rather than actually
reusing it, causing it to look like a new node. New nodes do not fire
change events for name, state, value or live regions.

Impact:
- We need to reuse nodes if we want them to be able to fire change
events when they are reparented at the same time.
- Accessibility nodes can be unexpectedly reparented by the layout
engine, as shown in the included test.

Bug: 469254
Change-Id: I7aec0d7852c712724b97be4a723df3c928720d62
Reviewed-on: https://chromium-review.googlesource.com/1152477
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578750}
parent 0e9a676f
...@@ -1101,32 +1101,6 @@ void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree, ...@@ -1101,32 +1101,6 @@ void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree,
obj->OnSubtreeWillBeDeleted(); obj->OnSubtreeWillBeDeleted();
} }
void BrowserAccessibilityManager::OnNodeWillBeReparented(ui::AXTree* tree,
ui::AXNode* node) {
AXEventGenerator::OnNodeWillBeReparented(tree, node);
// BrowserAccessibility should probably ask the tree source for the AXNode via
// an id rather than weakly holding a pointer to a AXNode that might have been
// destroyed under the hood and re-created later on. Treat this as a delete to
// make things work.
if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
return;
GetFromAXNode(node)->Destroy();
id_wrapper_map_.erase(node->id());
}
void BrowserAccessibilityManager::OnSubtreeWillBeReparented(ui::AXTree* tree,
ui::AXNode* node) {
AXEventGenerator::OnSubtreeWillBeReparented(tree, node);
// BrowserAccessibility should probably ask the tree source for the AXNode via
// an id rather than weakly holding a pointer to a AXNode that might have been
// destroyed under the hood and re-created later on. Treat this as a delete to
// make things work.
DCHECK(node);
BrowserAccessibility* obj = GetFromAXNode(node);
if (obj)
obj->OnSubtreeWillBeDeleted();
}
void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree, void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
ui::AXNode* node) { ui::AXNode* node) {
AXEventGenerator::OnNodeCreated(tree, node); AXEventGenerator::OnNodeCreated(tree, node);
...@@ -1139,13 +1113,13 @@ void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree, ...@@ -1139,13 +1113,13 @@ void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
void BrowserAccessibilityManager::OnNodeReparented(ui::AXTree* tree, void BrowserAccessibilityManager::OnNodeReparented(ui::AXTree* tree,
ui::AXNode* node) { ui::AXNode* node) {
AXEventGenerator::OnNodeReparented(tree, node); AXEventGenerator::OnNodeReparented(tree, node);
// BrowserAccessibility should probably ask the tree source for the AXNode via BrowserAccessibility* wrapper = GetFromID(node->id());
// an id rather than weakly holding a pointer to a AXNode that might have been if (!wrapper) {
// destroyed under the hood and re-created later on. Treat this as a create to wrapper = factory_->Create();
// make things work. id_wrapper_map_[node->id()] = wrapper;
BrowserAccessibility* wrapper = factory_->Create(); }
wrapper->Init(this, node); wrapper->Init(this, node);
id_wrapper_map_[node->id()] = wrapper;
wrapper->OnDataChanged(); wrapper->OnDataChanged();
} }
......
...@@ -347,8 +347,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXEventGenerator { ...@@ -347,8 +347,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXEventGenerator {
// AXTreeDelegate implementation. // AXTreeDelegate implementation.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override; void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override;
......
...@@ -339,6 +339,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, ...@@ -339,6 +339,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("live-region-create.html")); RunEventTest(FILE_PATH_LITERAL("live-region-create.html"));
} }
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
AccessibilityEventsLiveRegionElemReparent) {
RunEventTest(FILE_PATH_LITERAL("live-region-elem-reparent.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
AccessibilityEventsLiveRegionIgnoresClick) { AccessibilityEventsLiveRegionIgnoresClick) {
RunEventTest(FILE_PATH_LITERAL("live-region-ignores-click.html")); RunEventTest(FILE_PATH_LITERAL("live-region-ignores-click.html"));
......
IA2_EVENT_TEXT_INSERTED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE new_text={'<obj><obj><obj>' start=0 end=3}
IA2_EVENT_TEXT_INSERTED on <p#message> role=P new_text={'This is important!' start=0 end=18}
\ No newline at end of file
<!--
@WIN-DENY:*
@WIN-ALLOW:IA2_EVENT_TEXT_INSERTED*
-->
<!DOCTYPE html>
<html>
<body>
<button onclick="onClick();">Click</button>
<div id="something" style="display: none;"></div>
<span aria-live="polite">
<p id="message" style="position:absolute"></p>
</span>
<script>
function go() {
document.querySelector('button').click();
}
function onClick() {
/* The <p> to gets reparented and updated text at the same time */
var something = document.querySelector('#something');
something.style.display = 'block';
var message = document.querySelector('#message');
message.textContent = 'This is important!';
}
</script>
</body>
</html>
\ No newline at end of file
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