Index: chrome/renderer/extensions/automation_internal_custom_bindings.cc |
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc |
index 5c8dc7fa754e26d1226a369c9dd12fb42a777e3c..225d68d4a01b6a150cdd15c93da95797a0ea6b17 100644 |
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc |
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc |
@@ -112,11 +112,13 @@ static gfx::RectF ComputeLocalNodeBounds(TreeCache* cache, ui::AXNode* node) { |
return bounds; |
} |
-// 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::RectF bounds = ComputeLocalNodeBounds(cache, node); |
- |
+// Adjust the bounding box of a node from local to 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::RectF local_bounds) { |
+ gfx::RectF bounds = local_bounds; |
while (node) { |
if (node->data().transform) |
node->data().transform->TransformRect(&bounds); |
@@ -523,9 +525,11 @@ AutomationInternalCustomBindings::AutomationInternalCustomBindings( |
RouteNodeIDFunction( |
"GetLocation", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, |
TreeCache* cache, ui::AXNode* node) { |
- gfx::Rect location = ComputeGlobalNodeBounds(cache, node); |
- location.Offset(cache->location_offset); |
- result.Set(RectToV8Object(isolate, location)); |
+ gfx::RectF local_bounds = ComputeLocalNodeBounds(cache, node); |
+ gfx::Rect global_bounds = |
+ ComputeGlobalNodeBounds(cache, node, local_bounds); |
+ global_bounds.Offset(cache->location_offset); |
+ result.Set(RectToV8Object(isolate, global_bounds)); |
}); |
RouteNodeIDFunction( |
"GetLineStartOffsets", |
@@ -560,40 +564,54 @@ AutomationInternalCustomBindings::AutomationInternalCustomBindings( |
"GetBoundsForRange", |
[](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, |
TreeCache* cache, ui::AXNode* node, int start, int end) { |
- gfx::Rect location = ComputeGlobalNodeBounds(cache, node); |
- location.Offset(cache->location_offset); |
- if (node->data().role == ui::AX_ROLE_INLINE_TEXT_BOX) { |
- std::string name = node->data().GetStringAttribute(ui::AX_ATTR_NAME); |
- std::vector<int> character_offsets = |
- node->data().GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS); |
- int len = |
- static_cast<int>(std::min(name.size(), character_offsets.size())); |
- if (start >= 0 && start <= end && end <= len) { |
- int start_offset = start > 0 ? character_offsets[start - 1] : 0; |
- int end_offset = end > 0 ? character_offsets[end - 1] : 0; |
- |
- switch (node->data().GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)) { |
- case ui::AX_TEXT_DIRECTION_LTR: |
- default: |
- location.set_x(location.x() + start_offset); |
- location.set_width(end_offset - start_offset); |
- break; |
- case ui::AX_TEXT_DIRECTION_RTL: |
- location.set_x(location.x() + location.width() - end_offset); |
- location.set_width(end_offset - start_offset); |
- break; |
- case ui::AX_TEXT_DIRECTION_TTB: |
- location.set_y(location.y() + start_offset); |
- location.set_height(end_offset - start_offset); |
- break; |
- case ui::AX_TEXT_DIRECTION_BTT: |
- location.set_y(location.y() + location.height() - end_offset); |
- location.set_height(end_offset - start_offset); |
- break; |
- } |
+ gfx::RectF local_bounds = ComputeLocalNodeBounds(cache, node); |
+ if (node->data().role != ui::AX_ROLE_INLINE_TEXT_BOX) { |
+ gfx::Rect global_bounds = |
+ ComputeGlobalNodeBounds(cache, node, local_bounds); |
+ global_bounds.Offset(cache->location_offset); |
+ result.Set(RectToV8Object(isolate, global_bounds)); |
+ } |
+ |
+ // Use character offsets to compute the local bounds of this subrange. |
+ std::string name = node->data().GetStringAttribute(ui::AX_ATTR_NAME); |
+ std::vector<int> character_offsets = |
+ node->data().GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS); |
+ int len = |
+ static_cast<int>(std::min(name.size(), character_offsets.size())); |
+ if (start >= 0 && start <= end && end <= len) { |
+ int start_offset = start > 0 ? character_offsets[start - 1] : 0; |
+ int end_offset = end > 0 ? character_offsets[end - 1] : 0; |
+ |
+ switch (node->data().GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)) { |
+ case ui::AX_TEXT_DIRECTION_LTR: |
+ default: |
+ local_bounds.set_x(local_bounds.x() + start_offset); |
+ local_bounds.set_width(end_offset - start_offset); |
+ break; |
+ case ui::AX_TEXT_DIRECTION_RTL: |
+ local_bounds.set_x(local_bounds.x() + local_bounds.width() - |
+ end_offset); |
+ local_bounds.set_width(end_offset - start_offset); |
+ break; |
+ case ui::AX_TEXT_DIRECTION_TTB: |
+ local_bounds.set_y(local_bounds.y() + start_offset); |
+ local_bounds.set_height(end_offset - start_offset); |
+ break; |
+ case ui::AX_TEXT_DIRECTION_BTT: |
+ local_bounds.set_y(local_bounds.y() + local_bounds.height() - |
+ end_offset); |
+ local_bounds.set_height(end_offset - start_offset); |
+ break; |
} |
} |
- result.Set(RectToV8Object(isolate, location)); |
+ |
+ // Convert from local to global coordinates second, after subsetting, |
+ // because the local to global conversion might involve matrix |
+ // transformations. |
+ gfx::Rect global_bounds = |
+ ComputeGlobalNodeBounds(cache, node, local_bounds); |
+ global_bounds.Offset(cache->location_offset); |
+ result.Set(RectToV8Object(isolate, global_bounds)); |
}); |
// Bindings that take a Tree ID and Node ID and string attribute name |