Commit f6b31ec0 authored by Marialicia Villarreal Garcia's avatar Marialicia Villarreal Garcia Committed by Commit Bot

Hit testing Views elements doesn't account for device scale factor

This fix is needed to make touch work in the browser frame
when a screen reader is on. It consists in two main parts:
1. Apply the scale factor to the hit point received after touching
any element in the frame.
2. Add unit tests for the scale factor.

Bug: 990560
Change-Id: I00c3cd4de4ea49e8e8f881eb1db17c6a649b873c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1796888
Commit-Queue: Maria Villarreal <mavill@microsoft.com>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Reviewed-by: default avatarKevin Babbitt <kbabbitt@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#697399}
parent a2ec149b
......@@ -5,10 +5,12 @@
#include "ui/accessibility/platform/ax_fragment_root_win.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/accessibility/platform/ax_platform_node_win_unittest.h"
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
#include <UIAutomationClient.h>
#include <UIAutomationCoreApi.h>
#include "base/auto_reset.h"
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -77,6 +79,13 @@ TEST_F(AXFragmentRootTest, TestUIAElementProviderFromPoint) {
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
47, 67, &provider_from_point));
EXPECT_EQ(root_provider.Get(), provider_from_point.Get());
// This is on node 1 with scale factor of 1.5.
std::unique_ptr<base::AutoReset<float>> scale_factor_reset =
TestAXNodeWrapper::SetScaleFactor(1.5);
EXPECT_HRESULT_SUCCEEDED(fragment_root_prov->ElementProviderFromPoint(
60, 60, &provider_from_point));
EXPECT_EQ(element1_provider.Get(), provider_from_point.Get());
}
TEST_F(AXFragmentRootTest, TestUIAGetFocus) {
......
......@@ -9,6 +9,7 @@
#include <memory>
#include "base/auto_reset.h"
#include "base/stl_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/win/atl.h"
......@@ -445,7 +446,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleDetachedObject) {
TEST_F(AXPlatformNodeWinTest, TestIAccessibleHitTest) {
AXNodeData root;
root.id = 1;
root.relative_bounds.bounds = gfx::RectF(0, 0, 30, 30);
root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40);
AXNodeData node1;
node1.id = 2;
......@@ -455,7 +456,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleHitTest) {
AXNodeData node2;
node2.id = 3;
node2.relative_bounds.bounds = gfx::RectF(20, 20, 10, 10);
node2.relative_bounds.bounds = gfx::RectF(20, 20, 20, 20);
node2.SetName("Name2");
root.child_ids.push_back(node2.id);
......@@ -463,17 +464,23 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleHitTest) {
ComPtr<IAccessible> root_obj(GetRootIAccessible());
ScopedVariant obj;
// This is way outside of the root node
EXPECT_EQ(S_FALSE, root_obj->accHitTest(50, 50, obj.Receive()));
EXPECT_EQ(VT_EMPTY, obj.type());
// this is directly on node 1.
EXPECT_EQ(S_OK, root_obj->accHitTest(5, 5, obj.Receive()));
ASSERT_NE(nullptr, obj.ptr());
CheckVariantHasName(obj, L"Name1");
// This is way outside of the root node.
ScopedVariant obj_1;
EXPECT_EQ(S_FALSE, root_obj->accHitTest(50, 50, obj_1.Receive()));
EXPECT_EQ(VT_EMPTY, obj_1.type());
// This is directly on node 1.
EXPECT_EQ(S_OK, root_obj->accHitTest(5, 5, obj_1.Receive()));
ASSERT_NE(nullptr, obj_1.ptr());
CheckVariantHasName(obj_1, L"Name1");
// This is directly on node 2 with a scale factor of 1.5.
ScopedVariant obj_2;
std::unique_ptr<base::AutoReset<float>> scale_factor_reset =
TestAXNodeWrapper::SetScaleFactor(1.5);
EXPECT_EQ(S_OK, root_obj->accHitTest(38, 38, obj_2.Receive()));
ASSERT_NE(nullptr, obj_2.ptr());
CheckVariantHasName(obj_2, L"Name2");
}
TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) {
......
......@@ -26,6 +26,9 @@ std::unordered_map<AXNode*, TestAXNodeWrapper*> g_node_to_wrapper_map;
// A global coordinate offset.
gfx::Vector2d g_offset;
// A global scale factor.
float g_scale_factor = 1.0;
// A global map that stores which node is focused on a determined tree.
// - If a tree has no node being focused, there shouldn't be any entry on the
// map associated with such tree, i.e. a pair {tree, nullptr} is invalid.
......@@ -88,6 +91,12 @@ const AXNode* TestAXNodeWrapper::GetNodeFromLastDefaultAction() {
return g_node_from_last_default_action;
}
// static
std::unique_ptr<base::AutoReset<float>> TestAXNodeWrapper::SetScaleFactor(
float value) {
return std::make_unique<base::AutoReset<float>>(&g_scale_factor, value);
}
TestAXNodeWrapper::~TestAXNodeWrapper() {
platform_node_->Destroy();
}
......@@ -228,7 +237,8 @@ TestAXNodeWrapper* TestAXNodeWrapper::HitTestSyncInternal(int x, int y) {
}
gfx::NativeViewAccessible TestAXNodeWrapper::HitTestSync(int x, int y) {
TestAXNodeWrapper* wrapper = HitTestSyncInternal(x, y);
TestAXNodeWrapper* wrapper =
HitTestSyncInternal(x / g_scale_factor, y / g_scale_factor);
return wrapper ? wrapper->ax_platform_node()->GetNativeViewAccessible()
: nullptr;
}
......
......@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include "base/auto_reset.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
......@@ -40,6 +41,9 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
// called from for testing.
static const AXNode* GetNodeFromLastDefaultAction();
// Set a global scale factor for testing.
static std::unique_ptr<base::AutoReset<float>> SetScaleFactor(float value);
~TestAXNodeWrapper() override;
AXPlatformNode* ax_platform_node() const { return platform_node_; }
......
......@@ -16,6 +16,7 @@
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/base/layout.h"
#include "ui/events/event_utils.h"
#include "ui/views/accessibility/view_accessibility_utils.h"
#include "ui/views/controls/native/native_view_host.h"
......@@ -325,6 +326,15 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(int x,
if (IsLeaf())
return GetNativeObject();
gfx::NativeView native_view = view()->GetWidget()->GetNativeView();
float scale_factor = 1.0;
if (native_view) {
scale_factor = ui::GetScaleFactorForNativeView(native_view);
scale_factor = scale_factor <= 0 ? 1.0 : scale_factor;
}
x /= scale_factor;
y /= scale_factor;
// Search child widgets first, since they're on top in the z-order.
for (Widget* child_widget : GetChildWidgets().child_widgets) {
View* child_root_view = child_widget->GetRootView();
......
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