diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-08 10:28:10 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-20 13:40:30 +0000 |
commit | e733310db58160074f574c429d48f8308c0afe17 (patch) | |
tree | f8aef4b7e62a69928dbcf880620eece20f98c6df /chromium/ui/accessibility | |
parent | 2f583e4aec1ae3a86fa047829c96b310dc12ecdf (diff) | |
download | qtwebengine-chromium-e733310db58160074f574c429d48f8308c0afe17.tar.gz |
BASELINE: Update Chromium to 56.0.2924.122
Change-Id: I4e04de8f47e47e501c46ed934c76a431c6337ced
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/accessibility')
23 files changed, 1364 insertions, 231 deletions
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn index f1c43b74475..e40911efb0e 100644 --- a/chromium/ui/accessibility/BUILD.gn +++ b/chromium/ui/accessibility/BUILD.gn @@ -5,19 +5,25 @@ import("//build/config/linux/pkg_config.gni") import("//build/config/features.gni") import("//build/config/ui.gni") -import("//build/json_schema_api.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/test.gni") +import("//tools/json_schema_compiler/json_schema_api.gni") + if (is_android) { import("//build/config/android/rules.gni") } component("accessibility") { sources = [ + "ax_action_data.cc", + "ax_action_data.h", "ax_node.cc", "ax_node.h", "ax_node_data.cc", "ax_node_data.h", + "ax_node_position.cc", + "ax_node_position.h", + "ax_position.h", "ax_relative_bounds.cc", "ax_relative_bounds.h", "ax_serializable_tree.cc", @@ -34,8 +40,6 @@ component("accessibility") { "ax_tree_serializer.h", "ax_tree_source.h", "ax_tree_update.h", - "ax_view_state.cc", - "ax_view_state.h", "platform/ax_platform_node.cc", "platform/ax_platform_node.h", "platform/ax_platform_node_base.cc", @@ -120,6 +124,7 @@ static_library("test_support") { test("accessibility_unittests") { sources = [ "ax_generated_tree_unittest.cc", + "ax_node_position_unittest.cc", "ax_text_utils_unittest.cc", "ax_tree_combiner_unittest.cc", "ax_tree_serializer_unittest.cc", diff --git a/chromium/ui/accessibility/ax_action_data.cc b/chromium/ui/accessibility/ax_action_data.cc new file mode 100644 index 00000000000..8b9dbbef3c6 --- /dev/null +++ b/chromium/ui/accessibility/ax_action_data.cc @@ -0,0 +1,59 @@ +// Copyright 2016 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 "ui/accessibility/ax_action_data.h" + +#include <set> + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" + +using base::IntToString; + +namespace ui { + +AXActionData::AXActionData() + : action(AX_ACTION_NONE), + target_node_id(-1), + flags(0), + anchor_node_id(-1), + anchor_offset(-1), + focus_node_id(-1), + focus_offset(-1) { +} + +AXActionData::AXActionData(const AXActionData& other) = default; + +AXActionData::~AXActionData() { +} + +// Note that this includes an initial space character if nonempty, but +// that works fine because this is normally printed by AXAction::ToString. +std::string AXActionData::ToString() const { + std::string result = ui::ToString(action); + + if (target_node_id != -1) + result += " target_node_id=" + IntToString(target_node_id); + + if (flags & (1 << ui::AX_ACTION_FLAGS_REQUEST_IMAGES)) + result += " flag_request_images"; + + if (flags & (1 << ui::AX_ACTION_FLAGS_REQUEST_INLINE_TEXT_BOXES)) + result += " flag_request_inline_text_boxes"; + + if (anchor_node_id != -1) { + result += " anchor_node_id=" + IntToString(anchor_node_id); + result += " anchor_offset=" + IntToString(anchor_offset); + } + if (focus_node_id != -1) { + result += " focus_node_id=" + IntToString(focus_node_id); + result += " focus_offset=" + IntToString(focus_offset); + } + + return result; +} + +} // namespace ui diff --git a/chromium/ui/accessibility/ax_action_data.h b/chromium/ui/accessibility/ax_action_data.h new file mode 100644 index 00000000000..4c0af535749 --- /dev/null +++ b/chromium/ui/accessibility/ax_action_data.h @@ -0,0 +1,60 @@ +// Copyright 2016 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. + +#ifndef UI_ACCESSIBILITY_AX_ACTION_DATA_H_ +#define UI_ACCESSIBILITY_AX_ACTION_DATA_H_ + +#include "base/strings/string16.h" +#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace ui { + +// A compact representation of an accessibility action and the arguments +// associated with that action. +struct AX_EXPORT AXActionData { + AXActionData(); + AXActionData(const AXActionData& other); + virtual ~AXActionData(); + + // Return a string representation of this data, for debugging. + virtual std::string ToString() const; + + // This is a simple serializable struct. All member variables should be + // public and copyable. + + // See the AXAction enums in ax_enums.idl for explanations of which + // parameters apply. + + // The action to take. + AXAction action; + + // The ID of the node that this action should be performed on. + int target_node_id; + + // Use enums from AXActionFlags + int flags; + + // For an action that creates a selection, the selection anchor and focus + // (see ax_tree_data.h for definitions). + int anchor_node_id; + int anchor_offset; + + int focus_node_id; + int focus_offset; + + // The target rect for the action. + gfx::Rect target_rect; + + // The target point for the action. + gfx::Point target_point; + + // The new value for a node, for the SET_VALUE action. + base::string16 value; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_AX_ACTION_DATA_H_ diff --git a/chromium/ui/accessibility/ax_enums.idl b/chromium/ui/accessibility/ax_enums.idl index 89d38422786..e9e59fc99e0 100644 --- a/chromium/ui/accessibility/ax_enums.idl +++ b/chromium/ui/accessibility/ax_enums.idl @@ -7,7 +7,7 @@ // until the Chromium and Blink trees are merged. [camel_case_enum_to_string=true] namespace ui { - // For new entries to the following three enums, also add to + // For new entries to the following four enums, also add to // chrome/common/extensions/api/automation.idl. This is enforced // by a PRESUBMIT check. // @@ -210,6 +210,7 @@ expanded, focusable, haspopup, + // Grows horizontally, e.g. most toolbars and separators. horizontal, hovered, invisible, @@ -224,10 +225,61 @@ richly_editable, selectable, selected, + // Grows vertically, e.g. menu or combo box. vertical, visited }; + // An action to be taken on an accessibility node. + enum AXAction { + // Decrement a slider or range control by one step value. + decrement, + + // Do the default action for an object, typically this means "click". + do_default, + + // Given a point, find the object it corresponds to and fire a + // HOVER event on it in response. + hit_test, + + // Increment a slider or range control by one step value. + increment, + + // Delete any selected text in the control's text value and + // insert |AXActionData::value| in its place, like when typing or pasting. + replace_selected_text, + + // Scroll any scrollable containers to make the target object visible + // on the screen. Optionally pass a subfocus rect in + // AXActionData.target_rect. + scroll_to_make_visible, + + // Scroll the given object to a specified point on the screen in + // global screen coordinates. Pass a point in AXActionData.target_point. + scroll_to_point, + + set_accessibility_focus, + set_focus, + set_scroll_offset, + set_selection, + + // Don't focus this node, but set it as the sequential focus navigation + // starting point, so that pressing Tab moves to the next element + // following this one, for example. + set_sequential_focus_navigation_starting_point, + + // Replace the value of the control with AXActionData::value and + // reset the selection, if applicable. + set_value, + + show_context_menu + }; + + enum AXActionFlags { + request_images, + request_inline_text_boxes + }; + // A change to the accessibility tree. enum AXMutation { node_created, @@ -391,6 +443,11 @@ flowto_ids, labelledby_ids, + // For static text. Character indices where line breaks occur. Note that + // this attribute is only available on Chrome OS and will be deprecated + // soon. + line_breaks, + // For static text. These int lists must be the same size; they represent // the start and end character offset of each marker. Examples of markers // include spelling and grammar errors, and find-in-page matches. @@ -414,7 +471,7 @@ // within the object's bounds, the second offset is the right coordinate // of the second character, and so on. character_offsets, - + // Used for caching. Do not read directly. Use // |AXNode::GetOrComputeLineStartOffsets| // For all text fields and content editable roots: A list of the start diff --git a/chromium/ui/accessibility/ax_node.h b/chromium/ui/accessibility/ax_node.h index 12eb1b88db0..195d6f3cc5e 100644 --- a/chromium/ui/accessibility/ax_node.h +++ b/chromium/ui/accessibility/ax_node.h @@ -11,10 +11,6 @@ #include "ui/accessibility/ax_node_data.h" -namespace gfx { -class Rect; -} - namespace ui { // One node in an AXTree. diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc index 06c55e923b2..316ac433c09 100644 --- a/chromium/ui/accessibility/ax_node_data.cc +++ b/chromium/ui/accessibility/ax_node_data.cc @@ -287,13 +287,48 @@ void AXNodeData::AddIntListAttribute(AXIntListAttribute attribute, } void AXNodeData::SetName(const std::string& name) { + for (size_t i = 0; i < string_attributes.size(); ++i) { + if (string_attributes[i].first == AX_ATTR_NAME) { + string_attributes[i].second = name; + return; + } + } + string_attributes.push_back(std::make_pair(AX_ATTR_NAME, name)); } +void AXNodeData::SetName(const base::string16& name) { + SetName(base::UTF16ToUTF8(name)); +} + void AXNodeData::SetValue(const std::string& value) { + for (size_t i = 0; i < string_attributes.size(); ++i) { + if (string_attributes[i].first == AX_ATTR_VALUE) { + string_attributes[i].second = value; + return; + } + } + string_attributes.push_back(std::make_pair(AX_ATTR_VALUE, value)); } +void AXNodeData::SetValue(const base::string16& value) { + SetValue(base::UTF16ToUTF8(value)); +} + +// static +bool AXNodeData::IsFlagSet(uint32_t state, ui::AXState state_flag) { + return 0 != (state & (1 << state_flag)); +} + +void AXNodeData::AddStateFlag(ui::AXState state_flag) { + state |= (1 << state_flag); +} + +bool AXNodeData::HasStateFlag(ui::AXState state_flag) const { + return IsFlagSet(state, state_flag); +} + std::string AXNodeData::ToString() const { std::string result; @@ -692,6 +727,9 @@ std::string AXNodeData::ToString() const { case AX_ATTR_LABELLEDBY_IDS: result += " labelledby_ids=" + IntVectorToString(values); break; + case AX_ATTR_LINE_BREAKS: + result += " line_breaks=" + IntVectorToString(values); + break; case AX_ATTR_MARKER_TYPES: { std::string types_str; for (size_t i = 0; i < values.size(); ++i) { diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h index 3fbaaa5bd41..acd5ec54c47 100644 --- a/chromium/ui/accessibility/ax_node_data.h +++ b/chromium/ui/accessibility/ax_node_data.h @@ -93,8 +93,17 @@ struct AX_EXPORT AXNodeData { // Convenience functions, mainly for writing unit tests. // Equivalent to AddStringAttribute(ATTR_NAME, name). void SetName(const std::string& name); + void SetName(const base::string16& name); // Equivalent to AddStringAttribute(ATTR_VALUE, value). void SetValue(const std::string& value); + void SetValue(const base::string16& value); + + // Helper to check whether |state_flag| is set in the given |state|. + static bool IsFlagSet(uint32_t state, ui::AXState state_flag); + + // Set or check bits in |state_|. + void AddStateFlag(ui::AXState state_flag); + bool HasStateFlag(ui::AXState state_flag) const; // Return a string representation of this data, for debugging. virtual std::string ToString() const; diff --git a/chromium/ui/accessibility/ax_node_position.cc b/chromium/ui/accessibility/ax_node_position.cc new file mode 100644 index 00000000000..4b91f29b3a1 --- /dev/null +++ b/chromium/ui/accessibility/ax_node_position.cc @@ -0,0 +1,79 @@ +// Copyright 2016 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 "ui/accessibility/ax_node_position.h" + +#include "base/strings/string16.h" +#include "ui/accessibility/ax_enums.h" + +namespace ui { + +AXTree* AXNodePosition::tree_ = nullptr; + +AXNodePosition::AXNodePosition() {} + +AXNodePosition::~AXNodePosition() {} + +void AXNodePosition::AnchorChild(int child_index, + int* tree_id, + int32_t* child_id) const { + DCHECK(tree_id); + DCHECK(child_id); + + if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) { + *tree_id = AXPosition::INVALID_TREE_ID; + *child_id = AXPosition::INVALID_ANCHOR_ID; + return; + } + + AXNode* child = GetAnchor()->ChildAtIndex(child_index); + DCHECK(child); + *tree_id = this->tree_id(); + *child_id = child->id(); +} + +int AXNodePosition::AnchorChildCount() const { + return GetAnchor() ? GetAnchor()->child_count() : 0; +} + +int AXNodePosition::AnchorIndexInParent() const { + return GetAnchor() ? GetAnchor()->index_in_parent() + : AXPosition::INVALID_INDEX; +} + +void AXNodePosition::AnchorParent(int* tree_id, int32_t* parent_id) const { + DCHECK(tree_id); + DCHECK(parent_id); + + if (!GetAnchor() || !GetAnchor()->parent()) { + *tree_id = AXPosition::INVALID_TREE_ID; + *parent_id = AXPosition::INVALID_ANCHOR_ID; + return; + } + + AXNode* parent = GetAnchor()->parent(); + *tree_id = this->tree_id(); + *parent_id = parent->id(); +} + +AXNode* AXNodePosition::GetNodeInTree(int tree_id, int32_t node_id) const { + if (!tree_ || node_id == AXPosition::INVALID_ANCHOR_ID) + return nullptr; + return AXNodePosition::tree_->GetFromId(node_id); +} + +int AXNodePosition::MaxTextOffset() const { + if (IsTextPosition()) { + DCHECK(GetAnchor()); + base::string16 name = + GetAnchor()->data().GetString16Attribute(AX_ATTR_NAME); + return static_cast<int>(name.length()); + } else if (IsTreePosition()) { + return 0; + } + + return AXPosition::INVALID_INDEX; +} + +} // namespace ui diff --git a/chromium/ui/accessibility/ax_node_position.h b/chromium/ui/accessibility/ax_node_position.h new file mode 100644 index 00000000000..40b1a584499 --- /dev/null +++ b/chromium/ui/accessibility/ax_node_position.h @@ -0,0 +1,40 @@ +// Copyright 2016 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. + +#ifndef UI_ACCESSIBILITY_AX_NODE_POSITION_H_ +#define UI_ACCESSIBILITY_AX_NODE_POSITION_H_ + +#include <stdint.h> + +#include "ui/accessibility/ax_export.h" +#include "ui/accessibility/ax_node.h" +#include "ui/accessibility/ax_position.h" +#include "ui/accessibility/ax_tree.h" + +namespace ui { + +class AX_EXPORT AXNodePosition : public AXPosition<AXNodePosition, AXNode> { + public: + AXNodePosition(); + ~AXNodePosition() override; + + static void SetTreeForTesting(AXTree* tree) { tree_ = tree; } + + protected: + void AnchorChild(int child_index, + int* tree_id, + int32_t* child_id) const override; + int AnchorChildCount() const override; + int AnchorIndexInParent() const override; + void AnchorParent(int* tree_id, int32_t* parent_id) const override; + AXNode* GetNodeInTree(int tree_id, int32_t node_id) const override; + int MaxTextOffset() const override; + + private: + static AXTree* tree_; +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_AX_NODE_POSITION_H_ diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc new file mode 100644 index 00000000000..37c8ffabc74 --- /dev/null +++ b/chromium/ui/accessibility/ax_node_position_unittest.cc @@ -0,0 +1,564 @@ +// Copyright 2016 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 <stdint.h> + +#include <memory> +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_node.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_node_position.h" +#include "ui/accessibility/ax_serializable_tree.h" +#include "ui/accessibility/ax_tree_serializer.h" +#include "ui/accessibility/ax_tree_update.h" + +namespace ui { + +using TestPositionType = AXPosition<AXNodePosition, AXNode>; + +namespace { + +class AXPositionTest : public testing::Test { + public: + const char* TEXT_VALUE = "Line 1\nLine 2"; + + AXPositionTest(); + ~AXPositionTest() override; + + protected: + void SetUp() override; + void TearDown() override; + + AXNodeData root_; + AXNodeData button_; + AXNodeData check_box_; + AXNodeData text_field_; + AXNodeData static_text1_; + AXNodeData line_break_; + AXNodeData static_text2_; + AXNodeData inline_box1_; + AXNodeData inline_box2_; + + AXTree tree_; + DISALLOW_COPY_AND_ASSIGN(AXPositionTest); +}; + +AXPositionTest::AXPositionTest() {} + +AXPositionTest::~AXPositionTest() {} + +void AXPositionTest::SetUp() { + std::vector<int32_t> line_start_offsets{0, 6}; + std::vector<int32_t> word_starts{0, 5}; + std::vector<int32_t> word_ends{3, 6}; + + root_.id = 1; + button_.id = 2; + check_box_.id = 3; + text_field_.id = 4; + static_text1_.id = 5; + inline_box1_.id = 6; + line_break_.id = 7; + static_text2_.id = 8; + inline_box2_.id = 9; + + root_.role = AX_ROLE_DIALOG; + root_.state = 1 << AX_STATE_FOCUSABLE; + root_.location = gfx::RectF(0, 0, 800, 600); + + button_.role = AX_ROLE_BUTTON; + button_.state = 1 << AX_STATE_HASPOPUP; + button_.SetName("Sample button_"); + button_.location = gfx::RectF(20, 20, 200, 30); + root_.child_ids.push_back(button_.id); + + check_box_.role = AX_ROLE_CHECK_BOX; + check_box_.state = 1 << AX_STATE_CHECKED; + check_box_.SetName("Sample check box"); + check_box_.location = gfx::RectF(20, 50, 200, 30); + root_.child_ids.push_back(check_box_.id); + + text_field_.role = AX_ROLE_TEXT_FIELD; + text_field_.state = 1 << AX_STATE_EDITABLE; + text_field_.SetValue(TEXT_VALUE); + text_field_.AddIntListAttribute(AX_ATTR_CACHED_LINE_STARTS, + line_start_offsets); + text_field_.child_ids.push_back(static_text1_.id); + text_field_.child_ids.push_back(line_break_.id); + text_field_.child_ids.push_back(static_text2_.id); + root_.child_ids.push_back(text_field_.id); + + static_text1_.role = AX_ROLE_STATIC_TEXT; + static_text1_.state = 1 << AX_STATE_EDITABLE; + static_text1_.SetName("Line 1"); + static_text1_.child_ids.push_back(inline_box1_.id); + + inline_box1_.role = AX_ROLE_INLINE_TEXT_BOX; + inline_box1_.state = 1 << AX_STATE_EDITABLE; + inline_box1_.SetName("Line 1"); + inline_box1_.AddIntListAttribute(AX_ATTR_WORD_STARTS, word_starts); + inline_box1_.AddIntListAttribute(AX_ATTR_WORD_ENDS, word_ends); + + line_break_.role = AX_ROLE_LINE_BREAK; + line_break_.state = 1 << AX_STATE_EDITABLE; + line_break_.SetName("\n"); + + static_text2_.role = AX_ROLE_STATIC_TEXT; + static_text2_.state = 1 << AX_STATE_EDITABLE; + static_text2_.SetName("Line 2"); + static_text2_.child_ids.push_back(inline_box2_.id); + + inline_box2_.role = AX_ROLE_INLINE_TEXT_BOX; + inline_box2_.state = 1 << AX_STATE_EDITABLE; + inline_box2_.SetName("Line 2"); + inline_box2_.AddIntListAttribute(AX_ATTR_WORD_STARTS, word_starts); + inline_box2_.AddIntListAttribute(AX_ATTR_WORD_ENDS, word_ends); + + AXTreeUpdate initial_state; + initial_state.root_id = 1; + initial_state.nodes.push_back(root_); + initial_state.nodes.push_back(button_); + initial_state.nodes.push_back(check_box_); + initial_state.nodes.push_back(text_field_); + initial_state.nodes.push_back(static_text1_); + initial_state.nodes.push_back(inline_box1_); + initial_state.nodes.push_back(line_break_); + initial_state.nodes.push_back(static_text2_); + initial_state.nodes.push_back(inline_box2_); + initial_state.has_tree_data = true; + initial_state.tree_data.tree_id = 0; + initial_state.tree_data.title = "Dialog title"; + AXSerializableTree src_tree(initial_state); + + std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>> + tree_source(src_tree.CreateTreeSource()); + AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer( + tree_source.get()); + AXTreeUpdate update; + serializer.SerializeChanges(src_tree.root(), &update); + ASSERT_TRUE(tree_.Unserialize(update)); + AXNodePosition::SetTreeForTesting(&tree_); +} + +void AXPositionTest::TearDown() { + AXNodePosition::SetTreeForTesting(nullptr); +} + +} // namespace + +TEST_F(AXPositionTest, AtStartOfAnchorWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + EXPECT_FALSE(null_position->AtStartOfAnchor()); +} + +TEST_F(AXPositionTest, AtStartOfAnchorWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, root_.id, + 0 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_TRUE(tree_position->AtStartOfAnchor()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 1 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_FALSE(tree_position->AtStartOfAnchor()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 3 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_FALSE(tree_position->AtStartOfAnchor()); +} + +TEST_F(AXPositionTest, AtStartOfAnchorWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_TRUE(text_position->AtStartOfAnchor()); + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_FALSE(text_position->AtStartOfAnchor()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_FALSE(text_position->AtStartOfAnchor()); +} + +TEST_F(AXPositionTest, AtEndOfAnchorWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + EXPECT_FALSE(null_position->AtEndOfAnchor()); +} + +TEST_F(AXPositionTest, AtEndOfAnchorWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, root_.id, + 3 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_TRUE(tree_position->AtEndOfAnchor()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 2 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_FALSE(tree_position->AtEndOfAnchor()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 0 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + EXPECT_FALSE(tree_position->AtEndOfAnchor()); +} + +TEST_F(AXPositionTest, AtEndOfAnchorWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 6 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_TRUE(text_position->AtEndOfAnchor()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_FALSE(text_position->AtEndOfAnchor()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + EXPECT_FALSE(text_position->AtEndOfAnchor()); +} + +TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreatePositionAtStartOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, root_.id, + 0 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + std::unique_ptr<TestPositionType> test_position( + tree_position->CreatePositionAtStartOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(root_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->child_index()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 1 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + test_position.reset(tree_position->CreatePositionAtStartOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(root_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->child_index()); +} + +TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreatePositionAtStartOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreatePositionAtStartOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); +} + +TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreatePositionAtEndOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, root_.id, + 3 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + std::unique_ptr<TestPositionType> test_position( + tree_position->CreatePositionAtEndOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(root_.id, test_position->anchor_id()); + EXPECT_EQ(3, test_position->child_index()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 1 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + test_position.reset(tree_position->CreatePositionAtEndOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(root_.id, test_position->anchor_id()); + EXPECT_EQ(3, test_position->child_index()); +} + +TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 6 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreatePositionAtEndOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(6, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreatePositionAtEndOfAnchor()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(6, test_position->text_offset()); +} + +TEST_F(AXPositionTest, CreateChildPositionAtWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreateChildPositionAt(0)); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateChildPositionAtWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, root_.id, + 2 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + std::unique_ptr<TestPositionType> test_position( + tree_position->CreateChildPositionAt(1)); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(check_box_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->child_index()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, button_.id, 0 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + test_position.reset(tree_position->CreateChildPositionAt(0)); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateChildPositionAtWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, static_text1_.id, + 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreateChildPositionAt(0)); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, static_text2_.id, 4 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreateChildPositionAt(1)); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateParentPositionWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreateParentPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateParentPositionWithTreePosition) { + std::unique_ptr<TestPositionType> tree_position( + AXNodePosition::CreateTreePosition(tree_.data().tree_id, check_box_.id, + 0 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + std::unique_ptr<TestPositionType> test_position( + tree_position->CreateParentPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTreePosition()); + EXPECT_EQ(root_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->child_index()); + + tree_position.reset(AXNodePosition::CreateTreePosition( + tree_.data().tree_id, root_.id, 1 /* child_index */)); + ASSERT_NE(nullptr, tree_position); + test_position.reset(tree_position->CreateParentPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreateParentPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(static_text1_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); +} + +TEST_F(AXPositionTest, CreateNextCharacterPositionWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreateNextCharacterPositionWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box1_.id, + 4 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(5, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(line_break_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); + + test_position.reset(test_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); + + test_position.reset(test_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); + EXPECT_EQ(1, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, check_box_.id, 15 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreateNextCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); +} + +TEST_F(AXPositionTest, CreatePreviousCharacterPositionWithNullPosition) { + std::unique_ptr<TestPositionType> null_position( + AXNodePosition::CreateNullPosition()); + ASSERT_NE(nullptr, null_position); + std::unique_ptr<TestPositionType> test_position( + null_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsNullPosition()); +} + +TEST_F(AXPositionTest, CreatePreviousCharacterPositionWithTextPosition) { + std::unique_ptr<TestPositionType> text_position( + AXNodePosition::CreateTextPosition(tree_.data().tree_id, inline_box2_.id, + 5 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + std::unique_ptr<TestPositionType> test_position( + text_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); + EXPECT_EQ(4, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(line_break_.id, test_position->anchor_id()); + EXPECT_EQ(0, test_position->text_offset()); + + test_position.reset(test_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(5, test_position->text_offset()); + + test_position.reset(test_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); + EXPECT_EQ(4, test_position->text_offset()); + + text_position.reset(AXNodePosition::CreateTextPosition( + tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM)); + ASSERT_NE(nullptr, text_position); + test_position.reset(text_position->CreatePreviousCharacterPosition()); + EXPECT_NE(nullptr, test_position); + EXPECT_TRUE(test_position->IsTextPosition()); + EXPECT_EQ(check_box_.id, test_position->anchor_id()); + EXPECT_EQ(15, test_position->text_offset()); +} + +} // namespace ui diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h new file mode 100644 index 00000000000..831d5018d8c --- /dev/null +++ b/chromium/ui/accessibility/ax_position.h @@ -0,0 +1,390 @@ +// Copyright 2016 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. + +#ifndef UI_ACCESSIBILITY_AX_POSITION_H_ +#define UI_ACCESSIBILITY_AX_POSITION_H_ + +#include <stdint.h> + +#include <memory> + +namespace ui { + +// Defines the type of position in the accessibility tree. +// A tree position is used when referring to a specific child of a node in the +// accessibility tree. +// A text position is used when referring to a specific character of text inside +// a particular node. +// A null position is used to signify that the provided data is invalid or that +// a boundary has been reached. +enum class AXPositionKind { NullPosition, TreePosition, TextPosition }; + +// A position in the |AXTree|. +// It could either indicate a non-textual node in the accessibility tree, or a +// text node and a character offset. +// A text node has either a role of static_text, inline_text_box or line_break. +// +// This class template uses static polymorphism in order to allow sub-classes to +// be created from the base class without the base class knowing the type of the +// sub-class in advance. +// The template argument |AXPositionType| should always be set to the type of +// any class that inherits from this template, making this a +// "curiously recursive template". +template <class AXPositionType, class AXNodeType> +class AXPosition { + public: + static int INVALID_TREE_ID; + static int INVALID_ANCHOR_ID; + static int INVALID_INDEX; + static int INVALID_OFFSET; + + AXPosition() {} + virtual ~AXPosition() {} + + static AXPosition<AXPositionType, AXNodeType>* CreateNullPosition() { + auto new_position = static_cast<AXPosition<AXPositionType, AXNodeType>*>( + new AXPositionType()); + DCHECK(new_position); + new_position->Initialize(AXPositionKind::NullPosition, INVALID_TREE_ID, + INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET, + AX_TEXT_AFFINITY_UPSTREAM); + return new_position; + } + + static AXPosition<AXPositionType, AXNodeType>* + CreateTreePosition(int tree_id, int32_t anchor_id, int child_index) { + auto new_position = static_cast<AXPosition<AXPositionType, AXNodeType>*>( + new AXPositionType()); + DCHECK(new_position); + new_position->Initialize(AXPositionKind::TreePosition, tree_id, anchor_id, + child_index, INVALID_OFFSET, + AX_TEXT_AFFINITY_UPSTREAM); + return new_position; + } + + static AXPosition<AXPositionType, AXNodeType>* CreateTextPosition( + int tree_id, + int32_t anchor_id, + int text_offset, + AXTextAffinity affinity) { + auto new_position = static_cast<AXPosition<AXPositionType, AXNodeType>*>( + new AXPositionType()); + DCHECK(new_position); + new_position->Initialize(AXPositionKind::TextPosition, tree_id, anchor_id, + INVALID_INDEX, text_offset, affinity); + return new_position; + } + + int tree_id() const { return tree_id_; } + int32_t anchor_id() const { return anchor_id_; } + + AXNodeType* GetAnchor() const { + if (tree_id_ == INVALID_TREE_ID || anchor_id_ == INVALID_ANCHOR_ID) + return nullptr; + DCHECK_GE(tree_id_, 0); + DCHECK_GE(anchor_id_, 0); + return GetNodeInTree(tree_id_, anchor_id_); + } + + AXPositionKind kind() const { return kind_; } + int child_index() const { return child_index_; } + int text_offset() const { return text_offset_; } + AXTextAffinity affinity() const { return affinity_; } + + bool IsNullPosition() const { + return kind_ == AXPositionKind::NullPosition || !GetAnchor(); + } + bool IsTreePosition() const { + return GetAnchor() && kind_ == AXPositionKind::TreePosition; + } + bool IsTextPosition() const { + return GetAnchor() && kind_ == AXPositionKind::TextPosition; + } + + bool AtStartOfAnchor() const { + if (!GetAnchor()) + return false; + + switch (kind_) { + case AXPositionKind::NullPosition: + return false; + case AXPositionKind::TreePosition: + return child_index_ == 0; + case AXPositionKind::TextPosition: + return text_offset_ == 0; + } + + return false; + } + + bool AtEndOfAnchor() const { + if (!GetAnchor()) + return false; + + switch (kind_) { + case AXPositionKind::NullPosition: + return false; + case AXPositionKind::TreePosition: + return child_index_ == AnchorChildCount(); + case AXPositionKind::TextPosition: + return text_offset_ == MaxTextOffset(); + } + + return false; + } + + AXPosition<AXPositionType, AXNodeType>* CreatePositionAtStartOfAnchor() + const { + switch (kind_) { + case AXPositionKind::NullPosition: + return CreateNullPosition(); + case AXPositionKind::TreePosition: + return CreateTreePosition(tree_id_, anchor_id_, 0 /* child_index */); + case AXPositionKind::TextPosition: + return CreateTextPosition(tree_id_, anchor_id_, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM); + } + return CreateNullPosition(); + } + + AXPosition<AXPositionType, AXNodeType>* CreatePositionAtEndOfAnchor() const { + switch (kind_) { + case AXPositionKind::NullPosition: + return CreateNullPosition(); + case AXPositionKind::TreePosition: + return CreateTreePosition(tree_id_, anchor_id_, AnchorChildCount()); + case AXPositionKind::TextPosition: + return CreateTextPosition(tree_id_, anchor_id_, MaxTextOffset(), + AX_TEXT_AFFINITY_UPSTREAM); + } + return CreateNullPosition(); + } + + AXPosition<AXPositionType, AXNodeType>* CreateChildPositionAt( + int child_index) const { + if (IsNullPosition()) + return CreateNullPosition(); + + if (child_index < 0 || child_index >= AnchorChildCount()) + return CreateNullPosition(); + + int tree_id = INVALID_TREE_ID; + int32_t child_id = INVALID_ANCHOR_ID; + AnchorChild(child_index, &tree_id, &child_id); + DCHECK_NE(tree_id, INVALID_TREE_ID); + DCHECK_NE(child_id, INVALID_ANCHOR_ID); + switch (kind_) { + case AXPositionKind::NullPosition: + NOTREACHED(); + return CreateNullPosition(); + case AXPositionKind::TreePosition: + return CreateTreePosition(tree_id, child_id, 0 /* child_index */); + case AXPositionKind::TextPosition: + return CreateTextPosition(tree_id, child_id, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM); + } + + return CreateNullPosition(); + } + + AXPosition<AXPositionType, AXNodeType>* CreateParentPosition() const { + if (IsNullPosition()) + return CreateNullPosition(); + + int tree_id = INVALID_TREE_ID; + int32_t parent_id = INVALID_ANCHOR_ID; + AnchorParent(&tree_id, &parent_id); + if (tree_id == INVALID_TREE_ID || parent_id == INVALID_ANCHOR_ID) + return CreateNullPosition(); + + DCHECK_GE(tree_id, 0); + DCHECK_GE(parent_id, 0); + switch (kind_) { + case AXPositionKind::NullPosition: + NOTREACHED(); + return CreateNullPosition(); + case AXPositionKind::TreePosition: + return CreateTreePosition(tree_id, parent_id, 0 /* child_index */); + case AXPositionKind::TextPosition: + return CreateTextPosition(tree_id, parent_id, 0 /* text_offset */, + AX_TEXT_AFFINITY_UPSTREAM); + } + + return CreateNullPosition(); + } + + // The following methods work across anchors. + + // TODO(nektar): Not yet implemented for tree positions. + AXPosition<AXPositionType, AXNodeType>* CreateNextCharacterPosition() const { + if (IsNullPosition()) + return CreateNullPosition(); + + if (text_offset_ + 1 < MaxTextOffset()) { + return CreateTextPosition(tree_id_, anchor_id_, text_offset_ + 1, + AX_TEXT_AFFINITY_UPSTREAM); + } + + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> next_leaf( + CreateNextAnchorPosition()); + while (next_leaf && !next_leaf->IsNullPosition() && + next_leaf->AnchorChildCount()) { + next_leaf.reset(next_leaf->CreateNextAnchorPosition()); + } + + DCHECK(next_leaf); + return next_leaf.release(); + } + + // TODO(nektar): Not yet implemented for tree positions. + AXPosition<AXPositionType, AXNodeType>* CreatePreviousCharacterPosition() + const { + if (IsNullPosition()) + return CreateNullPosition(); + + if (text_offset_ > 0) { + return CreateTextPosition(tree_id_, anchor_id_, text_offset_ - 1, + AX_TEXT_AFFINITY_UPSTREAM); + } + + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> previous_leaf( + CreatePreviousAnchorPosition()); + while (previous_leaf && !previous_leaf->IsNullPosition() && + previous_leaf->AnchorChildCount()) { + previous_leaf.reset(previous_leaf->CreatePreviousAnchorPosition()); + } + + DCHECK(previous_leaf); + previous_leaf.reset(previous_leaf->CreatePositionAtEndOfAnchor()); + if (!previous_leaf->AtStartOfAnchor()) + --previous_leaf->text_offset_; + return previous_leaf.release(); + } + + // TODO(nektar): Add word, line and paragraph navigation methods. + + protected: + virtual void Initialize(AXPositionKind kind, + int tree_id, + int32_t anchor_id, + int child_index, + int text_offset, + AXTextAffinity affinity) { + kind_ = kind; + tree_id_ = tree_id; + anchor_id_ = anchor_id; + child_index_ = child_index; + text_offset_ = text_offset; + affinity_ = affinity; + + if (!GetAnchor() || + (child_index_ != INVALID_INDEX && + (child_index_ < 0 || child_index_ > AnchorChildCount())) || + (text_offset_ != INVALID_OFFSET && + (text_offset_ < 0 || text_offset_ > MaxTextOffset()))) { + // reset to the null position. + kind_ = AXPositionKind::NullPosition; + tree_id_ = INVALID_TREE_ID; + anchor_id_ = INVALID_ANCHOR_ID; + child_index_ = INVALID_INDEX; + text_offset_ = INVALID_OFFSET; + affinity_ = AX_TEXT_AFFINITY_UPSTREAM; + } + } + + // Uses depth-first pre-order traversal. + virtual AXPosition<AXPositionType, AXNodeType>* CreateNextAnchorPosition() + const { + if (IsNullPosition()) + return CreateNullPosition(); + + if (AnchorChildCount()) + return CreateChildPositionAt(0); + + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> current_position( + CreateTreePosition(tree_id_, anchor_id_, child_index_)); + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> parent_position( + CreateParentPosition()); + while (parent_position && !parent_position->IsNullPosition()) { + // Get the next sibling if it exists, otherwise move up to the parent's + // next sibling. + int index_in_parent = current_position->AnchorIndexInParent(); + if (index_in_parent < parent_position->AnchorChildCount() - 1) { + AXPosition<AXPositionType, AXNodeType>* next_sibling = + parent_position->CreateChildPositionAt(index_in_parent + 1); + DCHECK(next_sibling && !next_sibling->IsNullPosition()); + return next_sibling; + } + + current_position = std::move(parent_position); + parent_position.reset(current_position->CreateParentPosition()); + } + + return CreateNullPosition(); + } + + // Uses depth-first pre-order traversal. + virtual AXPosition<AXPositionType, AXNodeType>* CreatePreviousAnchorPosition() + const { + if (IsNullPosition()) + return CreateNullPosition(); + + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> parent_position( + CreateParentPosition()); + if (!parent_position || parent_position->IsNullPosition()) + return CreateNullPosition(); + + // Get the previous sibling's deepest first child if a previous sibling + // exists, otherwise move up to the parent. + int index_in_parent = AnchorIndexInParent(); + if (index_in_parent <= 0) + return parent_position.release(); + + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> leaf( + parent_position->CreateChildPositionAt(index_in_parent - 1)); + while (leaf && !leaf->IsNullPosition() && leaf->AnchorChildCount()) + leaf.reset(leaf->CreateChildPositionAt(0)); + + return leaf.release(); + } + + // Abstract methods. + virtual void AnchorChild(int child_index, + int* tree_id, + int32_t* child_id) const = 0; + virtual int AnchorChildCount() const = 0; + virtual int AnchorIndexInParent() const = 0; + virtual void AnchorParent(int* tree_id, int32_t* parent_id) const = 0; + virtual AXNodeType* GetNodeInTree(int tree_id, int32_t node_id) const = 0; + // Returns the length of the text that is present inside the anchor node, + // including any text found on descendant nodes. + virtual int MaxTextOffset() const = 0; + + private: + AXPositionKind kind_; + int tree_id_; + int32_t anchor_id_; + + // For text positions, |child_index_| is initially set to |-1| and only + // computed on demand. The same with tree positions and |text_offset_|. + int child_index_; + int text_offset_; + + // TODO(nektar): Get rid of affinity and make Blink handle affinity + // internally since inline text objects don't span lines. + ui::AXTextAffinity affinity_; +}; + +template <class AXPositionType, class AXNodeType> +int AXPosition<AXPositionType, AXNodeType>::INVALID_TREE_ID = -1; +template <class AXPositionType, class AXNodeType> +int32_t AXPosition<AXPositionType, AXNodeType>::INVALID_ANCHOR_ID = -1; +template <class AXPositionType, class AXNodeType> +int AXPosition<AXPositionType, AXNodeType>::INVALID_INDEX = -1; +template <class AXPositionType, class AXNodeType> +int AXPosition<AXPositionType, AXNodeType>::INVALID_OFFSET = -1; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_AX_POSITION_H_ diff --git a/chromium/ui/accessibility/ax_tree_combiner.cc b/chromium/ui/accessibility/ax_tree_combiner.cc index 736cc583a15..b983e995519 100644 --- a/chromium/ui/accessibility/ax_tree_combiner.cc +++ b/chromium/ui/accessibility/ax_tree_combiner.cc @@ -82,6 +82,7 @@ bool IsNodeIdIntListAttribute(AXIntListAttribute attr) { // add a new attribute without explicitly considering whether it's // a node id attribute or not. case AX_INT_LIST_ATTRIBUTE_NONE: + case AX_ATTR_LINE_BREAKS: case AX_ATTR_MARKER_TYPES: case AX_ATTR_MARKER_STARTS: case AX_ATTR_MARKER_ENDS: @@ -167,12 +168,6 @@ int32_t AXTreeCombiner::MapId(int32_t tree_id, int32_t node_id) { } void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { - // The root of each tree may contain a transform that needs to apply - // to all of its descendants. - gfx::Transform old_transform = transform_; - if (!tree->nodes.empty() && tree->nodes[0].transform) - transform_.ConcatTransform(*tree->nodes[0].transform); - int32_t tree_id = tree->tree_data.tree_id; for (size_t i = 0; i < tree->nodes.size(); ++i) { AXNodeData node = tree->nodes[i]; @@ -185,9 +180,9 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { for (size_t j = 0; j < node.child_ids.size(); ++j) node.child_ids[j] = MapId(tree_id, node.child_ids[j]); - // Reset the offset container ID because we make all bounding boxes - // absolute. - node.offset_container_id = -1; + // Map the container id. + if (node.offset_container_id > 0) + node.offset_container_id = MapId(tree_id, node.offset_container_id); // Map other int attributes that refer to node IDs, and remove the // AX_ATTR_CHILD_TREE_ID attribute. @@ -210,10 +205,6 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { } } - // Apply the transformation to the object's bounds to put it in - // the coordinate space of the root frame. - transform_.TransformRect(&node.location); - // See if this node has a child tree. As a sanity check make sure the // child tree lists this tree as its parent tree id. const AXTreeUpdate* child_tree = nullptr; @@ -236,9 +227,6 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { if (child_tree) ProcessTree(child_tree); } - - // Reset the transform. - transform_ = old_transform; } } // namespace ui diff --git a/chromium/ui/accessibility/ax_tree_combiner.h b/chromium/ui/accessibility/ax_tree_combiner.h index 37b9fa56879..ce8fbc792d5 100644 --- a/chromium/ui/accessibility/ax_tree_combiner.h +++ b/chromium/ui/accessibility/ax_tree_combiner.h @@ -9,7 +9,6 @@ #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_tree_update.h" -#include "ui/gfx/transform.h" namespace ui { @@ -19,8 +18,7 @@ namespace ui { // // Since node IDs are relative to each ID, it has to renumber all of the IDs // and update all of the attributes that reference IDs of other nodes to -// ensure they point to the right node. It also applies transformations to -// local bounding rectangles to make them global. +// ensure they point to the right node. // // It also makes sure the final combined tree points to the correct focused // node across all of the trees based on the focused tree ID of the root tree. @@ -45,7 +43,6 @@ class AX_EXPORT AXTreeCombiner { std::map<int32_t, const AXTreeUpdate*> tree_id_map_; std::map<std::pair<int32_t, int32_t>, int32_t> tree_id_node_id_map_; AXTreeUpdate combined_; - gfx::Transform transform_; }; diff --git a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc index 49fbccc988f..b80771d3bf0 100644 --- a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc +++ b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc @@ -149,57 +149,6 @@ TEST(CombineAXTreesTest, MapAllIdAttributes) { AX_ATTR_UNIQUE_CELL_IDS)[0]); } -TEST(CombineAXTreesTest, Coordinates) { - AXTreeUpdate parent_tree; - parent_tree.has_tree_data = true; - parent_tree.tree_data.tree_id = 1; - parent_tree.root_id = 1; - parent_tree.nodes.resize(3); - parent_tree.nodes[0].id = 1; - parent_tree.nodes[0].child_ids.push_back(2); - parent_tree.nodes[0].child_ids.push_back(3); - parent_tree.nodes[1].id = 2; - parent_tree.nodes[1].role = AX_ROLE_BUTTON; - parent_tree.nodes[1].location = gfx::RectF(50, 10, 200, 100); - parent_tree.nodes[2].id = 3; - parent_tree.nodes[2].role = AX_ROLE_IFRAME; - parent_tree.nodes[2].AddIntAttribute(AX_ATTR_CHILD_TREE_ID, 2); - - AXTreeUpdate child_tree; - child_tree.has_tree_data = true; - child_tree.tree_data.parent_tree_id = 1; - child_tree.tree_data.tree_id = 2; - child_tree.root_id = 1; - child_tree.nodes.resize(2); - child_tree.nodes[0].id = 1; - child_tree.nodes[0].child_ids.push_back(2); - - child_tree.nodes[0].transform.reset(new gfx::Transform()); - child_tree.nodes[0].transform->Translate(0, 300); - child_tree.nodes[0].transform->Scale(2.0, 2.0); - - child_tree.nodes[1].id = 2; - child_tree.nodes[1].role = AX_ROLE_BUTTON; - child_tree.nodes[1].location = gfx::RectF(50, 10, 200, 100); - - AXTreeCombiner combiner; - combiner.AddTree(parent_tree, true); - combiner.AddTree(child_tree, false); - combiner.Combine(); - - const AXTreeUpdate& combined = combiner.combined(); - - ASSERT_EQ(5U, combined.nodes.size()); - EXPECT_EQ(50, combined.nodes[1].location.x()); - EXPECT_EQ(10, combined.nodes[1].location.y()); - EXPECT_EQ(200, combined.nodes[1].location.width()); - EXPECT_EQ(100, combined.nodes[1].location.height()); - EXPECT_EQ(100, combined.nodes[4].location.x()); - EXPECT_EQ(320, combined.nodes[4].location.y()); - EXPECT_EQ(400, combined.nodes[4].location.width()); - EXPECT_EQ(200, combined.nodes[4].location.height()); -} - TEST(CombineAXTreesTest, FocusedTree) { AXTreeUpdate parent_tree; parent_tree.has_tree_data = true; diff --git a/chromium/ui/accessibility/ax_view_state.cc b/chromium/ui/accessibility/ax_view_state.cc deleted file mode 100644 index fe101a500c6..00000000000 --- a/chromium/ui/accessibility/ax_view_state.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2011 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 "ui/accessibility/ax_view_state.h" - -namespace ui { - -AXViewState::AXViewState() - : role(AX_ROLE_CLIENT), - selection_start(-1), - selection_end(-1), - index(-1), - count(-1), - state_(0) { } - -AXViewState::~AXViewState() { } - -// static -bool AXViewState::IsFlagSet(uint32_t state, ui::AXState state_flag) { - return 0 != (state & (1 << state_flag)); -} - -void AXViewState::AddStateFlag(ui::AXState state_flag) { - state_ |= (1 << state_flag); -} - -bool AXViewState::HasStateFlag(ui::AXState state_flag) const { - return IsFlagSet(state_, state_flag); -} - -} // namespace ui diff --git a/chromium/ui/accessibility/ax_view_state.h b/chromium/ui/accessibility/ax_view_state.h deleted file mode 100644 index a20a65d6e7d..00000000000 --- a/chromium/ui/accessibility/ax_view_state.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef UI_ACCESSIBILITY_AX_VIEW_STATE_H_ -#define UI_ACCESSIBILITY_AX_VIEW_STATE_H_ - -#include <stdint.h> - -#include "base/callback.h" -#include "base/strings/string16.h" -#include "ui/accessibility/ax_enums.h" -#include "ui/accessibility/ax_export.h" - -namespace ui { - -//////////////////////////////////////////////////////////////////////////////// -// -// AXViewState -// -// A cross-platform struct for storing the core accessibility information -// that should be provided about any UI view to assistive technology (AT). -// -//////////////////////////////////////////////////////////////////////////////// -struct AX_EXPORT AXViewState { - public: - AXViewState(); - ~AXViewState(); - - // Helper to check whether |state_flag| is set in the given |state|. - static bool IsFlagSet(uint32_t state, ui::AXState state_flag); - - // Set or check bits in |state_|. - void AddStateFlag(ui::AXState state_flag); - bool HasStateFlag(ui::AXState state_flag) const; - - // The view's state, a bitmask containing fields such as checked - // (for a checkbox) and protected (for a password text box). This "state" - // should not be confused with the class's name. - uint32_t state() { return state_; } - - // The view's role, like button or list box. - AXRole role; - - // The view's name / label. - base::string16 name; - - // The view's value, for example the text content. - base::string16 value; - - // The name of the default action if the user clicks on this view. - base::string16 default_action; - - // The keyboard shortcut to activate this view, if any. - base::string16 keyboard_shortcut; - - // The view's placeholder value, used only for views with editable text. - base::string16 placeholder; - - // The view's help text/description, set to the view's tooltip text (if any). - base::string16 description; - - // The selection start and end. Only applies to views with text content, - // such as a text box or combo box; start and end should be -1 otherwise. - int selection_start; - int selection_end; - - // The selected item's index and the count of the number of items. - // Only applies to views with multiple choices like a listbox; both - // index and count should be -1 otherwise. - int index; - int count; - - // An optional callback that can be used by accessibility clients to - // set the string value of this view. This only applies to roles where - // setting the value makes sense, like a text box. Not often used by - // screen readers, but often used by automation software to script - // things like logging into portals or filling forms. - // - // This callback is only valid for the lifetime of the view, and should - // be a safe no-op if the view is deleted. Typically, accessible views - // should use a WeakPtr when binding the callback. - base::Callback<void(const base::string16&)> set_value_callback; - - private: - uint32_t state_; -}; - -} // namespace ui - -#endif // UI_ACCESSIBILITY_AX_VIEW_STATE_H_ diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb index c7c1bc0f4e3..04b981db1a0 100644 --- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb +++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb @@ -18,7 +18,7 @@ <translation id="2648340354586434750">শব্দগুলির দ্বারা সরাতে <span class='key'>বিকল্প</span> টিপে ধরে রাখুন৷</translation> <translation id="2795227192542594043">এই এক্সটেনশানটি আপনাকে ওয়েব পৃষ্ঠাটির উপর একটি চলনশীল কার্সার দেয়, আপনাকে কীবোর্ড দিয়ে পাঠ্য নির্বাচন করতে দেয়৷</translation> <translation id="2808027189040546825">পদক্ষেপ ১: ক্ষীণতম তারকা সহ সারিটি নির্বাচন করুন:</translation> -<translation id="2965611304828530558"><p>যখন আপনি কোনো লিঙ্ক অ্যাক্সেস করেন বা নিয়ন্ত্রণ করেন, তখন এটি স্বয়ংক্রিয়ভাবে ফোকাস করবে৷ কোনো লিঙ্ক বা বোতামে ক্লিক করতে <span class='key'>Enter</span> টিপুন৷ </p> <p> যখন কোনো ফোকাস করা নিয়ন্ত্রণ (কোনো পাঠ্য বক্স বা তালিকা বক্স) নির্দেশক তীরচিহ্নগুলি ক্যাপচার করে, তখন ক্যারেট ব্রাউজিং করা চালিয়ে যেতে বাম বা ডান তীর অনুসরণ করে <span class='key'>Esc</span> টিপুন৷ </p> <p> অন্যথা, পরবর্তী ফোকাসযোগ্য নিয়ন্ত্রণে সরে যেতে <span class='key'>Tab</span> টিপুন৷ </p></translation> +<translation id="2965611304828530558"><p>যখন আপনি কোনো লিঙ্ক অ্যাক্সেস করেন বা নিয়ন্ত্রণ করেন, তখন এটি স্বয়ংক্রিয়ভাবে ফোকাস করবে৷ কোনো লিঙ্ক বা বোতামে ক্লিক করতে <span class='key'>Enter</span> টিপুন৷ </p> <p> যখন কোনো ফোকাস করা নিয়ন্ত্রণ (কোনো পাঠ্য বক্স বা তালিকা বক্স) নির্দেশক তীরচিহ্নগুলি ক্যাপচার করে, তখন ক্যারেট ব্রাউজিং করা চালিয়ে যেতে বাঁ বা ডান তীর অনুসরণ করে <span class='key'>Esc</span> টিপুন৷ </p> <p> অন্যথা, পরবর্তী ফোকাসযোগ্য নিয়ন্ত্রণে সরে যেতে <span class='key'>Tab</span> টিপুন৷ </p></translation> <translation id="3252573918265662711">সেটআপ</translation> <translation id="3410969471888629217">সাইট কাস্টমাইজেশনগুলি মুছুন</translation> <translation id="3435896845095436175">সক্ষম করুন</translation> diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_da.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_da.xtb index db92820b5f7..c22efe89c8e 100644 --- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_da.xtb +++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_da.xtb @@ -21,7 +21,7 @@ <translation id="2965611304828530558"><p>Når du når til et link eller et kontrolelement, fremhæves det automatisk. Tryk på <span class='key'>Enter</span> for at klikke på et link eller en knap. </p> <p> Når et fremhævet kontrolelement (som f.eks. et tekstfelt eller et listefelt) griber piletaster, skal du trykke på <span class='key'>Esc</span> efterfulgt af venstre eller højre pil for at fortsætte tastebrowsing. </p> <p> Alternativt kan du også trykke på <span class='key'>Tab</span> for at gå til det næste kontrolelement, der kan fremhæves. </p></translation> <translation id="3252573918265662711">Konfiguration</translation> <translation id="3410969471888629217">Glem websitets tilpasninger</translation> -<translation id="3435896845095436175">Aktiver</translation> +<translation id="3435896845095436175">Aktivér</translation> <translation id="3622586652998721735">Vælg som standardtema</translation> <translation id="3812541808639806898">Visningsprogram for billeder og "Alt"-tekst</translation> <translation id="381767806621926835">Højreklik på indhold med en "longdesc"- eller "Aria-describedat"-attribut for at få adgang den lange version af beskrivelsen.</translation> diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h index 1e27f3f00a0..8569e7ff52d 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h @@ -85,10 +85,18 @@ class AX_EXPORT AXPlatformNodeDelegate { virtual void DoDefaultAction() = 0; // Change the value of a control, such as the text content of a text field. - virtual bool SetStringValue(const base::string16& new_value) = 0; - - // Whether the string value is settable. + // If |clear_first| is true, this replaces all text with the |new_value|. + // Otherwise this inserts |new_value| at the cursor position, replacing any + // selected text. The cursor is placed at the end of |new_value|. + virtual bool SetStringValue(const base::string16& new_value, + bool clear_first) = 0; + + // Whether SetStringValue() is callable, i.e. if the string value is not read + // only and if the callback exists. virtual bool CanSetStringValue() = 0; + + // Focus or unfocus a View, checking if the View is focusable first. + virtual bool SetFocused(bool focused) = 0; }; } // namespace ui diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm index be9eb9e3679..a30b42007f0 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm @@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/strings/sys_string_conversions.h" #include "ui/accessibility/ax_node_data.h" -#include "ui/accessibility/ax_view_state.h" #include "ui/accessibility/platform/ax_platform_node_delegate.h" #import "ui/gfx/mac/coordinate_conversion.h" @@ -378,16 +377,13 @@ void NotifyMacEvent(AXPlatformNodeCocoa* target, ui::AXEvent event_type) { return NO; } - if ([attributeName isEqualToString:NSAccessibilityValueAttribute]) + if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || + [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) return node_->GetDelegate()->CanSetStringValue(); - // TODO(patricialor): Implement and merge with conditional for value above. - if ([attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) - return NO; if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { - if (ui::AXViewState::IsFlagSet(node_->GetData().state, - ui::AX_STATE_FOCUSABLE)) - return NO; + return ui::AXNodeData::IsFlagSet(node_->GetData().state, + ui::AX_STATE_FOCUSABLE); } // TODO(patricialor): Add callbacks for updating the above attributes except @@ -396,9 +392,20 @@ void NotifyMacEvent(AXPlatformNodeCocoa* target, ui::AXEvent event_type) { } - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { - if ([attribute isEqualToString:NSAccessibilityValueAttribute] && - [value isKindOfClass:[NSString class]]) - node_->GetDelegate()->SetStringValue(base::SysNSStringToUTF16(value)); + if ([value isKindOfClass:[NSString class]]) { + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + node_->GetDelegate()->SetStringValue(base::SysNSStringToUTF16(value), + true); + } else if ([attribute + isEqualToString:NSAccessibilitySelectedTextAttribute]) { + node_->GetDelegate()->SetStringValue(base::SysNSStringToUTF16(value), + false); + } + } else if ([value isKindOfClass:[NSNumber class]]) { + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + node_->GetDelegate()->SetFocused([value boolValue]); + } + } // TODO(patricialor): Plumb through all the other writable attributes as // specified in accessibilityIsAttributeSettable. @@ -443,8 +450,8 @@ void NotifyMacEvent(AXPlatformNodeCocoa* target, ui::AXEvent event_type) { ui::AXRole role = node_->GetData().role; switch (role) { case ui::AX_ROLE_TEXT_FIELD: - if (ui::AXViewState::IsFlagSet(node_->GetData().state, - ui::AX_STATE_PROTECTED)) + if (ui::AXNodeData::IsFlagSet(node_->GetData().state, + ui::AX_STATE_PROTECTED)) return NSAccessibilitySecureTextFieldSubrole; break; default: @@ -471,13 +478,13 @@ void NotifyMacEvent(AXPlatformNodeCocoa* target, ui::AXEvent event_type) { - (NSValue*)AXEnabled { return [NSNumber - numberWithBool:!ui::AXViewState::IsFlagSet(node_->GetData().state, - ui::AX_STATE_DISABLED)]; + numberWithBool:!ui::AXNodeData::IsFlagSet(node_->GetData().state, + ui::AX_STATE_DISABLED)]; } - (NSValue*)AXFocused { - if (ui::AXViewState::IsFlagSet(node_->GetData().state, - ui::AX_STATE_FOCUSABLE)) + if (ui::AXNodeData::IsFlagSet(node_->GetData().state, + ui::AX_STATE_FOCUSABLE)) return [NSNumber numberWithBool:(node_->GetDelegate()->GetFocus() == node_->GetNativeViewAccessible())]; return [NSNumber numberWithBool:NO]; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc index 814f383c19f..da6501c40c1 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc @@ -454,7 +454,7 @@ STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) { STDMETHODIMP AXPlatformNodeWin::put_accValue(VARIANT var_id, BSTR new_value) { COM_OBJECT_VALIDATE_VAR_ID(var_id); - if (delegate_->SetStringValue(new_value)) + if (delegate_->SetStringValue(new_value, true)) return S_OK; return E_FAIL; } @@ -511,6 +511,8 @@ STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) { *states = IA2_STATE_OPAQUE; if (GetData().state & (1 << ui::AX_STATE_EDITABLE)) *states |= IA2_STATE_EDITABLE; + if (GetData().state & (1 << ui::AX_STATE_VERTICAL)) + *states |= IA2_STATE_VERTICAL; return S_OK; } @@ -897,9 +899,10 @@ STDMETHODIMP AXPlatformNodeWin::QueryService( COM_OBJECT_VALIDATE_1_ARG(object); if (riid == IID_IAccessible2) { - FOR_EACH_OBSERVER(IAccessible2UsageObserver, - GetIAccessible2UsageObserverList(), - OnIAccessible2Used()); + for (IAccessible2UsageObserver& observer : + GetIAccessible2UsageObserverList()) { + observer.OnIAccessible2Used(); + } } if (guidService == IID_IAccessible || diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc index c639e0879bf..7388fd35758 100644 --- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc @@ -119,7 +119,8 @@ TestAXNodeWrapper::GetTargetForNativeAccessibilityEvent() { void TestAXNodeWrapper::DoDefaultAction() { } -bool TestAXNodeWrapper::SetStringValue(const base::string16& new_value) { +bool TestAXNodeWrapper::SetStringValue(const base::string16& new_value, + bool clear_first) { return false; } @@ -127,6 +128,10 @@ bool TestAXNodeWrapper::CanSetStringValue() { return false; } +bool TestAXNodeWrapper::SetFocused(bool focused) { + return false; +} + TestAXNodeWrapper::TestAXNodeWrapper(AXTree* tree, AXNode* node) : tree_(tree), node_(node), diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h index fdc2baa5abf..a52dd53707d 100644 --- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h @@ -39,8 +39,10 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegate { gfx::NativeViewAccessible GetFocus() override; gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; void DoDefaultAction() override; - bool SetStringValue(const base::string16& new_value) override; + bool SetStringValue(const base::string16& new_value, + bool clear_first) override; bool CanSetStringValue() override; + bool SetFocused(bool focused) override; private: TestAXNodeWrapper(AXTree* tree, AXNode* node); |