Use relative bounding boxes throughout Chrome accessibility
After a series of changes that added support in Blink for relative bounding
boxes for accessible objects, this change switches all of the code in Chrome
to use these relative bounding boxes.
This significantly cleans up the code to convert from local to global
coordinates. Instead of a complicated loop with lots of special cases
for things like out-of-process iframes, it's now a pretty straightforward
process of walking up the tree and applying offsets and transforms.
After this change lands successfully, we can delete the old absolute bounds
computation code from Blink.
BUG=618120
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation
Review-Url: https://codereview.chromium.org/2217363002
Cr-Commit-Position: refs/heads/master@{#412054}
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 66bad5b..7c77249d 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -81,19 +81,18 @@
disappearingObjectDoc: function() {/*!
<p>start</p>
- <article>
+ <div role="group">
<p>Before1</p>
<p>Before2</p>
<p>Before3</p>
- </article>
- <article>
+ </div>
+ <div role="group">
<p id="disappearing">Disappearing</p>
- </article>
- <article>
+ </div>
+ <div role="group">
<p>After1</p>
<p>After2</p>
<p>After3</p>
- </article>
</div>
<div id="live" aria-live="polite"></div>
<div id="delete" role="button">Delete</div>
diff --git a/chrome/common/extensions/chrome_extension_messages.h b/chrome/common/extensions/chrome_extension_messages.h
index 95f1824..a5236b3 100644
--- a/chrome/common/extensions/chrome_extension_messages.h
+++ b/chrome/common/extensions/chrome_extension_messages.h
@@ -71,6 +71,7 @@
IPC_STRUCT_TRAITS_MEMBER(intlist_attributes)
IPC_STRUCT_TRAITS_MEMBER(html_attributes)
IPC_STRUCT_TRAITS_MEMBER(child_ids)
+ IPC_STRUCT_TRAITS_MEMBER(offset_container_id)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeData)
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index 1a1bbcd..17bfce5 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -85,15 +85,15 @@
// Compute the bounding box of a node, fixing nodes with empty bounds by
// unioning the bounds of their children.
-static gfx::Rect ComputeLocalNodeBounds(TreeCache* cache, ui::AXNode* node) {
- gfx::Rect bounds = gfx::ToEnclosingRect(node->data().location);
+static gfx::RectF ComputeLocalNodeBounds(TreeCache* cache, ui::AXNode* node) {
+ gfx::RectF bounds = node->data().location;
if (bounds.width() > 0 && bounds.height() > 0)
return bounds;
// Compute the bounds of each child.
for (size_t i = 0; i < node->children().size(); i++) {
ui::AXNode* child = node->children()[i];
- gfx::Rect child_bounds = ComputeLocalNodeBounds(cache, child);
+ gfx::RectF child_bounds = ComputeLocalNodeBounds(cache, child);
// Ignore children that don't have valid bounds themselves.
if (child_bounds.width() == 0 || child_bounds.height() == 0)
@@ -115,35 +115,39 @@
// Compute the bounding box of a node in global coordinates, walking up the
// parent hierarchy to offset by frame offsets and scroll offsets.
static gfx::Rect ComputeGlobalNodeBounds(TreeCache* cache, ui::AXNode* node) {
- gfx::Rect bounds = ComputeLocalNodeBounds(cache, node);
+ gfx::RectF bounds = ComputeLocalNodeBounds(cache, node);
- ui::AXNode* root = cache->tree.root();
- while (root) {
- // Apply scroll offsets.
- if (root != node) {
- int sx = 0;
- int sy = 0;
- if (root->data().GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
- root->data().GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
- bounds.Offset(-sx, -sy);
+ while (node) {
+ if (node->data().transform)
+ node->data().transform->TransformRect(&bounds);
+
+ ui::AXNode* container =
+ cache->tree.GetFromId(node->data().offset_container_id);
+ if (!container) {
+ if (node == cache->tree.root()) {
+ container = cache->owner->GetParent(node, &cache);
+ } else {
+ container = cache->tree.root();
}
}
- if (root->data().transform) {
- gfx::RectF boundsf(bounds);
- root->data().transform->TransformRect(&boundsf);
- bounds = gfx::Rect(boundsf.x(), boundsf.y(), boundsf.width(),
- boundsf.height());
- }
-
- ui::AXNode* parent = cache->owner->GetParent(root, &cache);
- if (!parent)
+ if (!container || container == node)
break;
- root = cache->tree.root();
+ gfx::RectF container_bounds = ComputeLocalNodeBounds(cache, container);
+ bounds.Offset(container_bounds.x(), container_bounds.y());
+
+ int scroll_x = 0;
+ int scroll_y = 0;
+ if (container->data().GetIntAttribute(ui::AX_ATTR_SCROLL_X, &scroll_x) &&
+ container->data().GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &scroll_y)) {
+ bounds.Offset(-scroll_x, -scroll_y);
+ }
+
+ node = container;
}
- return bounds;
+ return gfx::ToEnclosingRect(bounds);
}
ui::AXNode* FindNodeWithChildTreeId(ui::AXNode* node, int child_tree_id) {
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index 99c241b..00d9a069 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -49,7 +49,7 @@
dict->SetInteger("boundsWidth", bounds.width());
dict->SetInteger("boundsHeight", bounds.height());
- gfx::Rect page_bounds = node.GetLocalBoundsRect();
+ gfx::Rect page_bounds = node.GetPageBoundsRect();
dict->SetInteger("pageBoundsX", page_bounds.x());
dict->SetInteger("pageBoundsY", page_bounds.y());
dict->SetInteger("pageBoundsWidth", page_bounds.width());
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 2186db0..0797a36 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -339,8 +339,8 @@
return empty_data;
}
-gfx::Rect BrowserAccessibility::GetLocation() const {
- return gfx::ToEnclosingRect(GetData().location);
+gfx::RectF BrowserAccessibility::GetLocation() const {
+ return GetData().location;
}
int32_t BrowserAccessibility::GetRole() const {
@@ -356,14 +356,20 @@
return GetData().html_attributes;
}
-gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
- gfx::Rect bounds = GetLocation();
+gfx::Rect BrowserAccessibility::GetFrameBoundsRect() const {
+ gfx::RectF bounds = GetLocation();
FixEmptyBounds(&bounds);
- return ElementBoundsToLocalBounds(bounds);
+ return RelativeToAbsoluteBounds(bounds, true);
}
-gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
- gfx::Rect bounds = GetLocalBoundsRect();
+gfx::Rect BrowserAccessibility::GetPageBoundsRect() const {
+ gfx::RectF bounds = GetLocation();
+ FixEmptyBounds(&bounds);
+ return RelativeToAbsoluteBounds(bounds, false);
+}
+
+gfx::Rect BrowserAccessibility::GetScreenBoundsRect() const {
+ gfx::Rect bounds = GetPageBoundsRect();
// Adjust the bounds by the top left corner of the containing view's bounds
// in screen coordinates.
@@ -372,7 +378,7 @@
return bounds;
}
-gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len)
+gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start, int len)
const {
DCHECK_GE(start, 0);
DCHECK_GE(len, 0);
@@ -381,7 +387,7 @@
// holds all the text.
// TODO(nektar): This is fragile! Replace with code that flattens tree.
if (IsSimpleTextControl() && InternalChildCount() == 1)
- return InternalGetChild(0)->GetLocalBoundsForRange(start, len);
+ return InternalGetChild(0)->GetPageBoundsForRange(start, len);
if (GetRole() != ui::AX_ROLE_STATIC_TEXT) {
gfx::Rect bounds;
@@ -395,9 +401,9 @@
if (start < child_length_in_parent) {
gfx::Rect child_rect;
if (child->IsTextOnlyObject()) {
- child_rect = child->GetLocalBoundsForRange(start, len);
+ child_rect = child->GetPageBoundsForRange(start, len);
} else {
- child_rect = child->GetLocalBoundsForRange(
+ child_rect = child->GetPageBoundsForRange(
0, static_cast<int>(child->GetText().size()));
}
bounds.Union(child_rect);
@@ -408,7 +414,7 @@
else
start = 0;
}
- return ElementBoundsToLocalBounds(bounds);
+ return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
}
int end = start + len;
@@ -451,7 +457,7 @@
int end_pixel_offset =
local_end > 0 ? character_offsets[local_end - 1] : 0;
- gfx::Rect child_rect = child->GetLocation();
+ gfx::Rect child_rect = gfx::ToEnclosingRect(child->GetLocation());
auto text_direction = static_cast<ui::AXTextDirection>(
child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION));
gfx::Rect child_overlap_rect;
@@ -495,12 +501,12 @@
bounds.Union(child_overlap_rect);
}
- return ElementBoundsToLocalBounds(bounds);
+ return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
}
-gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
+gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start, int len)
const {
- gfx::Rect bounds = GetLocalBoundsForRange(start, len);
+ gfx::Rect bounds = GetPageBoundsForRange(start, len);
// Adjust the bounds by the top left corner of the containing view's bounds
// in screen coordinates.
@@ -731,7 +737,7 @@
if (child->GetRole() == ui::AX_ROLE_COLUMN)
continue;
- if (child->GetGlobalBoundsRect().Contains(point)) {
+ if (child->GetScreenBoundsRect().Contains(point)) {
BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point);
if (result == child && !child_result)
child_result = result;
@@ -1146,7 +1152,7 @@
return text;
}
-void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const
+void BrowserAccessibility::FixEmptyBounds(gfx::RectF* bounds) const
{
if (bounds->width() > 0 && bounds->height() > 0)
return;
@@ -1155,7 +1161,7 @@
// Compute the bounds of each child - this calls FixEmptyBounds
// recursively if necessary.
BrowserAccessibility* child = InternalGetChild(i);
- gfx::Rect child_bounds = child->GetLocalBoundsRect();
+ gfx::Rect child_bounds = child->GetPageBoundsRect();
// Ignore children that don't have valid bounds themselves.
if (child_bounds.width() == 0 || child_bounds.height() == 0)
@@ -1163,63 +1169,53 @@
// For the first valid child, just set the bounds to that child's bounds.
if (bounds->width() == 0 || bounds->height() == 0) {
- *bounds = child_bounds;
+ *bounds = gfx::RectF(child_bounds);
continue;
}
// Union each additional child's bounds.
- bounds->Union(child_bounds);
+ bounds->Union(gfx::RectF(child_bounds));
}
}
-gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds)
- const {
- BrowserAccessibilityManager* manager = this->manager();
- BrowserAccessibility* root = manager->GetRoot();
- while (manager && root) {
- // Apply scroll offsets.
- if (root != this && (root->GetParent() ||
- manager->UseRootScrollOffsetsWhenComputingBounds())) {
+gfx::Rect BrowserAccessibility::RelativeToAbsoluteBounds(
+ gfx::RectF bounds,
+ bool frame_only) const {
+ const BrowserAccessibility* node = this;
+ while (node) {
+ if (node->GetData().transform)
+ node->GetData().transform->TransformRect(&bounds);
+
+ const BrowserAccessibility* container =
+ node->manager()->GetFromID(node->GetData().offset_container_id);
+ if (!container) {
+ if (node == node->manager()->GetRoot() && !frame_only) {
+ container = node->GetParent();
+ } else {
+ container = node->manager()->GetRoot();
+ }
+ }
+
+ if (!container || container == node)
+ break;
+
+ gfx::RectF container_bounds = container->GetLocation();
+ bounds.Offset(container_bounds.x(), container_bounds.y());
+
+ if (container->manager()->UseRootScrollOffsetsWhenComputingBounds() ||
+ container->GetParent()) {
int sx = 0;
int sy = 0;
- if (root->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
- root->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+ if (container->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+ container->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
bounds.Offset(-sx, -sy);
}
}
- // If the parent accessibility tree is in a different site instance,
- // ask the delegate to transform our coordinates into the root
- // coordinate space and then we're done.
- if (manager->delegate() &&
- root->GetParent() &&
- root->GetParent()->manager()->delegate()) {
- BrowserAccessibilityManager* parent_manager =
- root->GetParent()->manager();
- if (manager->delegate()->AccessibilityGetSiteInstance() !=
- parent_manager->delegate()->AccessibilityGetSiteInstance()) {
- return manager->delegate()->AccessibilityTransformToRootCoordSpace(
- bounds);
- }
- }
-
- // Otherwise, apply the transform from this frame into the coordinate
- // space of its parent frame.
- if (root->GetData().transform) {
- gfx::RectF boundsf(bounds);
- root->GetData().transform->TransformRect(&boundsf);
- bounds = gfx::Rect(boundsf.x(), boundsf.y(),
- boundsf.width(), boundsf.height());
- }
-
- if (!root->GetParent())
- break;
-
- manager = root->GetParent()->manager();
- root = manager->GetRoot();
+ node = container;
}
- return bounds;
+ return gfx::ToEnclosingRect(bounds);
}
} // namespace content
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index a72e562..8192a195e 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -143,21 +143,24 @@
// Returns nullptr if there are no children.
BrowserAccessibility* InternalDeepestLastChild() const;
+ // Returns the bounds of this object in coordinates relative to this frame.
+ gfx::Rect GetFrameBoundsRect() const;
+
// Returns the bounds of this object in coordinates relative to the
- // top-left corner of the overall web area.
- gfx::Rect GetLocalBoundsRect() const;
+ // page (specifically, the top-left corner of the topmost web contents).
+ gfx::Rect GetPageBoundsRect() const;
// Returns the bounds of this object in screen coordinates.
- gfx::Rect GetGlobalBoundsRect() const;
+ gfx::Rect GetScreenBoundsRect() const;
// Returns the bounds of the given range in coordinates relative to the
// top-left corner of the overall web area. Only valid when the
// role is WebAXRoleStaticText.
- gfx::Rect GetLocalBoundsForRange(int start, int len) const;
+ gfx::Rect GetPageBoundsForRange(int start, int len) const;
- // Same as GetLocalBoundsForRange, in screen coordinates. Only valid when
+ // Same as GetPageBoundsForRange, in screen coordinates. Only valid when
// the role is WebAXRoleStaticText.
- gfx::Rect GetGlobalBoundsForRange(int start, int len) const;
+ gfx::Rect GetScreenBoundsForRange(int start, int len) const;
// This is to handle the cases such as ARIA textbox, where the value should
// be calculated from the object's inner text.
@@ -225,7 +228,7 @@
int32_t GetId() const;
const ui::AXNodeData& GetData() const;
- gfx::Rect GetLocation() const;
+ gfx::RectF GetLocation() const;
int32_t GetRole() const;
int32_t GetState() const;
@@ -364,12 +367,13 @@
// children, since most accessibility APIs don't like elements with no
// bounds, but "virtual" elements in the accessibility tree that don't
// correspond to a layed-out element sometimes don't have bounds.
- void FixEmptyBounds(gfx::Rect* bounds) const;
+ void FixEmptyBounds(gfx::RectF* bounds) const;
// 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;
+ // its nearest scrollable ancestor) to absolute bounds, either in
+ // page coordinates (when |frameOnly| is false), or in frame coordinates
+ // (when |frameOnly| is true).
+ gfx::Rect RelativeToAbsoluteBounds(gfx::RectF bounds, bool frame_only) const;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
};
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index c509b05..abe3a01 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -972,18 +972,18 @@
// If this is a web area inside of an iframe, try to use the bounds of
// the containing element.
BrowserAccessibility* parent = GetParent();
- while (parent && (parent->GetLocation().width() == 0 ||
- parent->GetLocation().height() == 0)) {
+ while (parent && (parent->GetPageBoundsRect().width() == 0 ||
+ parent->GetPageBoundsRect().height() == 0)) {
parent = parent->GetParent();
}
if (parent)
- bounds = parent->GetLocation();
+ bounds = parent->GetPageBoundsRect();
else
- bounds = GetLocation();
+ bounds = GetPageBoundsRect();
} else {
// Otherwise this is something like a scrollable div, just use the
// bounds of this object itself.
- bounds = GetLocation();
+ bounds = GetPageBoundsRect();
}
// Scroll by 80% of one page.
@@ -1249,7 +1249,7 @@
CHECK_EQ(ui::AX_ROLE_INLINE_TEXT_BOX, child->GetRole());
// TODO(dmazzoni): replace this with a proper API to determine
// if two inline text boxes are on the same line. http://crbug.com/421771
- int y = child->GetLocation().y();
+ int y = child->GetPageBoundsRect().y();
if (i == 0) {
line_starts->push_back(offset);
} else if (y != last_y) {
diff --git a/content/browser/accessibility/browser_accessibility_auralinux.cc b/content/browser/accessibility/browser_accessibility_auralinux.cc
index 38066a1..b3e8ae2 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux.cc
@@ -144,7 +144,7 @@
return NULL;
gfx::Point point(x, y);
- if (!obj->GetGlobalBoundsRect().Contains(point))
+ if (!obj->GetScreenBoundsRect().Contains(point))
return NULL;
BrowserAccessibility* result = obj->BrowserAccessibilityForPoint(point);
@@ -170,7 +170,7 @@
if (!obj)
return;
- gfx::Rect bounds = obj->GetGlobalBoundsRect();
+ gfx::Rect bounds = obj->GetScreenBoundsRect();
if (x)
*x = bounds.x();
if (y)
@@ -300,7 +300,7 @@
gint* y,
gint* width,
gint* height) {
- gfx::Rect img_pos_size = obj->GetGlobalBoundsRect();
+ gfx::Rect img_pos_size = obj->GetScreenBoundsRect();
if (x)
*x = img_pos_size.x();
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 1b84156..900686d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1172,7 +1172,7 @@
- (NSPoint)origin {
if (![self instanceActive])
return NSMakePoint(0, 0);
- gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
+ gfx::Rect bounds = browserAccessibility_->GetPageBoundsRect();
return NSMakePoint(bounds.x(), bounds.y());
}
@@ -1610,7 +1610,7 @@
- (NSValue*)size {
if (![self instanceActive])
return nil;
- gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
+ gfx::Rect bounds = browserAccessibility_->GetPageBoundsRect();
return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
}
@@ -2248,7 +2248,7 @@
if ([self internalRole] != ui::AX_ROLE_STATIC_TEXT)
return nil;
NSRange range = [(NSValue*)parameter rangeValue];
- gfx::Rect rect = browserAccessibility_->GetGlobalBoundsForRange(
+ gfx::Rect rect = browserAccessibility_->GetScreenBoundsForRange(
range.location, range.length);
NSPoint origin = NSMakePoint(rect.x(), rect.y());
NSSize size = NSMakeSize(rect.width(), rect.height());
@@ -2312,7 +2312,7 @@
DCHECK_GE(startOffset, 0);
DCHECK_GE(endOffset, 0);
- gfx::Rect rect = BrowserAccessibilityManager::GetLocalBoundsForRange(
+ gfx::Rect rect = BrowserAccessibilityManager::GetPageBoundsForRange(
*startObject, startOffset, *endObject, endOffset);
NSPoint origin = NSMakePoint(rect.x(), rect.y());
NSSize size = NSMakeSize(rect.width(), rect.height());
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 7cef0bb5..3564fe2 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -413,7 +413,9 @@
if (!obj)
continue;
ui::AXNode* node = obj->node();
- node->SetLocation(params[i].new_location);
+ node->SetLocation(params[i].new_location.offset_container_id,
+ params[i].new_location.bounds,
+ params[i].new_location.transform.get());
}
SendLocationChangeEvents(params);
}
@@ -887,7 +889,7 @@
}
// static
-gfx::Rect BrowserAccessibilityManager::GetLocalBoundsForRange(
+gfx::Rect BrowserAccessibilityManager::GetPageBoundsForRange(
const BrowserAccessibility& start_object,
int start_offset,
const BrowserAccessibility& end_object,
@@ -904,7 +906,7 @@
return gfx::Rect();
}
- return start_object.GetLocalBoundsForRange(
+ return start_object.GetPageBoundsForRange(
start_offset, end_offset - start_offset);
}
@@ -934,10 +936,10 @@
start_char_index = start_offset;
if (current == last)
end_char_index = end_offset;
- result.Union(current->GetLocalBoundsForRange(
+ result.Union(current->GetPageBoundsForRange(
start_char_index, end_char_index - start_char_index));
} else {
- result.Union(current->GetLocalBoundsRect());
+ result.Union(current->GetPageBoundsRect());
}
if (current == last)
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index a1bb8e9..b57b89d5 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -343,7 +343,7 @@
const BrowserAccessibility& end_object,
int end_offset);
- static gfx::Rect GetLocalBoundsForRange(
+ static gfx::Rect GetPageBoundsForRange(
const BrowserAccessibility& start_object,
int start_offset,
const BrowserAccessibility& end_object,
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index e34d36a0..6253e4e 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -440,10 +440,10 @@
base::android::ConvertUTF16ToJavaString(env, element_id).obj());
}
- gfx::Rect absolute_rect = node->GetLocalBoundsRect();
+ gfx::Rect absolute_rect = node->GetPageBoundsRect();
gfx::Rect parent_relative_rect = absolute_rect;
if (node->GetParent()) {
- gfx::Rect parent_rect = node->GetParent()->GetLocalBoundsRect();
+ gfx::Rect parent_rect = node->GetParent()->GetPageBoundsRect();
parent_relative_rect.Offset(-parent_rect.OffsetFromOrigin());
}
bool is_root = node->GetParent() == NULL;
@@ -623,7 +623,7 @@
jint id) {
BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
if (node)
- ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size()));
+ ScrollToMakeVisible(*node, gfx::Rect(node->GetFrameBoundsRect().size()));
}
void BrowserAccessibilityManagerAndroid::SetTextFieldValue(
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index dfb0cf5..e4309f0 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -694,28 +694,28 @@
ASSERT_NE(nullptr, static_text_accessible);
EXPECT_EQ(gfx::Rect(100, 100, 6, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 1).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 1).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 26, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 5).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 5).ToString());
EXPECT_EQ(gfx::Rect(100, 109, 5, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(7, 1).ToString());
+ static_text_accessible->GetPageBoundsForRange(7, 1).ToString());
EXPECT_EQ(gfx::Rect(100, 109, 25, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(7, 5).ToString());
+ static_text_accessible->GetPageBoundsForRange(7, 5).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
- static_text_accessible->GetLocalBoundsForRange(5, 3).ToString());
+ static_text_accessible->GetPageBoundsForRange(5, 3).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 13).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 13).ToString());
// Note that each child in the parent element is represented by a single
// embedded object character and not by its text.
// TODO(nektar): Investigate failure on Linux.
EXPECT_EQ(gfx::Rect(100, 100, 29, 18).ToString(),
- root_accessible->GetLocalBoundsForRange(0, 13).ToString());
+ root_accessible->GetPageBoundsForRange(0, 13).ToString());
}
TEST(BrowserAccessibilityManagerTest, BoundsForRangeMultiElement) {
@@ -777,43 +777,43 @@
// The first line.
EXPECT_EQ(gfx::Rect(0, 20, 33, 9).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible, 0,
*static_text_accessible, 3).ToString());
// Part of the first line.
EXPECT_EQ(gfx::Rect(0, 20, 21, 9).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible, 0,
*static_text_accessible, 2).ToString());
// Part of the first line.
EXPECT_EQ(gfx::Rect(10, 20, 23, 9).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible, 1,
*static_text_accessible, 3).ToString());
// The second line.
EXPECT_EQ(gfx::Rect(10, 40, 33, 9).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible2, 0,
*static_text_accessible2, 3).ToString());
// All of both lines.
EXPECT_EQ(gfx::Rect(0, 20, 43, 29).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible, 0,
*static_text_accessible2, 3).ToString());
// Part of both lines.
EXPECT_EQ(gfx::Rect(10, 20, 23, 29).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible, 2,
*static_text_accessible2, 1).ToString());
// Part of both lines in reverse order.
EXPECT_EQ(gfx::Rect(10, 20, 23, 29).ToString(),
- manager->GetLocalBoundsForRange(
+ manager->GetPageBoundsForRange(
*static_text_accessible2, 1,
*static_text_accessible, 2).ToString());
}
@@ -824,7 +824,7 @@
// words, on-screen it would look like "123cba". This is possible to
// achieve if the source string had unicode control characters
// to switch directions. This test doesn't worry about how, though - it just
- // tests that if something like that were to occur, GetLocalBoundsForRange
+ // tests that if something like that were to occur, GetPageBoundsForRange
// returns the correct bounds for different ranges.
ui::AXNodeData root;
@@ -880,24 +880,24 @@
ASSERT_NE(nullptr, static_text_accessible);
EXPECT_EQ(gfx::Rect(100, 100, 60, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 6).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 6).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 10, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 1).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 1).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 30, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
EXPECT_EQ(gfx::Rect(150, 100, 10, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(3, 1).ToString());
+ static_text_accessible->GetPageBoundsForRange(3, 1).ToString());
EXPECT_EQ(gfx::Rect(130, 100, 30, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(3, 3).ToString());
+ static_text_accessible->GetPageBoundsForRange(3, 3).ToString());
// This range is only two characters, but because of the direction switch
// the bounds are as wide as four characters.
EXPECT_EQ(gfx::Rect(120, 100, 40, 20).ToString(),
- static_text_accessible->GetLocalBoundsForRange(2, 2).ToString());
+ static_text_accessible->GetPageBoundsForRange(2, 2).ToString());
}
TEST(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
@@ -942,10 +942,10 @@
if (manager->UseRootScrollOffsetsWhenComputingBounds()) {
EXPECT_EQ(gfx::Rect(75, 50, 16, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
} else {
EXPECT_EQ(gfx::Rect(100, 100, 16, 9).ToString(),
- static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+ static_text_accessible->GetPageBoundsForRange(0, 3).ToString());
}
}
@@ -1020,22 +1020,22 @@
ASSERT_NE(nullptr, div_accessible);
EXPECT_EQ(gfx::Rect(100, 100, 20, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(0, 1).ToString());
+ div_accessible->GetPageBoundsForRange(0, 1).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 40, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(0, 2).ToString());
+ div_accessible->GetPageBoundsForRange(0, 2).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 80, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(0, 4).ToString());
+ div_accessible->GetPageBoundsForRange(0, 4).ToString());
EXPECT_EQ(gfx::Rect(120, 100, 60, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(1, 3).ToString());
+ div_accessible->GetPageBoundsForRange(1, 3).ToString());
EXPECT_EQ(gfx::Rect(120, 100, 80, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(1, 4).ToString());
+ div_accessible->GetPageBoundsForRange(1, 4).ToString());
EXPECT_EQ(gfx::Rect(100, 100, 100, 20).ToString(),
- div_accessible->GetLocalBoundsForRange(0, 5).ToString());
+ div_accessible->GetPageBoundsForRange(0, 5).ToString());
}
TEST(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index b260045..238c6882 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -261,7 +261,7 @@
return E_INVALIDARG;
gfx::Point point(x_left, y_top);
- if (!GetGlobalBoundsRect().Contains(point)) {
+ if (!GetScreenBoundsRect().Contains(point)) {
// Return S_FALSE and VT_EMPTY when outside the object's boundaries.
child->vt = VT_EMPTY;
return S_FALSE;
@@ -294,7 +294,7 @@
if (!target)
return E_INVALIDARG;
- gfx::Rect bounds = target->GetGlobalBoundsRect();
+ gfx::Rect bounds = target->GetScreenBoundsRect();
*x_left = bounds.x();
*y_top = bounds.y();
*width = bounds.width();
@@ -827,7 +827,7 @@
if (!instance_active())
return E_FAIL;
- gfx::Rect r = GetLocation();
+ gfx::Rect r = GetFrameBoundsRect();
switch(scroll_type) {
case IA2_SCROLL_TYPE_TOP_LEFT:
manager()->ScrollToMakeVisible(*this, gfx::Rect(r.x(), r.y(), 0, 0));
@@ -875,7 +875,7 @@
scroll_to -= manager()->GetViewBounds().OffsetFromOrigin();
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
if (GetParent())
- scroll_to += GetParent()->GetLocation().OffsetFromOrigin();
+ scroll_to += GetParent()->GetFrameBoundsRect().OffsetFromOrigin();
} else {
return E_INVALIDARG;
}
@@ -1043,21 +1043,15 @@
return E_INVALIDARG;
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
- HWND parent_hwnd =
- manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
- if (!parent_hwnd)
- return E_FAIL;
- POINT top_left = {0, 0};
- ::ClientToScreen(parent_hwnd, &top_left);
- *x = GetLocation().x() + top_left.x;
- *y = GetLocation().y() + top_left.y;
+ gfx::Rect bounds = GetScreenBoundsRect();
+ *x = bounds.x();
+ *y = bounds.y();
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
- *x = GetLocation().x();
- *y = GetLocation().y();
- if (GetParent()) {
- *x -= GetParent()->GetLocation().x();
- *y -= GetParent()->GetLocation().y();
- }
+ gfx::Rect bounds = GetPageBoundsRect();
+ gfx::Rect parent_bounds =
+ GetParent() ? GetParent()->GetPageBoundsRect() : gfx::Rect();
+ *x = bounds.x() - parent_bounds.x();
+ *y = bounds.y() - parent_bounds.y();
} else {
return E_INVALIDARG;
}
@@ -1072,8 +1066,8 @@
if (!height || !width)
return E_INVALIDARG;
- *height = GetLocation().height();
- *width = GetLocation().width();
+ *height = GetPageBoundsRect().height();
+ *width = GetPageBoundsRect().width();
return S_OK;
}
@@ -2014,10 +2008,11 @@
gfx::Rect character_bounds;
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
- character_bounds = GetGlobalBoundsForRange(offset, 1);
+ character_bounds = GetScreenBoundsForRange(offset, 1);
} else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
- character_bounds = GetLocalBoundsForRange(offset, 1);
- character_bounds -= GetLocation().OffsetFromOrigin();
+ character_bounds = GetPageBoundsForRange(offset, 1);
+ if (GetParent())
+ character_bounds -= GetParent()->GetPageBoundsRect().OffsetFromOrigin();
} else {
return E_INVALIDARG;
}
@@ -3098,7 +3093,7 @@
return E_INVALIDARG;
}
- gfx::Rect bounds = GetGlobalBoundsForRange(
+ gfx::Rect bounds = GetScreenBoundsForRange(
start_index, end_index - start_index);
*out_x = bounds.x();
*out_y = bounds.y();
@@ -3119,7 +3114,7 @@
return E_INVALIDARG;
}
- manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
+ manager()->ScrollToMakeVisible(*this, GetPageBoundsForRange(
start_index, end_index - start_index));
manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index f929fbf6..e71b915 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -109,7 +109,7 @@
text_style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
}
- const gfx::Rect& absolute_rect = node->GetLocalBoundsRect();
+ const gfx::Rect& absolute_rect = node->GetPageBoundsRect();
gfx::Rect parent_relative_rect = absolute_rect;
bool is_root = node->GetParent() == nullptr;
if (!is_root) {
diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h
index 74ff2966..13697fd 100644
--- a/content/common/accessibility_messages.h
+++ b/content/common/accessibility_messages.h
@@ -14,6 +14,7 @@
#include "ipc/param_traits_macros.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_relative_bounds.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/transform.h"
@@ -39,6 +40,7 @@
IPC_STRUCT_TRAITS_MEMBER(html_attributes)
IPC_STRUCT_TRAITS_MEMBER(child_ids)
IPC_STRUCT_TRAITS_MEMBER(content_int_attributes)
+ IPC_STRUCT_TRAITS_MEMBER(offset_container_id)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::AXContentTreeData)
@@ -70,6 +72,12 @@
IPC_STRUCT_TRAITS_MEMBER(nodes)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(ui::AXRelativeBounds)
+ IPC_STRUCT_TRAITS_MEMBER(offset_container_id)
+ IPC_STRUCT_TRAITS_MEMBER(bounds)
+ IPC_STRUCT_TRAITS_MEMBER(transform)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_BEGIN(AccessibilityHostMsg_EventParams)
// The tree update.
IPC_STRUCT_MEMBER(content::AXContentTreeUpdate, update)
@@ -85,9 +93,8 @@
// ID of the object whose location is changing.
IPC_STRUCT_MEMBER(int, id)
- // The object's new location, in frame-relative coordinates (same
- // as the coordinates in AccessibilityNodeData).
- IPC_STRUCT_MEMBER(gfx::RectF, new_location)
+ // The object's new location info.
+ IPC_STRUCT_MEMBER(ui::AXRelativeBounds, new_location)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(AccessibilityHostMsg_FindInPageResultParams)
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index e405eb7..bc55845 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -19,6 +19,7 @@
#include "content/renderer/render_frame_proxy.h"
#include "content/renderer/render_view_impl.h"
#include "content/renderer/web_frame_utils.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebString.h"
@@ -40,6 +41,7 @@
using blink::WebAXObject;
using blink::WebDocument;
using blink::WebElement;
+using blink::WebFloatRect;
using blink::WebFrame;
using blink::WebLocalFrame;
using blink::WebNode;
@@ -265,9 +267,19 @@
AXContentNodeData* dst) const {
dst->role = AXRoleFromBlink(src.role());
dst->state = AXStateFromBlink(src);
- dst->location = gfx::RectF(src.boundingBoxRect());
dst->id = src.axID();
+ WebAXObject offset_container;
+ WebFloatRect bounds_in_container;
+ SkMatrix44 container_transform;
+ src.getRelativeBounds(
+ offset_container, bounds_in_container, container_transform);
+ dst->location = bounds_in_container;
+ if (!container_transform.isIdentity())
+ dst->transform = base::WrapUnique(new gfx::Transform(container_transform));
+ if (!offset_container.isDetached())
+ dst->offset_container_id = offset_container.axID();
+
blink::WebAXNameFrom nameFrom;
blink::WebVector<blink::WebAXObject> nameObjects;
blink::WebString web_name = src.name(nameFrom, nameObjects);
@@ -581,11 +593,8 @@
src.minValueForRange());
}
- if (dst->role == ui::AX_ROLE_ROOT_WEB_AREA) {
+ if (dst->role == ui::AX_ROLE_ROOT_WEB_AREA)
dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document");
- dst->transform.reset(
- new gfx::Transform(src.transformFromLocalParentFrame()));
- }
if (dst->role == ui::AX_ROLE_TABLE) {
int column_count = src.columnCount();
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 4538ca4..872beb3 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -19,6 +19,7 @@
#include "content/renderer/accessibility/blink_ax_enum_conversion.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_view_impl.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
#include "third_party/WebKit/public/web/WebAXObject.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
@@ -30,6 +31,7 @@
using blink::WebAXObject;
using blink::WebDocument;
using blink::WebElement;
+using blink::WebFloatRect;
using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebPoint;
@@ -337,8 +339,13 @@
// For each node in the update, set the location in our map from
// ids to locations.
for (size_t i = 0; i < event_msg.update.nodes.size(); ++i) {
- locations_[event_msg.update.nodes[i].id] =
- event_msg.update.nodes[i].location;
+ ui::AXNodeData& src = event_msg.update.nodes[i];
+ ui::AXRelativeBounds& dst = locations_[event_msg.update.nodes[i].id];
+ dst.offset_container_id = src.offset_container_id;
+ dst.bounds = src.location;
+ dst.transform.reset(nullptr);
+ if (src.transform)
+ dst.transform.reset(new gfx::Transform(*src.transform));
}
DVLOG(0) << "Accessibility event: " << ui::ToString(event.event_type)
@@ -362,7 +369,7 @@
return;
// Do a breadth-first explore of the whole blink AX tree.
- base::hash_map<int, gfx::RectF> new_locations;
+ base::hash_map<int, ui::AXRelativeBounds> new_locations;
std::queue<WebAXObject> objs_to_explore;
objs_to_explore.push(root);
while (objs_to_explore.size()) {
@@ -372,12 +379,22 @@
// See if we had a previous location. If not, this whole subtree must
// be new, so don't continue to explore this branch.
int id = obj.axID();
- base::hash_map<int, gfx::RectF>::iterator iter = locations_.find(id);
+ auto iter = locations_.find(id);
if (iter == locations_.end())
continue;
// If the location has changed, append it to the IPC message.
- gfx::RectF new_location = gfx::RectF(obj.boundingBoxRect());
+ WebAXObject offset_container;
+ WebFloatRect bounds_in_container;
+ SkMatrix44 container_transform;
+ obj.getRelativeBounds(
+ offset_container, bounds_in_container, container_transform);
+ ui::AXRelativeBounds new_location;
+ new_location.offset_container_id = offset_container.axID();
+ new_location.bounds = bounds_in_container;
+ if (!container_transform.isIdentity())
+ new_location.transform = base::WrapUnique(
+ new gfx::Transform(container_transform));
if (iter != locations_.end() && iter->second != new_location) {
AccessibilityHostMsg_LocationChangeParams message;
message.id = id;
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h
index 002da728..bd7e0cb9 100644
--- a/content/renderer/accessibility/render_accessibility_impl.h
+++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -15,6 +15,7 @@
#include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/accessibility/blink_ax_tree_source.h"
#include "third_party/WebKit/public/web/WebAXObject.h"
+#include "ui/accessibility/ax_relative_bounds.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -153,7 +154,7 @@
PdfAXTreeSource* pdf_tree_source_;
// Current location of every object, so we can detect when it moves.
- base::hash_map<int, gfx::RectF> locations_;
+ base::hash_map<int, ui::AXRelativeBounds> locations_;
// The most recently observed scroll offset of the root document element.
// TODO(dmazzoni): remove once https://bugs.webkit.org/show_bug.cgi?id=73460
diff --git a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
index 49b846ba..75d1a94 100644
--- a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
@@ -2,6 +2,6 @@
++iframe pageLocation=(0, 0)
++++rootWebArea pageLocation=(0, 0)
++++++image pageLocation=(10, 10) pageSize=(200, 200)
-++iframe pageLocation=(0, 300)
+++iframe pageLocation=(0, 300) transform
++++rootWebArea pageLocation=(0, 300)
++++++image pageLocation=(20, 320) pageSize=(400, 400)
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
index 40822d2..75d1a94 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
@@ -2,6 +2,6 @@
++iframe pageLocation=(0, 0)
++++rootWebArea pageLocation=(0, 0)
++++++image pageLocation=(10, 10) pageSize=(200, 200)
-++iframe pageLocation=(0, 300)
-++++rootWebArea pageLocation=(0, 300) transform
+++iframe pageLocation=(0, 300) transform
+++++rootWebArea pageLocation=(0, 300)
++++++image pageLocation=(20, 320) pageSize=(400, 400)
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
index 8daa565..434b7e9 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
@@ -1,6 +1,6 @@
rootWebArea pageLocation=(0, 0)
-++iframe pageLocation=(0, 100)
+++iframe pageLocation=(0, 100) transform
++++rootWebArea pageLocation=(0, 100)
-++++++iframe pageLocation=(200, 100)
+++++++iframe pageLocation=(200, 100) transform
++++++++rootWebArea pageLocation=(200, 100)
++++++++++image pageLocation=(240, 140) pageSize=(800, 800)
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
index 43c038e..434b7e9 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
@@ -1,6 +1,6 @@
rootWebArea pageLocation=(0, 0)
-++iframe pageLocation=(0, 100)
+++iframe pageLocation=(0, 100) transform
++++rootWebArea pageLocation=(0, 100)
-++++++iframe pageLocation=(200, 100)
-++++++++rootWebArea pageLocation=(200, 100) transform
+++++++iframe pageLocation=(200, 100) transform
+++++++++rootWebArea pageLocation=(200, 100)
++++++++++image pageLocation=(240, 140) pageSize=(800, 800)
diff --git a/content/test/data/accessibility/html/iframe-transform-scrolled-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-scrolled-expected-blink.txt
index 04979ae3..0c67fa4 100644
--- a/content/test/data/accessibility/html/iframe-transform-scrolled-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-scrolled-expected-blink.txt
@@ -1,6 +1,6 @@
rootWebArea pageLocation=(0, 0) scrollX=0 scrollXMin=0 scrollXMax=0 scrollY=0 scrollYMin=0 scrollYMax=0
++group pageLocation=(0, 0)
-++++iframe pageLocation=(0, 0)
-++++++rootWebArea pageLocation=(0, 0) transform scrollX=150 scrollXMin=0 scrollXMax=150 scrollY=50 scrollYMin=0 scrollYMax=50
+++++iframe pageLocation=(0, 0) transform
+++++++rootWebArea pageLocation=(0, 0) scrollX=150 scrollXMin=0 scrollXMax=150 scrollY=50 scrollYMin=0 scrollYMax=50
++++++++div pageLocation=(-300, -100)
++++++++++button pageLocation=(-250, -50) pageSize=(500, 100) name='Scrolled Button'
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index fa5c4917..2c9b49d 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -45,6 +45,8 @@
"ax_node.h",
"ax_node_data.cc",
"ax_node_data.h",
+ "ax_relative_bounds.cc",
+ "ax_relative_bounds.h",
"ax_serializable_tree.cc",
"ax_serializable_tree.h",
"ax_text_utils.cc",
diff --git a/ui/accessibility/accessibility.gyp b/ui/accessibility/accessibility.gyp
index 5489aa1..a99aece8 100644
--- a/ui/accessibility/accessibility.gyp
+++ b/ui/accessibility/accessibility.gyp
@@ -32,6 +32,8 @@
'ax_node.h',
'ax_node_data.cc',
'ax_node_data.h',
+ 'ax_relative_bounds.cc',
+ 'ax_relative_bounds.h',
'ax_serializable_tree.cc',
'ax_serializable_tree.h',
'ax_text_utils.cc',
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 462e4e8..a0e53fad 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ui/accessibility/ax_node.h"
+#include "ui/gfx/transform.h"
namespace ui {
@@ -18,8 +19,15 @@
data_ = src;
}
-void AXNode::SetLocation(const gfx::RectF& new_location) {
- data_.location = new_location;
+void AXNode::SetLocation(int offset_container_id,
+ const gfx::RectF& location,
+ gfx::Transform* transform) {
+ data_.offset_container_id = offset_container_id;
+ data_.location = location;
+ if (transform)
+ data_.transform.reset(new gfx::Transform(*transform));
+ else
+ data_.transform.reset(nullptr);
}
void AXNode::SetIndexInParent(int index_in_parent) {
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index 54e443d..e141591 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -44,7 +44,13 @@
// Update this node's location. This is separate from SetData just because
// changing only the location is common and should be more efficient than
// re-copying all of the data.
- void SetLocation(const gfx::RectF& new_location);
+ //
+ // The node's location is stored as a relative bounding box, the ID of
+ // the element it's relative to, and an optional transformation matrix.
+ // See ax_node_data.h for details.
+ void SetLocation(int offset_container_id,
+ const gfx::RectF& location,
+ gfx::Transform* transform);
// Set the index in parent, for example if siblings were inserted or deleted.
void SetIndexInParent(int index_in_parent);
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 0191bc6..0f04517 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -60,7 +60,8 @@
AXNodeData::AXNodeData()
: id(-1),
role(AX_ROLE_UNKNOWN),
- state(0xFFFFFFFF) {
+ state(0xFFFFFFFF),
+ offset_container_id(-1) {
}
AXNodeData::~AXNodeData() {
@@ -78,6 +79,7 @@
html_attributes = other.html_attributes;
child_ids = other.child_ids;
location = other.location;
+ offset_container_id = other.offset_container_id;
if (other.transform)
transform.reset(new gfx::Transform(*other.transform));
}
@@ -94,8 +96,11 @@
html_attributes = other.html_attributes;
child_ids = other.child_ids;
location = other.location;
+ offset_container_id = other.offset_container_id;
if (other.transform)
transform.reset(new gfx::Transform(*other.transform));
+ else
+ transform.reset(nullptr);
return *this;
}
@@ -343,6 +348,9 @@
IntToString(location.width()) + ", " +
IntToString(location.height()) + ")";
+ if (offset_container_id != -1)
+ result += " offset_container_id=" + IntToString(offset_container_id);
+
if (transform && !transform->IsIdentity())
result += " transform=" + transform->ToString();
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
index 7fe95e2..3fbaaa5 100644
--- a/ui/accessibility/ax_node_data.h
+++ b/ui/accessibility/ax_node_data.h
@@ -113,7 +113,14 @@
base::StringPairs html_attributes;
std::vector<int32_t> child_ids;
- // The object's location relative to its window or frame.
+ // TODO(dmazzoni): replace the following three members with a single
+ // instance of AXRelativeBounds.
+
+ // The id of an ancestor node in the same AXTree that this object's
+ // bounding box is relative to, or -1 if there's no offset container.
+ int offset_container_id;
+
+ // The relative bounding box of this node.
gfx::RectF location;
// An additional transform to apply to position this object and its subtree.
diff --git a/ui/accessibility/ax_relative_bounds.cc b/ui/accessibility/ax_relative_bounds.cc
new file mode 100644
index 0000000..322a068
--- /dev/null
+++ b/ui/accessibility/ax_relative_bounds.cc
@@ -0,0 +1,69 @@
+// 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_relative_bounds.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "ui/gfx/transform.h"
+
+using base::IntToString;
+
+namespace ui {
+
+AXRelativeBounds::AXRelativeBounds()
+ : offset_container_id(-1) {
+}
+
+AXRelativeBounds::~AXRelativeBounds() {
+}
+
+AXRelativeBounds::AXRelativeBounds(const AXRelativeBounds& other) {
+ offset_container_id = other.offset_container_id;
+ bounds = other.bounds;
+ if (other.transform)
+ transform.reset(new gfx::Transform(*other.transform));
+}
+
+AXRelativeBounds& AXRelativeBounds::operator=(AXRelativeBounds other) {
+ offset_container_id = other.offset_container_id;
+ bounds = other.bounds;
+ if (other.transform)
+ transform.reset(new gfx::Transform(*other.transform));
+ return *this;
+}
+
+bool AXRelativeBounds::operator==(const AXRelativeBounds& other) {
+ if (offset_container_id != other.offset_container_id)
+ return false;
+ if (bounds != other.bounds)
+ return false;
+ if (!transform && !other.transform)
+ return true;
+ if ((transform && !other.transform) || (!transform && other.transform))
+ return false;
+ return *transform == *other.transform;
+}
+
+bool AXRelativeBounds::operator!=(const AXRelativeBounds& other) {
+ return !operator==(other);
+}
+
+std::string AXRelativeBounds::ToString() const {
+ std::string result;
+
+ if (offset_container_id != -1)
+ result += "offset_container_id=" + IntToString(offset_container_id) + " ";
+
+ result += "(" + IntToString(bounds.x()) + ", " +
+ IntToString(bounds.y()) + ")-(" +
+ IntToString(bounds.width()) + ", " +
+ IntToString(bounds.height()) + ")";
+
+ if (transform && !transform->IsIdentity())
+ result += " transform=" + transform->ToString();
+
+ return result;
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_relative_bounds.h b/ui/accessibility/ax_relative_bounds.h
new file mode 100644
index 0000000..478275a
--- /dev/null
+++ b/ui/accessibility/ax_relative_bounds.h
@@ -0,0 +1,61 @@
+// 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_RELATIVE_BOUNDS_H_
+#define UI_ACCESSIBILITY_AX_RELATIVE_BOUNDS_H_
+
+#include <memory>
+
+#include "ui/accessibility/ax_export.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace gfx {
+class Transform;
+};
+
+namespace ui {
+
+// The relative bounding box of an AXNode.
+//
+// This is an efficient, compact, serializable representation of a node's
+// bounding box that requires minimal changes to the tree when layers are
+// moved or scrolled. Computing the absolute bounding box of a node requires
+// walking up the tree and applying node offsets and transforms until reaching
+// the top.
+//
+// If the offset container id is valid, the bounds are relative
+// to the node with that offset container id.
+//
+// Otherwise, for a node other than the root, the bounds are relative to
+// the root of the tree, and for the root of a tree, the bounds are relative
+// to its immediate containing node.
+struct AX_EXPORT AXRelativeBounds {
+ AXRelativeBounds();
+ virtual ~AXRelativeBounds();
+
+ AXRelativeBounds(const AXRelativeBounds& other);
+ AXRelativeBounds& operator=(AXRelativeBounds other);
+ bool operator!=(const AXRelativeBounds& other);
+ bool operator==(const AXRelativeBounds& other);
+
+ std::string ToString() const;
+
+ // The id of an ancestor node in the same AXTree that this object's
+ // bounding box is relative to, or -1 if there's no offset container.
+ int offset_container_id;
+
+ // The relative bounding box of this node.
+ gfx::RectF bounds;
+
+ // An additional transform to apply to position this object and its subtree.
+ // NOTE: this member is a std::unique_ptr because it's rare and gfx::Transform
+ // takes up a fair amount of space. The assignment operator and copy
+ // constructor both make a duplicate of the owned pointer, so it acts more
+ // like a member than a pointer.
+ std::unique_ptr<gfx::Transform> transform;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_NODE_DATA_H_
diff --git a/ui/accessibility/ax_tree_combiner.cc b/ui/accessibility/ax_tree_combiner.cc
index 8214248..07318025 100644
--- a/ui/accessibility/ax_tree_combiner.cc
+++ b/ui/accessibility/ax_tree_combiner.cc
@@ -185,6 +185,10 @@
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 other int attributes that refer to node IDs, and remove the
// AX_ATTR_CHILD_TREE_ID attribute.
for (size_t j = 0; j < node.int_attributes.size(); ++j) {