Commit 70118de7 authored by Lucas Radaelli's avatar Lucas Radaelli Committed by Chromium LUCI CQ

[fuchsia][a11y] Implements support for multiple iframes.

This change implements support in the AccessibilityBridge to deal with
multiple semantic trees, each one representing an iframe.

The trees are combined before they are sent to Fuchsia into a single
semantic tree.

Test: AccessibilityBridgeTest.*
Bug: fuchsia:63612,fuchsia:63610,fuchsia64329
Change-Id: I174ec9db254647edb33ada5b31eb24595debe031
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2556462Reviewed-by: default avatarSharon Yang <yangsharon@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Commit-Queue: Lucas Radaelli <lucasradaelli@google.com>
Cr-Commit-Position: refs/heads/master@{#831997}
parent a83c51af
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <fuchsia/ui/views/cpp/fidl.h> #include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h> #include <lib/fidl/cpp/binding.h>
#include <base/containers/flat_map.h>
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
...@@ -52,7 +53,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -52,7 +53,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
AccessibilityBridge(const AccessibilityBridge&) = delete; AccessibilityBridge(const AccessibilityBridge&) = delete;
AccessibilityBridge& operator=(const AccessibilityBridge&) = delete; AccessibilityBridge& operator=(const AccessibilityBridge&) = delete;
const ui::AXSerializableTree* ax_tree_for_test() { return &ax_tree_; } const ui::AXSerializableTree* ax_tree_for_test();
void set_event_received_callback_for_test(base::OnceClosure callback) { void set_event_received_callback_for_test(base::OnceClosure callback) {
event_received_callback_for_test_ = std::move(callback); event_received_callback_for_test_ = std::move(callback);
...@@ -67,9 +68,37 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -67,9 +68,37 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
FRIEND_TEST_ALL_PREFIXES(AccessibilityBridgeTest, FRIEND_TEST_ALL_PREFIXES(AccessibilityBridgeTest,
TreeModificationsAreForwarded); TreeModificationsAreForwarded);
// Represents a connection between two AXTrees that are in different frames.
struct TreeConnection {
// ID of the node in the parent tree that points to this tree.
int32_t parent_node_id = 0;
// ID of the parent tree.
ui::AXTreeID parent_tree_id = ui::AXTreeIDUnknown();
// Whether the trees are connected.
bool is_connected = false;
};
// Processes pending data and commits it to the Semantic Tree. // Processes pending data and commits it to the Semantic Tree.
void TryCommit(); void TryCommit();
// Connects trees if they are present or deletes the connection if both are
// gone.
void UpdateTreeConnections();
// Returns true if the main frame AXTree is not present or if trees are not
// connected.
bool ShouldHoldCommit();
// The AXTreeID of a tree can change. Updates all internal references of an
// AXTreeID by fetching the RenderFrameHost associated with |tree_id| and
// updates the value if it is different from the previously used AXTreeID.
// Returns false if the frame does not exist anymore, true otherwise.
bool UpdateAXTreeID(const ui::AXTreeID& tree_id);
// If |tree| is connected to another tree as its child, mark them as
// disconnected.
void MaybeDisconnectTreeFromParentTree(ui::AXTree* tree);
// Callback for SemanticTree::CommitUpdates. // Callback for SemanticTree::CommitUpdates.
void OnCommitComplete(); void OnCommitComplete();
...@@ -84,6 +113,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -84,6 +113,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
// content::WebContentsObserver implementation. // content::WebContentsObserver implementation.
void AccessibilityEventReceived( void AccessibilityEventReceived(
const content::AXEventNotificationDetails& details) override; const content::AXEventNotificationDetails& details) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
// fuchsia::accessibility::semantics::SemanticListener implementation. // fuchsia::accessibility::semantics::SemanticListener implementation.
void OnAccessibilityActionRequested( void OnAccessibilityActionRequested(
...@@ -96,7 +126,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -96,7 +126,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
OnSemanticsModeChangedCallback callback) final; OnSemanticsModeChangedCallback callback) final;
// ui::AXTreeObserver implementation. // ui::AXTreeObserver implementation.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeDeleted(ui::AXTree* tree, int32_t node_id) override;
void OnAtomicUpdateFinished( void OnAtomicUpdateFinished(
ui::AXTree* tree, ui::AXTree* tree,
bool root_changed, bool root_changed,
...@@ -105,7 +135,19 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -105,7 +135,19 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
fuchsia::accessibility::semantics::SemanticTreePtr semantic_tree_; fuchsia::accessibility::semantics::SemanticTreePtr semantic_tree_;
fidl::Binding<fuchsia::accessibility::semantics::SemanticListener> binding_; fidl::Binding<fuchsia::accessibility::semantics::SemanticListener> binding_;
content::WebContents* web_contents_; content::WebContents* web_contents_;
ui::AXSerializableTree ax_tree_;
// Holds one semantic tree per iframe.
base::flat_map<ui::AXTreeID, std::unique_ptr<ui::AXSerializableTree>>
ax_trees_;
// Maps frames to AXTrees.
base::flat_map<content::GlobalFrameRoutingId, ui::AXTreeID>
frame_id_to_tree_id_;
// Keeps track of semantic trees connections.
// The key is the AXTreeID of the semantic tree that is connected to another
// tree.
base::flat_map<ui::AXTreeID, TreeConnection> tree_connections_;
// Whether semantic updates are enabled. // Whether semantic updates are enabled.
bool enable_semantic_updates_ = false; bool enable_semantic_updates_ = false;
...@@ -123,7 +165,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge ...@@ -123,7 +165,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge
// will cause the frame |this| is owned by to be torn down. // will cause the frame |this| is owned by to be torn down.
base::OnceCallback<void(zx_status_t)> on_error_callback_; base::OnceCallback<void(zx_status_t)> on_error_callback_;
// The root id of |ax_tree_|. // The root id of the AXTree of the main frame.
int32_t root_id_ = 0; int32_t root_id_ = 0;
// Maps node IDs from one platform to another. // Maps node IDs from one platform to another.
......
...@@ -659,9 +659,39 @@ IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, OutOfProcessIframe) { ...@@ -659,9 +659,39 @@ IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, OutOfProcessIframe) {
EXPECT_TRUE( EXPECT_TRUE(
semantics_manager_.semantic_tree()->GetNodeFromLabel(kPageIframeTitle)); semantics_manager_.semantic_tree()->GetNodeFromLabel(kPageIframeTitle));
// TODO(https://crbug.com/1128954): Add support for combining AXTrees. // Data that is part of the iframe should be in the semantic tree.
// Expect that the contents of the iframe are not available in the semantic EXPECT_TRUE(
// tree. semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
// Makes the iframe navigate to a different page.
GURL out_of_process_url_2 = second_test_server.GetURL(kPage2Path);
const auto script =
base::StringPrintf("document.getElementById(\"iframeId\").src = '%s'",
out_of_process_url_2.spec().c_str());
frame_ptr_->ExecuteJavaScript(
{"*"}, cr_fuchsia::MemBufferFromString(script, "test2"),
[](fuchsia::web::Frame_ExecuteJavaScript_Result result) {
CHECK(result.is_response());
});
semantics_manager_.semantic_tree()->RunUntilCommitCountIs(4);
// check that the iframe navigated to a different page.
EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
// Old iframe data should be gone.
EXPECT_FALSE( EXPECT_FALSE(
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1)); semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
// Makes the main page navigate to a different page, causing the iframe to go
// away.
LoadPage(kPage2Path, kPage2Title);
semantics_manager_.semantic_tree()->RunUntilCommitCountIs(5);
// We've navigated to a different page that has no iframes. Only one frame
// should be present.
num_frames = frame_impl_->web_contents_for_test()->GetAllFrames().size();
EXPECT_EQ(num_frames, 1);
} }
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