diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-17 21:24:01 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-17 21:24:01 +0000 |
commit | 3dba3ed80dea635daebac1daecaa85fe30decd05 (patch) | |
tree | faab54509553cac8f368a86dc408323e7b1640df | |
parent | 2791a5fabac0b05b4964cf4403265b7a1f83857a (diff) | |
download | chromium_src-3dba3ed80dea635daebac1daecaa85fe30decd05.zip chromium_src-3dba3ed80dea635daebac1daecaa85fe30decd05.tar.gz chromium_src-3dba3ed80dea635daebac1daecaa85fe30decd05.tar.bz2 |
Allow computing bounds for range on any accessible element.
This change pulls the inline text tree for editable text nodes into
the browser process, and enables bounds for range to be called on
any element, just by passing it recursively to descendants and
unioning the rects.
Together, that allows bounds for range methods to succeed on
elements like <input> and <textarea>.
BUG=328485
Review URL: https://codereview.chromium.org/99033005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@241360 0039d316-1c4b-4281-b951-d872f2087c98
5 files changed, 143 insertions, 18 deletions
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 223cd8d..8429664 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -44,7 +44,22 @@ BrowserAccessibility::~BrowserAccessibility() { } bool BrowserAccessibility::PlatformIsLeaf() const { - return role_ == blink::WebAXRoleStaticText || child_count() == 0; + if (child_count() == 0) + return true; + + // All of these roles may have children that we use as internal + // implementation details, but we want to expose them as leaves + // to platform accessibility APIs. + switch (role_) { + case blink::WebAXRoleEditableText: + case blink::WebAXRoleSlider: + case blink::WebAXRoleStaticText: + case blink::WebAXRoleTextArea: + case blink::WebAXRoleTextField: + return true; + default: + return false; + } } uint32 BrowserAccessibility::PlatformChildCount() const { @@ -196,7 +211,24 @@ gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const { gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) const { - DCHECK_EQ(role_, blink::WebAXRoleStaticText); + if (role_ != blink::WebAXRoleStaticText) { + // Apply recursively to all static text descendants. For example, if + // you call it on a div with two text node children, it just calls + // GetLocalBoundsForRange on each of the two children (adjusting + // |start| for each one) and unions the resulting rects. + gfx::Rect bounds; + for (size_t i = 0; i < children_.size(); ++i) { + BrowserAccessibility* child = children_[i]; + int child_len = child->GetStaticTextLenRecursive(); + if (start < child_len && start + len > 0) { + gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len); + bounds.Union(child_rect); + } + start -= child_len; + } + return bounds; + } + int end = start + len; int child_start = 0; int child_end = 0; @@ -586,4 +618,16 @@ std::string BrowserAccessibility::GetTextRecursive() const { return result; } +int BrowserAccessibility::GetStaticTextLenRecursive() const { + if (role_ == blink::WebAXRoleStaticText) { + return static_cast<int>( + GetStringAttribute(AccessibilityNodeData::ATTR_VALUE).size()); + } + + int len = 0; + for (size_t i = 0; i < children_.size(); ++i) + len += children_[i]->GetStaticTextLenRecursive(); + return len; +} + } // namespace content diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 1258803..781ccff 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -282,6 +282,10 @@ class CONTENT_EXPORT BrowserAccessibility { BrowserAccessibility* parent_; private: + // Return the sum of the lengths of all static text descendants, + // including this object if it's static text. + int GetStaticTextLenRecursive() const; + // The index of this within its parent object. int32 index_in_parent_; diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index b0d4836..e427b9e 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -692,6 +692,11 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRange) { // Test range that's beyond the text. EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(), static_text_accessible->GetLocalBoundsForRange(-1, 999).ToString()); + + // Test that we can call bounds for range on the parent element, too, + // and it still works. + EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(), + root_accessible->GetLocalBoundsForRange(0, 13).ToString()); } TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) { @@ -776,4 +781,92 @@ TEST(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) { static_text_accessible->GetLocalBoundsForRange(2, 2).ToString()); } +TEST(BrowserAccessibilityManagerTest, BoundsForRangeOnParentElement) { + AccessibilityNodeData root; + root.id = 1; + root.role = blink::WebAXRoleRootWebArea; + root.child_ids.push_back(2); + + AccessibilityNodeData div; + div.id = 2; + div.role = blink::WebAXRoleDiv; + div.location = gfx::Rect(100, 100, 100, 20); + div.child_ids.push_back(3); + div.child_ids.push_back(4); + div.child_ids.push_back(5); + + AccessibilityNodeData static_text1; + static_text1.id = 3; + static_text1.SetValue("AB"); + static_text1.role = blink::WebAXRoleStaticText; + static_text1.location = gfx::Rect(100, 100, 40, 20); + static_text1.child_ids.push_back(6); + + AccessibilityNodeData img; + img.id = 4; + img.role = blink::WebAXRoleImage; + img.location = gfx::Rect(140, 100, 20, 20); + + AccessibilityNodeData static_text2; + static_text2.id = 5; + static_text2.SetValue("CD"); + static_text2.role = blink::WebAXRoleStaticText; + static_text2.location = gfx::Rect(160, 100, 40, 20); + static_text2.child_ids.push_back(7); + + AccessibilityNodeData inline_text1; + inline_text1.id = 6; + inline_text1.SetValue("AB"); + inline_text1.role = blink::WebAXRoleInlineTextBox; + inline_text1.location = gfx::Rect(100, 100, 40, 20); + inline_text1.AddIntAttribute(AccessibilityNodeData::ATTR_TEXT_DIRECTION, + blink::WebAXTextDirectionLR); + std::vector<int32> character_offsets1; + character_offsets1.push_back(20); // 0 + character_offsets1.push_back(40); // 1 + inline_text1.AddIntListAttribute( + AccessibilityNodeData::ATTR_CHARACTER_OFFSETS, character_offsets1); + + AccessibilityNodeData inline_text2; + inline_text2.id = 7; + inline_text2.SetValue("CD"); + inline_text2.role = blink::WebAXRoleInlineTextBox; + inline_text2.location = gfx::Rect(160, 100, 40, 20); + inline_text2.AddIntAttribute(AccessibilityNodeData::ATTR_TEXT_DIRECTION, + blink::WebAXTextDirectionLR); + std::vector<int32> character_offsets2; + character_offsets2.push_back(20); // 0 + character_offsets2.push_back(40); // 1 + inline_text2.AddIntListAttribute( + AccessibilityNodeData::ATTR_CHARACTER_OFFSETS, character_offsets2); + + scoped_ptr<BrowserAccessibilityManager> manager( + BrowserAccessibilityManager::Create( + root, + NULL, + new CountedBrowserAccessibilityFactory())); + manager->UpdateNodesForTesting( + div, static_text1, img, static_text2, inline_text1, inline_text2); + + BrowserAccessibility* root_accessible = manager->GetRoot(); + + EXPECT_EQ(gfx::Rect(100, 100, 20, 20).ToString(), + root_accessible->GetLocalBoundsForRange(0, 1).ToString()); + + EXPECT_EQ(gfx::Rect(100, 100, 40, 20).ToString(), + root_accessible->GetLocalBoundsForRange(0, 2).ToString()); + + EXPECT_EQ(gfx::Rect(100, 100, 80, 20).ToString(), + root_accessible->GetLocalBoundsForRange(0, 3).ToString()); + + EXPECT_EQ(gfx::Rect(120, 100, 60, 20).ToString(), + root_accessible->GetLocalBoundsForRange(1, 2).ToString()); + + EXPECT_EQ(gfx::Rect(120, 100, 80, 20).ToString(), + root_accessible->GetLocalBoundsForRange(1, 3).ToString()); + + EXPECT_EQ(gfx::Rect(100, 100, 100, 20).ToString(), + root_accessible->GetLocalBoundsForRange(0, 4).ToString()); +} + } // namespace content diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index 2c01503..f3520da 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -1933,9 +1933,6 @@ STDMETHODIMP BrowserAccessibilityWin::get_characterExtents( if (offset < 0 || offset > static_cast<LONG>(text_str.size())) return E_INVALIDARG; - if (blink_role() != blink::WebAXRoleStaticText) - return E_FAIL; - gfx::Rect character_bounds; if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { character_bounds = GetGlobalBoundsForRange(offset, 1); @@ -2722,9 +2719,6 @@ STDMETHODIMP BrowserAccessibilityWin::get_unclippedSubstringBounds( return E_INVALIDARG; } - if (blink_role() != blink::WebAXRoleStaticText) - return E_FAIL; - gfx::Rect bounds = GetGlobalBoundsForRange( start_index, end_index - start_index); *out_x = bounds.x(); diff --git a/content/renderer/accessibility/accessibility_node_serializer.cc b/content/renderer/accessibility/accessibility_node_serializer.cc index 39fa245..db79307 100644 --- a/content/renderer/accessibility/accessibility_node_serializer.cc +++ b/content/renderer/accessibility/accessibility_node_serializer.cc @@ -465,16 +465,6 @@ void SerializeAccessibilityNode( bool ShouldIncludeChildNode( const WebAXObject& parent, const WebAXObject& child) { - switch(parent.role()) { - case blink::WebAXRoleSlider: - case blink::WebAXRoleEditableText: - case blink::WebAXRoleTextArea: - case blink::WebAXRoleTextField: - return false; - default: - break; - } - // The child may be invalid due to issues in webkit accessibility code. // Don't add children that are invalid thus preventing a crash. // https://bugs.webkit.org/show_bug.cgi?id=44149 |