| Index: content/browser/accessibility/browser_accessibility_manager.cc
|
| diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
|
| index b3d3668035e6477cb81ac81b34f3abb576c2f3bc..f5f8808b0f952d174dcba7053edcb2c4ec7c7cf0 100644
|
| --- a/content/browser/accessibility/browser_accessibility_manager.cc
|
| +++ b/content/browser/accessibility/browser_accessibility_manager.cc
|
| @@ -398,6 +398,9 @@ void BrowserAccessibilityManager::OnAccessibilityEvents(
|
| // Fire the native event.
|
| BrowserAccessibility* event_target = GetFromAXNode(node);
|
| if (event_target) {
|
| + if (event_type == ui::AX_EVENT_HOVER)
|
| + GetRootManager()->CacheHitTestResult(event_target);
|
| +
|
| NotifyAccessibilityEvent(
|
| BrowserAccessibilityEvent::FromBlink,
|
| event_type,
|
| @@ -1095,4 +1098,56 @@ BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
|
| return update;
|
| }
|
|
|
| +BrowserAccessibility* BrowserAccessibilityManager::CachingAsyncHitTest(
|
| + const gfx::Point& screen_point) {
|
| + BrowserAccessibilityManager* root_manager = GetRootManager();
|
| + if (root_manager && root_manager != this)
|
| + return root_manager->CachingAsyncHitTest(screen_point);
|
| +
|
| + if (delegate()) {
|
| + // This triggers an asynchronous request to compute the true object that's
|
| + // under |screen_point|.
|
| + gfx::Point local_point = screen_point - GetViewBounds().OffsetFromOrigin();
|
| + delegate()->AccessibilityHitTest(local_point);
|
| +
|
| + // Unfortunately we still have to return an answer synchronously because
|
| + // the APIs were designed that way. The best case scenario is that the
|
| + // screen point is within the bounds of the last result we got from a
|
| + // call to AccessibilityHitTest - in that case, we can return that object!
|
| + if (last_hover_bounds_.Contains(screen_point)) {
|
| + BrowserAccessibilityManager* manager =
|
| + BrowserAccessibilityManager::FromID(last_hover_ax_tree_id_);
|
| + if (manager) {
|
| + BrowserAccessibility* node = manager->GetFromID(last_hover_node_id_);
|
| + if (node)
|
| + return node;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // If that test failed we have to fall back on searching the accessibility
|
| + // tree locally for the best bounding box match. This is generally right
|
| + // for simple pages but wrong in cases of z-index, overflow, and other
|
| + // more complicated layouts. The hope is that if the user is moving the
|
| + // mouse, this fallback will only be used transiently, and the asynchronous
|
| + // result will be used for the next call.
|
| + return GetRoot()->ApproximateHitTest(screen_point);
|
| +}
|
| +
|
| +void BrowserAccessibilityManager::CacheHitTestResult(
|
| + BrowserAccessibility* hit_test_result) {
|
| + // Walk up to the highest ancestor that's a leaf node; we don't want to
|
| + // return a node that's hidden from the tree.
|
| + BrowserAccessibility* parent = hit_test_result->GetParent();
|
| + while (parent) {
|
| + if (parent->PlatformChildCount() == 0)
|
| + hit_test_result = parent;
|
| + parent = parent->GetParent();
|
| + }
|
| +
|
| + last_hover_ax_tree_id_ = hit_test_result->manager()->ax_tree_id();
|
| + last_hover_node_id_ = hit_test_result->GetId();
|
| + last_hover_bounds_ = hit_test_result->GetScreenBoundsRect();
|
| +}
|
| +
|
| } // namespace content
|
|
|