[go: up one dir, main page]

Merge to M41: Accessibility BoundsForRange needs to take scroll offsets into account.

BUG=454995

Review URL: https://codereview.chromium.org/895233002

Cr-Commit-Position: refs/heads/master@{#314518}
(cherry picked from commit 9df5f8fdb80c94fd459000f8208cc352680963e8)

Review URL: https://codereview.chromium.org/920123003

Cr-Commit-Position: refs/branch-heads/2272@{#289}
Cr-Branched-From: 827a380cfdb31aa54c8d56e63ce2c3fd8c3ba4d4-refs/heads/master@{#310958}
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 66bd947..8f9a7e3 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -180,43 +180,7 @@
 
 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
   gfx::Rect bounds = GetLocation();
-
-  // Walk up the parent chain. Every time we encounter a Web Area, offset
-  // based on the scroll bars and then offset based on the origin of that
-  // nested web area.
-  BrowserAccessibility* parent = GetParentForBoundsCalculation();
-  bool need_to_offset_web_area =
-      (GetRole() == ui::AX_ROLE_WEB_AREA ||
-       GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
-  while (parent) {
-    if (need_to_offset_web_area &&
-        parent->GetLocation().width() > 0 &&
-        parent->GetLocation().height() > 0) {
-      bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
-      need_to_offset_web_area = false;
-    }
-
-    // On some platforms, we don't want to take the root scroll offsets
-    // into account.
-    if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
-        !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
-      break;
-    }
-
-    if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
-        parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
-      int sx = 0;
-      int sy = 0;
-      if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
-          parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
-        bounds.Offset(-sx, -sy);
-      }
-      need_to_offset_web_area = true;
-    }
-    parent = parent->GetParentForBoundsCalculation();
-  }
-
-  return bounds;
+  return ElementBoundsToLocalBounds(bounds);
 }
 
 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
@@ -246,7 +210,7 @@
       }
       start -= child_len;
     }
-    return bounds;
+    return ElementBoundsToLocalBounds(bounds);
   }
 
   int end = start + len;
@@ -323,7 +287,7 @@
       bounds.Union(child_overlap_rect);
   }
 
-  return bounds;
+  return ElementBoundsToLocalBounds(bounds);
 }
 
 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
@@ -731,4 +695,44 @@
   return manager_->delegate()->AccessibilityGetParentFrame();
 }
 
+gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds)
+    const {
+  // Walk up the parent chain. Every time we encounter a Web Area, offset
+  // based on the scroll bars and then offset based on the origin of that
+  // nested web area.
+  BrowserAccessibility* parent = GetParentForBoundsCalculation();
+  bool need_to_offset_web_area =
+      (GetRole() == ui::AX_ROLE_WEB_AREA ||
+       GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+  while (parent) {
+    if (need_to_offset_web_area &&
+        parent->GetLocation().width() > 0 &&
+        parent->GetLocation().height() > 0) {
+      bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
+      need_to_offset_web_area = false;
+    }
+
+    // On some platforms, we don't want to take the root scroll offsets
+    // into account.
+    if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
+        !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
+      break;
+    }
+
+    if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
+        parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+      int sx = 0;
+      int sy = 0;
+      if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+          parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+        bounds.Offset(-sx, -sy);
+      }
+      need_to_offset_web_area = true;
+    }
+    parent = parent->GetParentForBoundsCalculation();
+  }
+
+  return bounds;
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 64811bd..429375f 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -272,6 +272,11 @@
   std::string name_;
   std::string value_;
 
+  // Convert the bounding rectangle of an element (which is relative to
+  // its nearest scrollable ancestor) to local bounds (which are relative
+  // to the top of the web accessibility tree).
+  gfx::Rect ElementBoundsToLocalBounds(gfx::Rect bounds) const;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
 };
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index d0ca4bb..1b831615 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -798,6 +798,54 @@
             static_text_accessible->GetLocalBoundsForRange(2, 2).ToString());
 }
 
+TEST(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
+  ui::AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.AddIntAttribute(ui::AX_ATTR_SCROLL_X, 25);
+  root.AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 50);
+
+  ui::AXNodeData static_text;
+  static_text.id = 2;
+  static_text.SetValue("ABC");
+  static_text.role = ui::AX_ROLE_STATIC_TEXT;
+  static_text.location = gfx::Rect(100, 100, 16, 9);
+  root.child_ids.push_back(2);
+
+  ui::AXNodeData inline_text;
+  inline_text.id = 3;
+  inline_text.SetValue("ABC");
+  inline_text.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+  inline_text.location = gfx::Rect(100, 100, 16, 9);
+  inline_text.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
+                              ui::AX_TEXT_DIRECTION_LR);
+  std::vector<int32> character_offsets1;
+  character_offsets1.push_back(6);   // 0
+  character_offsets1.push_back(11);  // 1
+  character_offsets1.push_back(16);  // 2
+  inline_text.AddIntListAttribute(
+      ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
+  static_text.child_ids.push_back(3);
+
+  scoped_ptr<BrowserAccessibilityManager> manager(
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, static_text, inline_text),
+          NULL,
+          new CountedBrowserAccessibilityFactory()));
+
+  BrowserAccessibility* root_accessible = manager->GetRoot();
+  BrowserAccessibility* static_text_accessible =
+      root_accessible->PlatformGetChild(0);
+
+  if (manager->UseRootScrollOffsetsWhenComputingBounds()) {
+    EXPECT_EQ(gfx::Rect(75, 50, 16, 9).ToString(),
+              static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+  } else {
+    EXPECT_EQ(gfx::Rect(100, 100, 16, 9).ToString(),
+              static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+  }
+}
+
 #if defined(OS_WIN)
 #define MAYBE_BoundsForRangeOnParentElement \
   DISABLED_BoundsForRangeOnParentElement