[fuchsia][a11y] Add code path to instantiate v2 accessibility bridge.
This change adds a code path by which FrameImpl can instantiate the v2 accessibility bridge. We also add a new set of browsertests for the new accessibility bridge. AX-Relnotes: n/a Test: Accessibility*Test.* Bug: fuchsia:90880 Change-Id: Ie96af26fdd2b247f14c1ebdad6e074dc218bc995 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3389994 Reviewed-by: Sergey Ulanov <sergeyu@chromium.org> Reviewed-by: David Tseng <dtseng@chromium.org> Commit-Queue: Alexander Brusher <abrusher@google.com> Cr-Commit-Position: refs/heads/main@{#969651}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4fdf8bb596
commit
78c1a67268
@ -430,6 +430,7 @@ source_set("browsertest_core") {
|
||||
test("web_engine_browsertests") {
|
||||
sources = [
|
||||
"browser/accessibility_bridge_browsertest.cc",
|
||||
"browser/accessibility_browsertest.cc",
|
||||
"browser/autoplay_browsertest.cc",
|
||||
"browser/cast_streaming_browsertest.cc",
|
||||
"browser/client_hints_browsertest.cc",
|
||||
|
@ -54,7 +54,7 @@ AccessibilityBridge::AccessibilityBridge(
|
||||
fuchsia::accessibility::semantics::SemanticsManager* semantics_manager,
|
||||
FrameWindowTreeHost* window_tree_host,
|
||||
content::WebContents* web_contents,
|
||||
base::OnceCallback<void(zx_status_t)> on_error_callback,
|
||||
base::OnceCallback<bool(zx_status_t)> on_error_callback,
|
||||
inspect::Node inspect_node)
|
||||
: binding_(this),
|
||||
window_tree_host_(window_tree_host),
|
||||
|
@ -53,7 +53,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge final
|
||||
fuchsia::accessibility::semantics::SemanticsManager* semantics_manager,
|
||||
FrameWindowTreeHost* window_tree_host,
|
||||
content::WebContents* web_contents,
|
||||
base::OnceCallback<void(zx_status_t)> on_error_callback,
|
||||
base::OnceCallback<bool(zx_status_t)> on_error_callback,
|
||||
inspect::Node inspect_node);
|
||||
~AccessibilityBridge() override;
|
||||
|
||||
@ -246,7 +246,7 @@ class WEB_ENGINE_EXPORT AccessibilityBridge final
|
||||
|
||||
// Run in the case of an internal error that cannot be recovered from. This
|
||||
// will cause the frame |this| is owned by to be torn down.
|
||||
base::OnceCallback<void(zx_status_t)> on_error_callback_;
|
||||
base::OnceCallback<bool(zx_status_t)> on_error_callback_;
|
||||
|
||||
// The root id of the AXTree of the main frame.
|
||||
int32_t root_id_ = 0;
|
||||
|
@ -53,6 +53,9 @@ const size_t kPage2NodeCount = 190;
|
||||
const size_t kInitialRangeValue = 51;
|
||||
const size_t kStepSize = 3;
|
||||
|
||||
// Simulated screen bounds to use when testing the SemanticsManager.
|
||||
constexpr gfx::Size kTestWindowSize = {720, 640};
|
||||
|
||||
fuchsia::math::PointF GetCenterOfBox(fuchsia::ui::gfx::BoundingBox box) {
|
||||
fuchsia::math::PointF center;
|
||||
center.x = (box.min.x + box.max.x) / 2;
|
||||
@ -131,6 +134,11 @@ class AccessibilityBridgeTest : public cr_fuchsia::WebEngineBrowserTest {
|
||||
|
||||
frame_impl_ = context_impl()->GetFrameImplForTest(&frame_.ptr());
|
||||
frame_impl_->set_semantics_manager_for_test(&semantics_manager_);
|
||||
frame_impl_->set_window_size_for_test(kTestWindowSize);
|
||||
|
||||
// TODO(crbug.com/1291330): Remove uses of
|
||||
// set_use_v2_accessibility_bridge().
|
||||
frame_impl_->set_use_v2_accessibility_bridge(false);
|
||||
frame_->EnableHeadlessRendering();
|
||||
|
||||
semantics_manager_.WaitUntilViewRegistered();
|
||||
|
611
fuchsia/engine/browser/accessibility_browsertest.cc
Normal file
611
fuchsia/engine/browser/accessibility_browsertest.cc
Normal file
@ -0,0 +1,611 @@
|
||||
// Copyright 2022 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 <fuchsia/accessibility/semantics/cpp/fidl.h>
|
||||
#include <lib/ui/scenic/cpp/view_ref_pair.h>
|
||||
#include <zircon/types.h>
|
||||
|
||||
#include "base/fuchsia/mem_buffer_util.h"
|
||||
#include "base/fuchsia/scoped_service_binding.h"
|
||||
#include "base/fuchsia/test_component_context_for_process.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "fuchsia/base/test/frame_test_util.h"
|
||||
#include "fuchsia/base/test/test_navigation_listener.h"
|
||||
#include "fuchsia/engine/browser/accessibility_bridge.h"
|
||||
#include "fuchsia/engine/browser/context_impl.h"
|
||||
#include "fuchsia/engine/browser/fake_semantics_manager.h"
|
||||
#include "fuchsia/engine/browser/frame_impl.h"
|
||||
#include "fuchsia/engine/test/frame_for_test.h"
|
||||
#include "fuchsia/engine/test/test_data.h"
|
||||
#include "fuchsia/engine/test/web_engine_browser_test.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "ui/accessibility/ax_action_data.h"
|
||||
#include "ui/accessibility/ax_tree_observer.h"
|
||||
#include "ui/accessibility/platform/fuchsia/ax_platform_node_fuchsia.h"
|
||||
#include "ui/gfx/switches.h"
|
||||
#include "ui/ozone/public/ozone_switches.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kPage1Path[] = "/ax1.html";
|
||||
const char kPage2Path[] = "/batching.html";
|
||||
const char kPageIframePath[] = "/iframe.html";
|
||||
const char kPage1Title[] = "accessibility 1";
|
||||
const char kPage2Title[] = "lots of nodes!";
|
||||
const char kPageIframeTitle[] = "iframe title";
|
||||
const char kButtonName1[] = "a button";
|
||||
const char kButtonName2[] = "another button";
|
||||
const char kButtonName3[] = "button 3";
|
||||
const char kNodeName[] = "last node";
|
||||
const char kParagraphName[] = "a third paragraph";
|
||||
const char kOffscreenNodeName[] = "offscreen node";
|
||||
const size_t kPage1NodeCount = 29;
|
||||
const size_t kPage2NodeCount = 190;
|
||||
|
||||
const size_t kInitialRangeValue = 51;
|
||||
const size_t kStepSize = 3;
|
||||
|
||||
// Simulated screen bounds to use.
|
||||
constexpr gfx::Size kTestWindowSize = {720, 640};
|
||||
|
||||
fuchsia::math::PointF GetCenterOfBox(fuchsia::ui::gfx::BoundingBox box) {
|
||||
fuchsia::math::PointF center;
|
||||
center.x = (box.min.x + box.max.x) / 2;
|
||||
center.y = (box.min.y + box.max.y) / 2;
|
||||
return center;
|
||||
}
|
||||
|
||||
// Returns whether or not the given node supports the given action.
|
||||
bool HasAction(const fuchsia::accessibility::semantics::Node& node,
|
||||
fuchsia::accessibility::semantics::Action action) {
|
||||
for (const auto& node_action : node.actions()) {
|
||||
if (node_action == action)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class FuchsiaFrameAccessibilityTest : public cr_fuchsia::WebEngineBrowserTest {
|
||||
public:
|
||||
FuchsiaFrameAccessibilityTest() {
|
||||
cr_fuchsia::WebEngineBrowserTest::set_test_server_root(
|
||||
base::FilePath(cr_fuchsia::kTestServerRoot));
|
||||
}
|
||||
|
||||
~FuchsiaFrameAccessibilityTest() override = default;
|
||||
|
||||
FuchsiaFrameAccessibilityTest(const FuchsiaFrameAccessibilityTest&) = delete;
|
||||
FuchsiaFrameAccessibilityTest& operator=(
|
||||
const FuchsiaFrameAccessibilityTest&) = delete;
|
||||
|
||||
void SetUp() override {
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
command_line->AppendSwitchNative(switches::kOzonePlatform,
|
||||
switches::kHeadless);
|
||||
command_line->AppendSwitch(switches::kHeadless);
|
||||
cr_fuchsia::WebEngineBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
void SetUpOnMainThread() override {
|
||||
test_context_.emplace(
|
||||
base::TestComponentContextForProcess::InitialState::kCloneAll);
|
||||
cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread();
|
||||
|
||||
// Remove the injected a11y manager from /svc; otherwise, we won't be able
|
||||
// to replace it with the fake owned by the test fixture.
|
||||
test_context_->additional_services()
|
||||
->RemovePublicService<
|
||||
fuchsia::accessibility::semantics::SemanticsManager>();
|
||||
semantics_manager_binding_.emplace(test_context_->additional_services(),
|
||||
&semantics_manager_);
|
||||
|
||||
frame_ = cr_fuchsia::FrameForTest::Create(context(), {});
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
frame_impl_ = context_impl()->GetFrameImplForTest(&frame_.ptr());
|
||||
frame_impl_->set_window_size_for_test(kTestWindowSize);
|
||||
frame_impl_->set_use_v2_accessibility_bridge(true);
|
||||
frame_->EnableHeadlessRendering();
|
||||
|
||||
semantics_manager_.WaitUntilViewRegistered();
|
||||
ASSERT_TRUE(semantics_manager_.is_view_registered());
|
||||
ASSERT_TRUE(semantics_manager_.is_listener_valid());
|
||||
|
||||
ASSERT_TRUE(embedded_test_server()->Start());
|
||||
|
||||
// Change the accessibility mode on the Fuchsia side and check that it is
|
||||
// propagated correctly.
|
||||
ASSERT_FALSE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
|
||||
semantics_manager_.SetSemanticsModeEnabled(true);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
ASSERT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
}
|
||||
|
||||
void LoadPage(base::StringPiece url, base::StringPiece page_title) {
|
||||
GURL page_url(embedded_test_server()->GetURL(std::string(url)));
|
||||
ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
|
||||
frame_.GetNavigationController(), fuchsia::web::LoadUrlParams(),
|
||||
page_url.spec()));
|
||||
frame_.navigation_listener().RunUntilUrlAndTitleEquals(page_url,
|
||||
page_title);
|
||||
}
|
||||
|
||||
protected:
|
||||
// TODO(crbug.com/1038786): Maybe move to WebEngineBrowserTest.
|
||||
absl::optional<base::TestComponentContextForProcess> test_context_;
|
||||
|
||||
cr_fuchsia::FrameForTest frame_;
|
||||
FrameImpl* frame_impl_;
|
||||
FakeSemanticsManager semantics_manager_;
|
||||
|
||||
// Binding to the fake semantics manager.
|
||||
// Optional so that it can be instantiated outside the constructor.
|
||||
absl::optional<base::ScopedServiceBinding<
|
||||
fuchsia::accessibility::semantics::SemanticsManager>>
|
||||
semantics_manager_binding_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, CorrectDataSent) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
// Check that the data values are correct in the FakeSemanticTree.
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
|
||||
}
|
||||
|
||||
// Batching is performed when the number of nodes to send or delete exceeds the
|
||||
// maximum, as set on the Fuchsia side. Check that all nodes are received by the
|
||||
// Semantic Tree when batching is performed.
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, DataSentWithBatching) {
|
||||
LoadPage(kPage2Path, kPage2Title);
|
||||
|
||||
// Run until we expect more than a batch's worth of nodes to be present.
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
|
||||
EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
|
||||
|
||||
// Checks if the actual batching happened.
|
||||
EXPECT_GE(semantics_manager_.semantic_tree()->num_update_calls(), 18u);
|
||||
|
||||
// Checks if one or more commit calls were made to send the data.
|
||||
EXPECT_GE(semantics_manager_.semantic_tree()->num_commit_calls(), 1u);
|
||||
}
|
||||
|
||||
// Check that semantics information is correctly sent when navigating from page
|
||||
// to page.
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, NavigateFromPageToPage) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
|
||||
|
||||
LoadPage(kPage2Path, kPage2Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeWithLabelIsInTree(
|
||||
kPage2Title);
|
||||
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage2Title));
|
||||
EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
|
||||
|
||||
// Check that data from the first page has been deleted successfully.
|
||||
EXPECT_FALSE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
|
||||
EXPECT_FALSE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
|
||||
}
|
||||
|
||||
// Checks that the correct node ID is returned when performing hit testing.
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, HitTest) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
fuchsia::accessibility::semantics::Node* target_node =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName);
|
||||
EXPECT_TRUE(target_node);
|
||||
|
||||
fuchsia::math::PointF target_point = GetCenterOfBox(target_node->location());
|
||||
|
||||
float scale_factor = 20.f;
|
||||
// Make the bridge use scaling in hit test calculations.
|
||||
frame_impl_->set_device_scale_factor_for_test(scale_factor);
|
||||
|
||||
// Downscale the target point, since the hit test calculation will scale it
|
||||
// back up.
|
||||
target_point.x /= scale_factor;
|
||||
target_point.y /= scale_factor;
|
||||
|
||||
uint32_t hit_node_id =
|
||||
semantics_manager_.HitTestAtPointSync(std::move(target_point));
|
||||
fuchsia::accessibility::semantics::Node* hit_node =
|
||||
semantics_manager_.semantic_tree()->GetNodeWithId(hit_node_id);
|
||||
|
||||
EXPECT_EQ(hit_node->attributes().label(), kParagraphName);
|
||||
|
||||
// Expect hit testing to return the root when the point given is out of
|
||||
// bounds or there is no semantic node at that position.
|
||||
target_point.x = -1;
|
||||
target_point.y = -1;
|
||||
EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
|
||||
target_point.x = 1. / scale_factor;
|
||||
target_point.y = 1. / scale_factor;
|
||||
EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, PerformDefaultAction) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
fuchsia::accessibility::semantics::Node* button1 =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
|
||||
EXPECT_TRUE(button1);
|
||||
fuchsia::accessibility::semantics::Node* button2 =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
|
||||
EXPECT_TRUE(button2);
|
||||
fuchsia::accessibility::semantics::Node* button3 =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName3);
|
||||
EXPECT_TRUE(button3);
|
||||
|
||||
EXPECT_TRUE(
|
||||
HasAction(*button1, fuchsia::accessibility::semantics::Action::DEFAULT));
|
||||
|
||||
EXPECT_TRUE(semantics_manager_.RequestAccessibilityActionSync(
|
||||
button1->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest,
|
||||
PerformUnsupportedAction) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
fuchsia::accessibility::semantics::Node* button1 =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
|
||||
EXPECT_TRUE(button1);
|
||||
fuchsia::accessibility::semantics::Node* button2 =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
|
||||
EXPECT_TRUE(button2);
|
||||
|
||||
// Attempt to perform unsupported action.
|
||||
EXPECT_FALSE(semantics_manager_.RequestAccessibilityActionSync(
|
||||
button2->node_id(),
|
||||
fuchsia::accessibility::semantics::Action::SECONDARY));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, Disconnect) {
|
||||
base::RunLoop run_loop;
|
||||
frame_.ptr().set_error_handler([&run_loop](zx_status_t status) {
|
||||
EXPECT_EQ(ZX_ERR_INTERNAL, status);
|
||||
run_loop.Quit();
|
||||
});
|
||||
|
||||
semantics_manager_.semantic_tree()->Disconnect();
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest,
|
||||
PerformScrollToMakeVisible) {
|
||||
// Set the screen height to be small so that we can detect if we've
|
||||
// scrolled past our target, even if the max scroll is bounded.
|
||||
constexpr int kScreenWidth = 720;
|
||||
constexpr int kScreenHeight = 20;
|
||||
gfx::Rect screen_bounds(kScreenWidth, kScreenHeight);
|
||||
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
auto* semantic_tree = semantics_manager_.semantic_tree();
|
||||
ASSERT_TRUE(semantic_tree);
|
||||
|
||||
semantic_tree->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
auto* content_view =
|
||||
frame_impl_->web_contents_for_test()->GetContentNativeView();
|
||||
content_view->SetBounds(screen_bounds);
|
||||
|
||||
// Get a node that is off the screen, and verify that it is off the screen.
|
||||
fuchsia::accessibility::semantics::Node* fuchsia_node =
|
||||
semantic_tree->GetNodeFromLabel(kOffscreenNodeName);
|
||||
ASSERT_TRUE(fuchsia_node);
|
||||
|
||||
// Get the corresponding AXPlatformNode.
|
||||
auto* fuchsia_platform_node = static_cast<ui::AXPlatformNodeFuchsia*>(
|
||||
ui::AXPlatformNodeBase::GetFromUniqueId(fuchsia_node->node_id()));
|
||||
ASSERT_TRUE(fuchsia_platform_node);
|
||||
auto* delegate = fuchsia_platform_node->GetDelegate();
|
||||
|
||||
ui::AXOffscreenResult offscreen_result;
|
||||
delegate->GetClippedScreenBoundsRect(&offscreen_result);
|
||||
EXPECT_EQ(offscreen_result, ui::AXOffscreenResult::kOffscreen);
|
||||
|
||||
// Perform SHOW_ON_SCREEN on that node.
|
||||
EXPECT_TRUE(semantics_manager_.RequestAccessibilityActionSync(
|
||||
fuchsia_node->node_id(),
|
||||
fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN));
|
||||
|
||||
semantic_tree->RunUntilConditionIsTrue(
|
||||
base::BindLambdaForTesting([semantic_tree]() {
|
||||
auto* root = semantic_tree->GetNodeWithId(0u);
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
// Once the scroll action has been handled, the root should have a
|
||||
// non-zero y-scroll offset.
|
||||
return root->has_states() && root->states().has_viewport_offset() &&
|
||||
root->states().viewport_offset().y > 0;
|
||||
}));
|
||||
|
||||
// Verify that the AXNode we tried to make visible is now onscreen.
|
||||
delegate->GetClippedScreenBoundsRect(&offscreen_result);
|
||||
EXPECT_EQ(offscreen_result, ui::AXOffscreenResult::kOnscreen);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, Slider) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
fuchsia::accessibility::semantics::Node* node =
|
||||
semantics_manager_.semantic_tree()->GetNodeFromRole(
|
||||
fuchsia::accessibility::semantics::Role::SLIDER);
|
||||
EXPECT_TRUE(node);
|
||||
EXPECT_TRUE(node->has_states() && node->states().has_range_value());
|
||||
EXPECT_EQ(node->states().range_value(), kInitialRangeValue);
|
||||
|
||||
base::RunLoop run_loop;
|
||||
semantics_manager_.semantic_tree()->SetNodeUpdatedCallback(
|
||||
node->node_id(), run_loop.QuitClosure());
|
||||
|
||||
semantics_manager_.RequestAccessibilityActionSync(
|
||||
node->node_id(), fuchsia::accessibility::semantics::Action::INCREMENT);
|
||||
run_loop.Run();
|
||||
|
||||
node = semantics_manager_.semantic_tree()->GetNodeWithId(node->node_id());
|
||||
EXPECT_TRUE(node->has_states() && node->states().has_range_value());
|
||||
EXPECT_EQ(node->states().range_value(), kInitialRangeValue + kStepSize);
|
||||
}
|
||||
|
||||
// This test makes sure that when semantic updates toggle on / off / on, the
|
||||
// full semantic tree is sent in the first update when back on.
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, TogglesSemanticsUpdates) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
semantics_manager_.SetSemanticsModeEnabled(false);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_FALSE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
|
||||
// The tree gets cleared when semantic updates are off.
|
||||
EXPECT_EQ(semantics_manager_.semantic_tree()->tree_size(), 0u);
|
||||
semantics_manager_.SetSemanticsModeEnabled(true);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_TRUE(frame_impl_->web_contents_for_test()
|
||||
->IsFullAccessibilityModeForTesting());
|
||||
}
|
||||
|
||||
// This test performs several tree modifications (insertions, changes, and
|
||||
// removals). All operations must leave the tree in a valid state and
|
||||
// also forward the nodes in a way that leaves the tree in the Fuchsia side in a
|
||||
// valid state. Note that every time that a new tree is sent to Fuchsia, the
|
||||
// FakeSemantiTree checks if the tree is valid.
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest,
|
||||
TreeModificationsAreForwarded) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
auto* semantic_tree = semantics_manager_.semantic_tree();
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
// Create a new HTML element.
|
||||
{
|
||||
const auto script = base::StringPrintf(
|
||||
"var p = document.createElement(\"p\"); var text = "
|
||||
"document.createTextNode(\"new_label\"); p.appendChild(text); "
|
||||
"document.body.appendChild(p);");
|
||||
|
||||
frame_->ExecuteJavaScript(
|
||||
{"*"}, base::MemBufferFromString(script, "add node"),
|
||||
[](fuchsia::web::Frame_ExecuteJavaScript_Result result) {
|
||||
CHECK(result.is_response());
|
||||
});
|
||||
|
||||
semantic_tree->RunUntilNodeWithLabelIsInTree("new_label");
|
||||
}
|
||||
|
||||
// Remove an HTML element.
|
||||
{
|
||||
// Verify that slider is present initially.
|
||||
EXPECT_TRUE(semantic_tree->GetNodeFromRole(
|
||||
fuchsia::accessibility::semantics::Role::SLIDER));
|
||||
|
||||
const auto script = base::StringPrintf(
|
||||
"var slider = document.getElementById(\"myRange\"); slider.remove();");
|
||||
|
||||
frame_->ExecuteJavaScript(
|
||||
{"*"}, base::MemBufferFromString(script, "reparent nodes"),
|
||||
[](fuchsia::web::Frame_ExecuteJavaScript_Result result) {
|
||||
CHECK(result.is_response());
|
||||
});
|
||||
|
||||
semantic_tree->RunUntilConditionIsTrue(
|
||||
base::BindLambdaForTesting([semantic_tree]() {
|
||||
return !semantic_tree->GetNodeFromRole(
|
||||
fuchsia::accessibility::semantics::Role::SLIDER);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, OutOfProcessIframe) {
|
||||
constexpr int64_t kBindingsId = 1234;
|
||||
|
||||
// Start a different embedded test server, and load a page on it. The URL for
|
||||
// this page will have a different port and be considered out of process when
|
||||
// used as the src for an iframe.
|
||||
net::EmbeddedTestServer second_test_server;
|
||||
second_test_server.ServeFilesFromSourceDirectory(
|
||||
base::FilePath(cr_fuchsia::kTestServerRoot));
|
||||
ASSERT_TRUE(second_test_server.Start());
|
||||
GURL out_of_process_url = second_test_server.GetURL(kPage1Path);
|
||||
|
||||
// Before loading a page on the default embedded test server, set the iframe
|
||||
// src to be |out_of_process_url|.
|
||||
frame_->AddBeforeLoadJavaScript(
|
||||
kBindingsId, {"*"},
|
||||
base::MemBufferFromString(
|
||||
base::StringPrintf("iframeSrc = '%s'",
|
||||
out_of_process_url.spec().c_str()),
|
||||
"test"),
|
||||
[](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) {
|
||||
CHECK(result.is_response());
|
||||
});
|
||||
LoadPage(kPageIframePath, "iframe loaded");
|
||||
|
||||
// Run until the title of the iframe page is in the semantic tree. Because
|
||||
// the iframe's semantic tree is only sent when it is connected to the parent
|
||||
// tree, it is guaranteed that both trees will be present.
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeWithLabelIsInTree(
|
||||
kPage1Title);
|
||||
|
||||
// Two frames should be present.
|
||||
int num_frames = CollectAllRenderFrameHosts(
|
||||
frame_impl_->web_contents_for_test()->GetPrimaryPage())
|
||||
.size();
|
||||
|
||||
EXPECT_EQ(num_frames, 2);
|
||||
|
||||
// Check that the iframe node has been loaded.
|
||||
EXPECT_TRUE(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kPageIframeTitle));
|
||||
|
||||
// Data that is part of the iframe should be in the semantic tree.
|
||||
EXPECT_TRUE(
|
||||
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_->ExecuteJavaScript(
|
||||
{"*"}, base::MemBufferFromString(script, "test2"),
|
||||
[](fuchsia::web::Frame_ExecuteJavaScript_Result result) {
|
||||
CHECK(result.is_response());
|
||||
});
|
||||
|
||||
semantics_manager_.semantic_tree()->RunUntilNodeWithLabelIsInTree(
|
||||
kPage2Title);
|
||||
|
||||
// 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(
|
||||
semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
|
||||
|
||||
// Makes the main page navigate to a different page, causing the iframe to go
|
||||
// away.
|
||||
LoadPage(kPage2Path, kPage2Title);
|
||||
|
||||
// Wait for the root to be updated, which means that we navigated to a new
|
||||
// page.
|
||||
base::RunLoop run_loop;
|
||||
semantics_manager_.semantic_tree()->SetNodeUpdatedCallback(
|
||||
0u, run_loop.QuitClosure());
|
||||
run_loop.Run();
|
||||
|
||||
// We've navigated to a different page that has no iframes. Only one frame
|
||||
// should be present.
|
||||
num_frames = CollectAllRenderFrameHosts(
|
||||
frame_impl_->web_contents_for_test()->GetPrimaryPage())
|
||||
.size();
|
||||
|
||||
EXPECT_EQ(num_frames, 1);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(FuchsiaFrameAccessibilityTest, UpdatesFocusInformation) {
|
||||
LoadPage(kPage1Path, kPage1Title);
|
||||
|
||||
auto* semantic_tree = semantics_manager_.semantic_tree();
|
||||
semantic_tree->RunUntilNodeCountAtLeast(kPage1NodeCount);
|
||||
|
||||
// Get a node that is off the screen, and verify that it is off the screen.
|
||||
fuchsia::accessibility::semantics::Node* fuchsia_node =
|
||||
semantic_tree->GetNodeFromLabel(kButtonName1);
|
||||
ASSERT_TRUE(fuchsia_node);
|
||||
EXPECT_FALSE(fuchsia_node->states().has_input_focus());
|
||||
|
||||
// Get the corresponding AXPlatformNode.
|
||||
auto* fuchsia_platform_node = static_cast<ui::AXPlatformNodeFuchsia*>(
|
||||
ui::AXPlatformNodeBase::GetFromUniqueId(fuchsia_node->node_id()));
|
||||
ASSERT_TRUE(fuchsia_platform_node);
|
||||
|
||||
// Focus the node.
|
||||
ui::AXActionData action_data;
|
||||
action_data.action = ax::mojom::Action::kFocus;
|
||||
fuchsia_platform_node->PerformAction(action_data);
|
||||
|
||||
semantic_tree->RunUntilConditionIsTrue(
|
||||
base::BindLambdaForTesting([semantic_tree, fuchsia_node]() {
|
||||
auto* node = semantic_tree->GetNodeWithId(fuchsia_node->node_id());
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
return node->has_states() && node->states().has_has_input_focus() &&
|
||||
node->states().has_input_focus();
|
||||
}));
|
||||
|
||||
// Changes the focus to a different node and checks that the old value is
|
||||
// cleared.
|
||||
fuchsia::accessibility::semantics::Node* new_focus_node =
|
||||
semantic_tree->GetNodeFromLabel(kButtonName2);
|
||||
ASSERT_TRUE(new_focus_node);
|
||||
|
||||
// Get the corresponding AXPlatformNode.
|
||||
auto* new_focus_platform_node = static_cast<ui::AXPlatformNodeFuchsia*>(
|
||||
ui::AXPlatformNodeBase::GetFromUniqueId(new_focus_node->node_id()));
|
||||
ASSERT_TRUE(new_focus_platform_node);
|
||||
|
||||
// Focus the new node. We can reuse the original action data.
|
||||
new_focus_platform_node->PerformAction(action_data);
|
||||
|
||||
semantic_tree->RunUntilConditionIsTrue(base::BindLambdaForTesting(
|
||||
[semantic_tree, new_focus_id = new_focus_node->node_id(),
|
||||
old_focus_id = fuchsia_node->node_id()]() {
|
||||
auto* old_focus = semantic_tree->GetNodeWithId(old_focus_id);
|
||||
auto* node = semantic_tree->GetNodeWithId(new_focus_id);
|
||||
|
||||
if (!node || !old_focus)
|
||||
return false;
|
||||
|
||||
// Node has the focus, root does not.
|
||||
return (node->has_states() && node->states().has_has_input_focus() &&
|
||||
node->states().has_input_focus()) &&
|
||||
(old_focus->has_states() &&
|
||||
old_focus->states().has_has_input_focus() &&
|
||||
!old_focus->states().has_input_focus());
|
||||
}));
|
||||
}
|
@ -49,6 +49,21 @@ void FakeSemanticsManager::CheckNumActions() {
|
||||
}
|
||||
}
|
||||
|
||||
bool FakeSemanticsManager::RequestAccessibilityActionSync(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action) {
|
||||
base::RunLoop run_loop;
|
||||
bool action_handled = false;
|
||||
listener_->OnAccessibilityActionRequested(
|
||||
node_id, action, [&action_handled, &run_loop](bool handled) {
|
||||
action_handled = handled;
|
||||
run_loop.QuitClosure().Run();
|
||||
});
|
||||
run_loop.Run();
|
||||
|
||||
return action_handled;
|
||||
}
|
||||
|
||||
void FakeSemanticsManager::RequestAccessibilityAction(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action) {
|
||||
|
@ -43,11 +43,18 @@ class FakeSemanticsManager : public fuchsia::accessibility::semantics::testing::
|
||||
// A helper function for RequestAccessibilityAction.
|
||||
void CheckNumActions();
|
||||
|
||||
// TODO(crbug.com/1291330): Remove async RequestAccessibilityAction(), and
|
||||
// replace with RequestAccessibilityActionSync().
|
||||
// Request the client to perform |action| on the node with |node_id|.
|
||||
void RequestAccessibilityAction(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action);
|
||||
|
||||
// Request the client to perform |action| on the node with |node_id|.
|
||||
bool RequestAccessibilityActionSync(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action);
|
||||
|
||||
// Runs until |num_actions| accessibility actions have been handled.
|
||||
void RunUntilNumActionsHandledEquals(int32_t num_actions);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
@ -61,6 +62,7 @@
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
|
||||
#include "third_party/blink/public/mojom/navigation/was_activated_option.mojom.h"
|
||||
#include "ui/accessibility/platform/fuchsia/semantic_provider_impl.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/compositor/compositor.h"
|
||||
#include "ui/gfx/switches.h"
|
||||
@ -73,9 +75,6 @@ namespace {
|
||||
// Simulated screen bounds to use when headless rendering is enabled.
|
||||
constexpr gfx::Size kHeadlessWindowSize = {1, 1};
|
||||
|
||||
// Simulated screen bounds to use when testing the SemanticsManager.
|
||||
constexpr gfx::Size kSemanticsTestingWindowSize = {720, 640};
|
||||
|
||||
// Name of the Inspect node that holds accessibility information.
|
||||
constexpr char kAccessibilityInspectNodeName[] = "accessibility";
|
||||
|
||||
@ -533,6 +532,7 @@ void FrameImpl::DestroyWindowTreeHost() {
|
||||
window_tree_host_->compositor()->SetVisible(false);
|
||||
window_tree_host_.reset();
|
||||
accessibility_bridge_.reset();
|
||||
v2_accessibility_bridge_.reset();
|
||||
|
||||
// Allows posted focus events to process before the FocusController is torn
|
||||
// down.
|
||||
@ -556,12 +556,17 @@ void FrameImpl::OnMediaPlayerDisconnect() {
|
||||
media_player_ = nullptr;
|
||||
}
|
||||
|
||||
void FrameImpl::OnAccessibilityError(zx_status_t error) {
|
||||
bool FrameImpl::OnAccessibilityError(zx_status_t error) {
|
||||
// The task is posted so |accessibility_bridge_| does not tear |this| down
|
||||
// while events are still being processed.
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&FrameImpl::CloseAndDestroyFrame,
|
||||
weak_factory_.GetWeakPtr(), error));
|
||||
|
||||
// The return value indicates to the accessibility bridge whether we should
|
||||
// attempt to reconnect. Since the frame has been destroyed, no reconnect
|
||||
// attempt should be made.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrameImpl::MaybeHandleCastStreamingMessage(
|
||||
@ -617,22 +622,38 @@ void FrameImpl::UpdateRenderViewZoomLevel(
|
||||
}
|
||||
|
||||
void FrameImpl::ConnectToAccessibilityBridge() {
|
||||
fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager;
|
||||
if (!semantics_manager_for_test_) {
|
||||
semantics_manager =
|
||||
base::ComponentContextForProcess()
|
||||
->svc()
|
||||
->Connect<fuchsia::accessibility::semantics::SemanticsManager>();
|
||||
}
|
||||
if (use_v2_accessibility_bridge_) {
|
||||
// TODO(crbug.com/1291613): Replace callbacks with an interface that
|
||||
// FrameImpl implements.
|
||||
v2_accessibility_bridge_ =
|
||||
std::make_unique<ui::AccessibilityBridgeFuchsiaImpl>(
|
||||
root_window(), window_tree_host_->CreateViewRef(),
|
||||
base::BindRepeating(&FrameImpl::GetDeviceScaleFactor,
|
||||
base::Unretained(this)),
|
||||
base::BindRepeating(&FrameImpl::SetAccessibilityEnabled,
|
||||
base::Unretained(this)),
|
||||
base::BindRepeating(&FrameImpl::OnAccessibilityError,
|
||||
base::Unretained(this)),
|
||||
inspect_node_.CreateChild(kAccessibilityInspectNodeName));
|
||||
} else {
|
||||
fuchsia::accessibility::semantics::SemanticsManagerPtr semantics_manager;
|
||||
if (!semantics_manager_for_test_) {
|
||||
semantics_manager =
|
||||
base::ComponentContextForProcess()
|
||||
->svc()
|
||||
->Connect<fuchsia::accessibility::semantics::SemanticsManager>();
|
||||
}
|
||||
|
||||
// If the SemanticTree owned by |accessibility_bridge_| is disconnected, it
|
||||
// will cause |this| to be closed.
|
||||
accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
|
||||
semantics_manager_for_test_ ? semantics_manager_for_test_
|
||||
: semantics_manager.get(),
|
||||
window_tree_host_.get(), web_contents_.get(),
|
||||
base::BindOnce(&FrameImpl::OnAccessibilityError, base::Unretained(this)),
|
||||
inspect_node_.CreateChild(kAccessibilityInspectNodeName));
|
||||
// If the SemanticTree owned by |accessibility_bridge_| is disconnected, it
|
||||
// will cause |this| to be closed.
|
||||
accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
|
||||
semantics_manager_for_test_ ? semantics_manager_for_test_
|
||||
: semantics_manager.get(),
|
||||
window_tree_host_.get(), web_contents_.get(),
|
||||
base::BindOnce(&FrameImpl::OnAccessibilityError,
|
||||
base::Unretained(this)),
|
||||
inspect_node_.CreateChild(kAccessibilityInspectNodeName));
|
||||
}
|
||||
}
|
||||
|
||||
void FrameImpl::CreateView(fuchsia::ui::views::ViewToken view_token) {
|
||||
@ -896,11 +917,10 @@ void FrameImpl::EnableHeadlessRendering() {
|
||||
std::move(view_ref_pair));
|
||||
|
||||
gfx::Rect bounds(kHeadlessWindowSize);
|
||||
if (semantics_manager_for_test_) {
|
||||
ConnectToAccessibilityBridge();
|
||||
|
||||
// Set bounds for testing hit testing.
|
||||
bounds.set_size(kSemanticsTestingWindowSize);
|
||||
if (window_size_for_test_) {
|
||||
ConnectToAccessibilityBridge();
|
||||
bounds.set_size(*window_size_for_test_);
|
||||
}
|
||||
|
||||
window_tree_host_->SetBoundsInPixels(bounds);
|
||||
@ -1334,3 +1354,22 @@ void FrameImpl::ResourceLoadComplete(
|
||||
void FrameImpl::EnableExplicitSitesFilter(std::string error_page) {
|
||||
explicit_sites_filter_error_page_ = std::move(error_page);
|
||||
}
|
||||
|
||||
float FrameImpl::GetDeviceScaleFactor() {
|
||||
if (device_scale_factor_for_test_)
|
||||
return *device_scale_factor_for_test_;
|
||||
|
||||
return window_tree_host_->scenic_scale_factor();
|
||||
}
|
||||
|
||||
void FrameImpl::SetAccessibilityEnabled(bool enabled) {
|
||||
auto* browser_accessibility_state =
|
||||
content::BrowserAccessibilityState::GetInstance();
|
||||
|
||||
if (enabled) {
|
||||
browser_accessibility_state->AddAccessibilityModeFlags(ui::kAXModeComplete);
|
||||
} else {
|
||||
browser_accessibility_state->RemoveAccessibilityModeFlags(
|
||||
ui::kAXModeComplete);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "fuchsia/engine/browser/theme_manager.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "ui/accessibility/platform/fuchsia/accessibility_bridge_fuchsia_impl.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/wm/core/focus_controller.h"
|
||||
#include "url/gurl.h"
|
||||
@ -115,6 +116,15 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
return web_contents_.get();
|
||||
}
|
||||
bool has_view_for_test() const { return window_tree_host_ != nullptr; }
|
||||
FrameWindowTreeHost* window_tree_host_for_test() {
|
||||
return window_tree_host_.get();
|
||||
}
|
||||
|
||||
// Accessibility bridge accessor/setter methods.
|
||||
// TODO(crbug.com/1291330): Remove the three methods below.
|
||||
void set_use_v2_accessibility_bridge(bool use_v2_accessibility_bridge) {
|
||||
use_v2_accessibility_bridge_ = use_v2_accessibility_bridge;
|
||||
}
|
||||
AccessibilityBridge* accessibility_bridge_for_test() const {
|
||||
return accessibility_bridge_.get();
|
||||
}
|
||||
@ -122,9 +132,6 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
fuchsia::accessibility::semantics::SemanticsManager* semantics_manager) {
|
||||
semantics_manager_for_test_ = semantics_manager;
|
||||
}
|
||||
FrameWindowTreeHost* window_tree_host_for_test() {
|
||||
return window_tree_host_.get();
|
||||
}
|
||||
|
||||
// Override |blink_prefs| with settings defined in |content_settings_|.
|
||||
//
|
||||
@ -132,6 +139,14 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
// recomputed.
|
||||
void OverrideWebPreferences(blink::web_pref::WebPreferences* web_prefs);
|
||||
|
||||
void set_window_size_for_test(gfx::Size size) {
|
||||
window_size_for_test_ = size;
|
||||
}
|
||||
|
||||
void set_device_scale_factor_for_test(float device_scale_factor) {
|
||||
device_scale_factor_for_test_ = device_scale_factor;
|
||||
}
|
||||
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(FrameImplTest, DelayedNavigationEventAck);
|
||||
FRIEND_TEST_ALL_PREFIXES(FrameImplTest, NavigationObserverDisconnected);
|
||||
@ -169,7 +184,7 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
void OnMediaPlayerDisconnect();
|
||||
|
||||
// An error handler for |accessibility_bridge_|.
|
||||
void OnAccessibilityError(zx_status_t error);
|
||||
bool OnAccessibilityError(zx_status_t error);
|
||||
|
||||
// Creates and initializes WindowTreeHost for the view with the specified
|
||||
// |view_token|. |view_token| may be uninitialized in headless mode.
|
||||
@ -330,6 +345,9 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
const content::GlobalRequestID& request_id,
|
||||
const blink::mojom::ResourceLoadInfo& resource_load_info) override;
|
||||
|
||||
float GetDeviceScaleFactor();
|
||||
void SetAccessibilityEnabled(bool enabled);
|
||||
|
||||
const std::unique_ptr<content::WebContents> web_contents_;
|
||||
ContextImpl* const context_;
|
||||
|
||||
@ -350,9 +368,16 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
// Owned via |window_tree_host_|.
|
||||
FrameLayoutManager* layout_manager_ = nullptr;
|
||||
|
||||
// TODO(crbug.com/1291330): Remove acessibility_bridge_ and
|
||||
// semantics_manager_for_test_.
|
||||
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
|
||||
fuchsia::accessibility::semantics::SemanticsManager*
|
||||
semantics_manager_for_test_ = nullptr;
|
||||
std::unique_ptr<ui::AccessibilityBridgeFuchsiaImpl> v2_accessibility_bridge_;
|
||||
|
||||
// Test settings.
|
||||
absl::optional<gfx::Size> window_size_for_test_;
|
||||
absl::optional<float> device_scale_factor_for_test_;
|
||||
|
||||
EventFilter event_filter_;
|
||||
NavigationControllerImpl navigation_controller_;
|
||||
@ -391,6 +416,10 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
inspect::Node inspect_node_;
|
||||
const inspect::StringProperty inspect_name_property_;
|
||||
|
||||
// TODO(crbug.com/1291330): Remove.
|
||||
// Used to control which accessibility bridge version is live.
|
||||
bool use_v2_accessibility_bridge_ = false;
|
||||
|
||||
base::WeakPtrFactory<FrameImpl> weak_factory_{this};
|
||||
};
|
||||
|
||||
|
@ -122,11 +122,6 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, MAYBE_VisibilityState) {
|
||||
|
||||
auto frame = cr_fuchsia::FrameForTest::Create(context(), {});
|
||||
base::RunLoop().RunUntilIdle();
|
||||
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame.ptr());
|
||||
|
||||
// CreateView() will cause the AccessibilityBridge to be created.
|
||||
FakeSemanticsManager fake_semantics_manager;
|
||||
frame_impl->set_semantics_manager_for_test(&fake_semantics_manager);
|
||||
|
||||
// Navigate to a page and wait for it to finish loading.
|
||||
ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
|
||||
@ -308,10 +303,6 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, ContextDeletedBeforeFrameWithView) {
|
||||
base::RunLoop().RunUntilIdle();
|
||||
FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame.ptr());
|
||||
|
||||
// CreateView() will cause the AccessibilityBridge to be created.
|
||||
FakeSemanticsManager fake_semantics_manager;
|
||||
frame_impl->set_semantics_manager_for_test(&fake_semantics_manager);
|
||||
|
||||
auto view_tokens = scenic::ViewTokenPair::New();
|
||||
frame->CreateView(std::move(view_tokens.view_token));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
@ -1048,10 +1039,6 @@ IN_PROC_BROWSER_TEST_F(FrameImplTest, RecreateView) {
|
||||
ASSERT_TRUE(frame_impl);
|
||||
EXPECT_FALSE(frame_impl->has_view_for_test());
|
||||
|
||||
// CreateView() will cause the AccessibilityBridge to be created.
|
||||
FakeSemanticsManager fake_semantics_manager;
|
||||
frame_impl->set_semantics_manager_for_test(&fake_semantics_manager);
|
||||
|
||||
// Verify that the Frame can navigate, prior to the View being created.
|
||||
const GURL page1_url(embedded_test_server()->GetURL(kPage1Path));
|
||||
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
|
||||
|
@ -53,7 +53,7 @@ AccessibilityBridgeFuchsiaImpl::AccessibilityBridgeFuchsiaImpl(
|
||||
fuchsia::ui::views::ViewRef view_ref,
|
||||
base::RepeatingCallback<float()> get_pixel_scale,
|
||||
base::RepeatingCallback<void(bool)> on_semantics_enabled,
|
||||
base::RepeatingCallback<bool()> on_connection_closed,
|
||||
OnConnectionClosedCallback on_connection_closed,
|
||||
inspect::Node inspect_node)
|
||||
: root_window_(window),
|
||||
on_semantics_enabled_(std::move(on_semantics_enabled)),
|
||||
@ -232,9 +232,10 @@ void AccessibilityBridgeFuchsiaImpl::OnSemanticsEnabled(bool enabled) {
|
||||
on_semantics_enabled_.Run(enabled);
|
||||
}
|
||||
|
||||
bool AccessibilityBridgeFuchsiaImpl::OnSemanticsManagerConnectionClosed() {
|
||||
bool AccessibilityBridgeFuchsiaImpl::OnSemanticsManagerConnectionClosed(
|
||||
zx_status_t status) {
|
||||
if (on_connection_closed_)
|
||||
return on_connection_closed_.Run();
|
||||
return on_connection_closed_.Run(status);
|
||||
|
||||
// If the user does not specify a callback, then we can assume no attempt to
|
||||
// reconnect should be made.
|
||||
|
@ -23,6 +23,8 @@ class AX_EXPORT AccessibilityBridgeFuchsiaImpl final
|
||||
: public ui::AccessibilityBridgeFuchsia,
|
||||
public ui::AXFuchsiaSemanticProvider::Delegate {
|
||||
public:
|
||||
using OnConnectionClosedCallback = base::RepeatingCallback<bool(zx_status_t)>;
|
||||
|
||||
// Constructor args:
|
||||
//
|
||||
// |root_window|: Refers to the root aura::Window for which this accessibility
|
||||
@ -52,7 +54,7 @@ class AX_EXPORT AccessibilityBridgeFuchsiaImpl final
|
||||
fuchsia::ui::views::ViewRef view_ref,
|
||||
base::RepeatingCallback<float()> get_pixel_scale,
|
||||
base::RepeatingCallback<void(bool)> on_semantics_enabled,
|
||||
base::RepeatingCallback<bool()> on_connection_closed,
|
||||
OnConnectionClosedCallback on_connection_closed,
|
||||
inspect::Node inspect_node);
|
||||
~AccessibilityBridgeFuchsiaImpl() override;
|
||||
|
||||
@ -66,7 +68,7 @@ class AX_EXPORT AccessibilityBridgeFuchsiaImpl final
|
||||
inspect::Node GetInspectNode() override;
|
||||
|
||||
// SemanticProvider::Delegate overrides.
|
||||
bool OnSemanticsManagerConnectionClosed() override;
|
||||
bool OnSemanticsManagerConnectionClosed(zx_status_t status) override;
|
||||
bool OnAccessibilityAction(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action) override;
|
||||
@ -111,7 +113,10 @@ class AX_EXPORT AccessibilityBridgeFuchsiaImpl final
|
||||
base::RepeatingCallback<void(bool)> on_semantics_enabled_;
|
||||
|
||||
// Callback invoked whenever the semantics manager connection is closed.
|
||||
base::RepeatingCallback<bool()> on_connection_closed_;
|
||||
// We use a base::RepeatingCallback, because we may attempt to reconnect, in
|
||||
// which case it's possible that we may need to invoke the callback more than
|
||||
// once.
|
||||
OnConnectionClosedCallback on_connection_closed_;
|
||||
|
||||
// The inspect output will have a node for each AXTree in this accessibility
|
||||
// bridge's window. Inspect node names are static, but AXTreeIDs can change.
|
||||
|
@ -101,7 +101,7 @@ class AccessibilityBridgeFuchsiaTest : public ::testing::Test {
|
||||
/*root_window=*/nullptr, std::move(view_ref_pair.view_ref),
|
||||
base::BindRepeating([]() { return 1.0f; }),
|
||||
base::RepeatingCallback<void(bool)>(),
|
||||
base::RepeatingCallback<bool()>(), inspect::Node());
|
||||
base::RepeatingCallback<bool(zx_status_t)>(), inspect::Node());
|
||||
accessibility_bridge_->set_semantic_provider_for_test(
|
||||
std::move(mock_semantic_provider));
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class AX_EXPORT AXFuchsiaSemanticProvider {
|
||||
|
||||
// Called when the FIDL channel to the Semantics Manager is closed. If this
|
||||
// callback returns true, an attempt to reconnect will be made.
|
||||
virtual bool OnSemanticsManagerConnectionClosed() = 0;
|
||||
virtual bool OnSemanticsManagerConnectionClosed(zx_status_t status) = 0;
|
||||
|
||||
// Processes an incoming accessibility action from Fuchsia. It
|
||||
// receives the Fuchsia node ID and the action requested. If this
|
||||
|
@ -78,7 +78,7 @@ AXFuchsiaSemanticProviderImpl::AXFuchsiaSemanticProviderImpl(
|
||||
semantic_tree_.NewRequest());
|
||||
semantic_tree_.set_error_handler([this](zx_status_t status) {
|
||||
ZX_LOG(ERROR, status) << "SemanticTree disconnected";
|
||||
delegate_->OnSemanticsManagerConnectionClosed();
|
||||
delegate_->OnSemanticsManagerConnectionClosed(status);
|
||||
semantic_updates_enabled_ = false;
|
||||
});
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class AXFuchsiaSemanticProviderDelegate
|
||||
AXFuchsiaSemanticProviderDelegate() = default;
|
||||
~AXFuchsiaSemanticProviderDelegate() override = default;
|
||||
|
||||
bool OnSemanticsManagerConnectionClosed() override {
|
||||
bool OnSemanticsManagerConnectionClosed(zx_status_t status) override {
|
||||
on_semantics_manager_connection_closed_called_ = true;
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user