Commit 69ecbb7f authored by James Cook's avatar James Cook Committed by Commit Bot

chromeos: Fix ChromeVox highlight rects for shortcut viewer with hidpi

The serialized AX node locations need to be adjusted by the display
device scale factor. This is similar to how AXTreeSourceArc handles
remote ARC++ apps.

Bug: 851578
Test: added to views_mus_unittests
Change-Id: Ibf17c76584e1ec54e5b214866a7cd1abbcc88f7f
Reviewed-on: https://chromium-review.googlesource.com/1168120
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582226}
parent 1eca6385
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "ui/accessibility/platform/ax_unique_id.h" #include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/mus/window_tree_client.h" #include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/mus/ax_tree_source_mus.h" #include "ui/views/mus/ax_tree_source_mus.h"
#include "ui/views/mus/mus_client.h" #include "ui/views/mus/mus_client.h"
...@@ -20,6 +22,9 @@ ...@@ -20,6 +22,9 @@
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
using display::Display;
using display::Screen;
namespace views { namespace views {
// For external linkage. // For external linkage.
...@@ -68,12 +73,17 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) { ...@@ -68,12 +73,17 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper); tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper);
tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(tree_source_.get()); tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(tree_source_.get());
// Inform the serializer of the display device scale factor.
UpdateDeviceScaleFactor();
Screen::GetScreen()->AddObserver(this);
SendEvent(contents_wrapper, ax::mojom::Event::kLoadComplete); SendEvent(contents_wrapper, ax::mojom::Event::kLoadComplete);
} }
void AXRemoteHost::StopMonitoringWidget() { void AXRemoteHost::StopMonitoringWidget() {
DCHECK(widget_); DCHECK(widget_);
DCHECK(widget_->HasObserver(this)); DCHECK(widget_->HasObserver(this));
Screen::GetScreen()->RemoveObserver(this);
widget_->RemoveObserver(this); widget_->RemoveObserver(this);
AXAuraObjCache* cache = AXAuraObjCache::GetInstance(); AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
cache->OnRootWindowObjDestroyed(widget_->GetNativeWindow()); cache->OnRootWindowObjDestroyed(widget_->GetNativeWindow());
...@@ -129,6 +139,14 @@ void AXRemoteHost::OnWidgetDestroying(Widget* widget) { ...@@ -129,6 +139,14 @@ void AXRemoteHost::OnWidgetDestroying(Widget* widget) {
StopMonitoringWidget(); StopMonitoringWidget();
} }
void AXRemoteHost::OnDisplayMetricsChanged(const Display& display,
uint32_t metrics) {
if (metrics & display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR) {
UpdateDeviceScaleFactor();
SendEvent(tree_source_->GetRoot(), ax::mojom::Event::kLocationChanged);
}
}
void AXRemoteHost::OnChildWindowRemoved(AXAuraObjWrapper* parent) { void AXRemoteHost::OnChildWindowRemoved(AXAuraObjWrapper* parent) {
if (!enabled_ || !widget_) if (!enabled_ || !widget_)
return; return;
...@@ -186,9 +204,12 @@ void AXRemoteHost::Disable() { ...@@ -186,9 +204,12 @@ void AXRemoteHost::Disable() {
void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj, void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) { ax::mojom::Event event_type) {
DCHECK(aura_obj); DCHECK(aura_obj);
if (!enabled_ || !tree_serializer_) if (!enabled_ || !widget_)
return; return;
DCHECK(tree_source_);
DCHECK(tree_serializer_);
ui::AXTreeUpdate update; ui::AXTreeUpdate update;
if (!tree_serializer_->SerializeChanges(aura_obj, &update)) { if (!tree_serializer_->SerializeChanges(aura_obj, &update)) {
LOG(ERROR) << "Unable to serialize accessibility tree."; LOG(ERROR) << "Unable to serialize accessibility tree.";
...@@ -228,4 +249,14 @@ void AXRemoteHost::PerformHitTest(const ui::AXActionData& action) { ...@@ -228,4 +249,14 @@ void AXRemoteHost::PerformHitTest(const ui::AXActionData& action) {
hit_view->NotifyAccessibilityEvent(action.hit_test_event_to_fire, true); hit_view->NotifyAccessibilityEvent(action.hit_test_event_to_fire, true);
} }
void AXRemoteHost::UpdateDeviceScaleFactor() {
DCHECK(widget_);
DCHECK(tree_source_);
// Use the scale factor for the widget's window's current display.
Display display =
Screen::GetScreen()->GetDisplayNearestWindow(widget_->GetNativeWindow());
tree_source_->set_device_scale_factor(display.device_scale_factor());
}
} // namespace views } // namespace views
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "ui/accessibility/ax_tree_serializer.h" #include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/mojom/ax_host.mojom.h" #include "ui/accessibility/mojom/ax_host.mojom.h"
#include "ui/display/display_observer.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h" #include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/mus/mus_export.h" #include "ui/views/mus/mus_export.h"
#include "ui/views/widget/widget_observer.h" #include "ui/views/widget/widget_observer.h"
...@@ -37,6 +38,7 @@ class Widget; ...@@ -37,6 +38,7 @@ class Widget;
// (e.g. the keyboard shortcut viewer app). // (e.g. the keyboard shortcut viewer app).
class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost, class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
public WidgetObserver, public WidgetObserver,
public display::DisplayObserver,
public AXAuraObjCache::Delegate { public AXAuraObjCache::Delegate {
public: public:
// Well-known tree ID for the remote client. // Well-known tree ID for the remote client.
...@@ -68,6 +70,10 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost, ...@@ -68,6 +70,10 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void OnWidgetClosing(Widget* widget) override; void OnWidgetClosing(Widget* widget) override;
void OnWidgetDestroying(Widget* widget) override; void OnWidgetDestroying(Widget* widget) override;
// display::DisplayObserver:
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
// AXAuraObjCache::Delegate: // AXAuraObjCache::Delegate:
void OnChildWindowRemoved(AXAuraObjWrapper* parent) override; void OnChildWindowRemoved(AXAuraObjWrapper* parent) override;
void OnEvent(AXAuraObjWrapper* aura_obj, void OnEvent(AXAuraObjWrapper* aura_obj,
...@@ -88,6 +94,9 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost, ...@@ -88,6 +94,9 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void PerformHitTest(const ui::AXActionData& action); void PerformHitTest(const ui::AXActionData& action);
// Updates the display device scale factor used when serializing nodes.
void UpdateDeviceScaleFactor();
// Accessibility host service in the browser. // Accessibility host service in the browser.
ax::mojom::AXHostPtr ax_host_ptr_; ax::mojom::AXHostPtr ax_host_ptr_;
......
...@@ -8,8 +8,12 @@ ...@@ -8,8 +8,12 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/mojom/ax_host.mojom.h" #include "ui/accessibility/mojom/ax_host.mojom.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h" #include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/mus/mus_client_test_api.h" #include "ui/views/mus/mus_client_test_api.h"
#include "ui/views/mus/screen_mus.h"
#include "ui/views/test/views_test_base.h" #include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
...@@ -41,6 +45,7 @@ class TestAXHostService : public ax::mojom::AXHost { ...@@ -41,6 +45,7 @@ class TestAXHostService : public ax::mojom::AXHost {
const ui::AXEvent& event) override { const ui::AXEvent& event) override {
++event_count_; ++event_count_;
last_tree_id_ = tree_id; last_tree_id_ = tree_id;
last_updates_ = updates;
last_event_ = event; last_event_ = event;
} }
...@@ -49,6 +54,7 @@ class TestAXHostService : public ax::mojom::AXHost { ...@@ -49,6 +54,7 @@ class TestAXHostService : public ax::mojom::AXHost {
int add_client_count_ = 0; int add_client_count_ = 0;
int event_count_ = 0; int event_count_ = 0;
int last_tree_id_ = 0; int last_tree_id_ = 0;
std::vector<ui::AXTreeUpdate> last_updates_;
ui::AXEvent last_event_; ui::AXEvent last_event_;
private: private:
...@@ -241,5 +247,26 @@ TEST_F(AXRemoteHostTest, PerformHitTest) { ...@@ -241,5 +247,26 @@ TEST_F(AXRemoteHostTest, PerformHitTest) {
EXPECT_EQ(ax::mojom::Event::kNone, view.last_event_type_); EXPECT_EQ(ax::mojom::Event::kNone, view.last_event_type_);
} }
TEST_F(AXRemoteHostTest, ScaleFactor) {
// Set the primary display to high DPI.
ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
display::Display display = screen->GetPrimaryDisplay();
display.set_device_scale_factor(2.f);
screen->display_list().UpdateDisplay(display);
// Create a widget.
TestAXHostService service(true /*automation_enabled*/);
AXRemoteHost* remote = CreateRemote(&service);
std::unique_ptr<Widget> widget = CreateTestWidget();
remote->FlushForTesting();
// Widget transform is scaled by a factor of 2.
ASSERT_FALSE(service.last_updates_.empty());
gfx::Transform* transform = service.last_updates_[0].nodes[0].transform.get();
ASSERT_TRUE(transform);
EXPECT_TRUE(transform->IsScale2d());
EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), transform->Scale2d());
}
} // namespace } // namespace
} // namespace views } // namespace views
...@@ -34,7 +34,15 @@ void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node, ...@@ -34,7 +34,15 @@ void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
// However, the contents view in the host (browser) already has an offset // However, the contents view in the host (browser) already has an offset
// from its Widget, so the root should start at (0,0). // from its Widget, so the root should start at (0,0).
out_data->location.set_origin(gfx::PointF()); out_data->location.set_origin(gfx::PointF());
out_data->transform.reset();
// Adjust for display device scale factor.
if (device_scale_factor_ == 1.f) {
// The AX system represents the identity transform with null.
out_data->transform.reset();
} else {
out_data->transform = std::make_unique<gfx::Transform>();
out_data->transform->Scale(device_scale_factor_, device_scale_factor_);
}
return; return;
} }
......
...@@ -23,6 +23,8 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews { ...@@ -23,6 +23,8 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
explicit AXTreeSourceMus(AXAuraObjWrapper* root); explicit AXTreeSourceMus(AXAuraObjWrapper* root);
~AXTreeSourceMus() override; ~AXTreeSourceMus() override;
void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
// AXTreeSource: // AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override; bool GetTreeData(ui::AXTreeData* data) const override;
AXAuraObjWrapper* GetRoot() const override; AXAuraObjWrapper* GetRoot() const override;
...@@ -33,6 +35,9 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews { ...@@ -33,6 +35,9 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
// The top-level object to use for the AX tree. // The top-level object to use for the AX tree.
AXAuraObjWrapper* root_; AXAuraObjWrapper* root_;
// The display device scale factor to use while serializing this update.
float device_scale_factor_ = 1.f;
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMus); DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMus);
}; };
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "ui/accessibility/ax_tree_data.h" #include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_unique_id.h" #include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h" #include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
...@@ -86,5 +88,23 @@ TEST_F(AXTreeSourceMusTest, Serialize) { ...@@ -86,5 +88,23 @@ TEST_F(AXTreeSourceMusTest, Serialize) {
EXPECT_EQ(root->GetUniqueId().Get(), node_data.offset_container_id); EXPECT_EQ(root->GetUniqueId().Get(), node_data.offset_container_id);
} }
TEST_F(AXTreeSourceMusTest, ScaleFactor) {
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
// Simulate serializing a widget on a high-dpi display.
AXTreeSourceMus tree(root);
tree.set_device_scale_factor(2.f);
// Serialize the root.
ui::AXNodeData node_data;
tree.SerializeNode(root, &node_data);
// Transform is scaled.
ASSERT_TRUE(node_data.transform);
EXPECT_TRUE(node_data.transform->IsScale2d());
EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), node_data.transform->Scale2d());
}
} // namespace } // namespace
} // namespace views } // namespace views
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