Fix AXTree::RelativeToTreeBounds for nodes with position but zero size.

AXTree::RelativeToTreeBounds has some logic that tries to avoid
returning an empty bounding rect. If the current node has zero size,
it tries to compute the size either from the union of that node's
children, or if that fails, from the bounds of that node's nearest
ancestor with a size.

There was a subtle bug in this logic if a node has a position but
zero size. In a case like this:

root (0,0) size (800x600)
  window (100,100) size (400,300)
    button (120, 120) size (0,0)

The algorithm was returning a position of (220,220) incorrectly.

The fundamental problem was trying to fix a bounding box with zero size
at the same time as it was trying to walk up the ancestry to turn relative
positions to absolute positions.

The new algorithm just does it in two passes: first convert relative to
absolute, then if the bounds has no size, find the nearest ancestor with
a size and expand the current node as much as possible within that
ancestor's bounds.

Bug: 1005977
Change-Id: Ib4963fa98dabf958be49d3e13d6d932280b01b1b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1815257
Commit-Queue: Dominic Mazzoni <[email protected]>
Reviewed-by: Anastasia Helfinstein <[email protected]>
Cr-Commit-Position: refs/heads/master@{#700398}
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
index a706758..d056df49a 100644
--- a/ui/accessibility/ax_tree.h
+++ b/ui/accessibility/ax_tree.h
@@ -275,6 +275,14 @@
                             std::vector<AXNode*>* new_children,
                             AXTreeUpdateState* update_state);
 
+  // Internal implementation of RelativeToTreeBounds. It calls itself
+  // recursively but ensures that it can only do so exactly once!
+  gfx::RectF RelativeToTreeBoundsInternal(const AXNode* node,
+                                          gfx::RectF node_bounds,
+                                          bool* offscreen,
+                                          bool clip_bounds,
+                                          bool allow_recursion) const;
+
   base::ObserverList<AXTreeObserver> observers_;
   AXNode* root_ = nullptr;
   std::unordered_map<int32_t, AXNode*> id_map_;