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 @@
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/mus/window_tree_client.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/mus/ax_tree_source_mus.h"
#include "ui/views/mus/mus_client.h"
......@@ -20,6 +22,9 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
using display::Display;
using display::Screen;
namespace views {
// For external linkage.
......@@ -68,12 +73,17 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper);
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);
}
void AXRemoteHost::StopMonitoringWidget() {
DCHECK(widget_);
DCHECK(widget_->HasObserver(this));
Screen::GetScreen()->RemoveObserver(this);
widget_->RemoveObserver(this);
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
cache->OnRootWindowObjDestroyed(widget_->GetNativeWindow());
......@@ -129,6 +139,14 @@ void AXRemoteHost::OnWidgetDestroying(Widget* widget) {
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) {
if (!enabled_ || !widget_)
return;
......@@ -186,9 +204,12 @@ void AXRemoteHost::Disable() {
void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) {
DCHECK(aura_obj);
if (!enabled_ || !tree_serializer_)
if (!enabled_ || !widget_)
return;
DCHECK(tree_source_);
DCHECK(tree_serializer_);
ui::AXTreeUpdate update;
if (!tree_serializer_->SerializeChanges(aura_obj, &update)) {
LOG(ERROR) << "Unable to serialize accessibility tree.";
......@@ -228,4 +249,14 @@ void AXRemoteHost::PerformHitTest(const ui::AXActionData& action) {
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
......@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "ui/accessibility/ax_tree_serializer.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/mus/mus_export.h"
#include "ui/views/widget/widget_observer.h"
......@@ -37,6 +38,7 @@ class Widget;
// (e.g. the keyboard shortcut viewer app).
class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
public WidgetObserver,
public display::DisplayObserver,
public AXAuraObjCache::Delegate {
public:
// Well-known tree ID for the remote client.
......@@ -68,6 +70,10 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void OnWidgetClosing(Widget* widget) override;
void OnWidgetDestroying(Widget* widget) override;
// display::DisplayObserver:
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
// AXAuraObjCache::Delegate:
void OnChildWindowRemoved(AXAuraObjWrapper* parent) override;
void OnEvent(AXAuraObjWrapper* aura_obj,
......@@ -88,6 +94,9 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void PerformHitTest(const ui::AXActionData& action);
// Updates the display device scale factor used when serializing nodes.
void UpdateDeviceScaleFactor();
// Accessibility host service in the browser.
ax::mojom::AXHostPtr ax_host_ptr_;
......
......@@ -8,8 +8,12 @@
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.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/mus/mus_client_test_api.h"
#include "ui/views/mus/screen_mus.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
......@@ -41,6 +45,7 @@ class TestAXHostService : public ax::mojom::AXHost {
const ui::AXEvent& event) override {
++event_count_;
last_tree_id_ = tree_id;
last_updates_ = updates;
last_event_ = event;
}
......@@ -49,6 +54,7 @@ class TestAXHostService : public ax::mojom::AXHost {
int add_client_count_ = 0;
int event_count_ = 0;
int last_tree_id_ = 0;
std::vector<ui::AXTreeUpdate> last_updates_;
ui::AXEvent last_event_;
private:
......@@ -241,5 +247,26 @@ TEST_F(AXRemoteHostTest, PerformHitTest) {
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 views
......@@ -34,7 +34,15 @@ void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
// However, the contents view in the host (browser) already has an offset
// from its Widget, so the root should start at (0,0).
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;
}
......
......@@ -23,6 +23,8 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
explicit AXTreeSourceMus(AXAuraObjWrapper* root);
~AXTreeSourceMus() override;
void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
// AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override;
AXAuraObjWrapper* GetRoot() const override;
......@@ -33,6 +35,9 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
// The top-level object to use for the AX tree.
AXAuraObjWrapper* root_;
// The display device scale factor to use while serializing this update.
float device_scale_factor_ = 1.f;
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMus);
};
......
......@@ -12,6 +12,8 @@
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_unique_id.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_wrapper.h"
#include "ui/views/controls/label.h"
......@@ -86,5 +88,23 @@ TEST_F(AXTreeSourceMusTest, Serialize) {
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 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