Commit 7a166102 authored by David Tseng's avatar David Tseng Committed by Commit Bot

Relax focus requirements in AutomationAXTreeWrapper::IsInFocusChain

Some web trees, in particular:
rootWebArea
  iframe
    ***rootWebArea
      iframe
        rootWebArea

*** will set its
tree->data().focus_id
but not either its
focus->GetStringAttribute(            ax::mojom::StringAttribute::kChildTreeId)
nor its
tree->data().focused_tree_id

The code assumed this more strict interpretation of the data, which appears to not work in this case. The topmost tree directly points to the innermost frame, skipping the frame in-between.

Fixed: 1038739
Test: manually on the snippet in the bug.
Change-Id: I5174cfcfabeb3bb4606d8636ab0f867d1310e52e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2080783Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: David Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#746120}
parent b15df0e2
...@@ -398,35 +398,37 @@ bool AutomationAXTreeWrapper::IsInFocusChain(int32_t node_id) { ...@@ -398,35 +398,37 @@ bool AutomationAXTreeWrapper::IsInFocusChain(int32_t node_id) {
if (IsDesktopTree()) if (IsDesktopTree())
return true; return true;
AutomationAXTreeWrapper* child_of_ancestor = this; AutomationAXTreeWrapper* descendant = this;
AutomationAXTreeWrapper* ancestor = nullptr; ui::AXTreeID descendant_tree_id = GetTreeID();
while ((ancestor = AutomationAXTreeWrapper* ancestor = descendant;
GetParentOfTreeId(child_of_ancestor->tree()->data().tree_id))) { bool found = true;
while ((ancestor = GetParentOfTreeId(ancestor->tree()->data().tree_id))) {
int32_t focus_id = ancestor->tree()->data().focus_id; int32_t focus_id = ancestor->tree()->data().focus_id;
ui::AXNode* focus = ancestor->tree()->GetFromId(focus_id); ui::AXNode* focus = ancestor->tree()->GetFromId(focus_id);
if (!focus) if (!focus)
return false; return false;
const ui::AXTreeID& child_tree_id = // Surprisingly, an ancestor frame can "skip" a child frame to point to a
child_of_ancestor->tree()->data().tree_id; // descendant granchild, so we have to scan upwards.
// Either the focused node points to the child tree, or the ancestor tree
// points to the child tree via the focused tree id. Exit early if both are
// not true.
if (ui::AXTreeID::FromString(focus->GetStringAttribute( if (ui::AXTreeID::FromString(focus->GetStringAttribute(
ax::mojom::StringAttribute::kChildTreeId)) != child_tree_id && ax::mojom::StringAttribute::kChildTreeId)) != descendant_tree_id &&
ancestor->tree()->data().focused_tree_id != child_tree_id) ancestor->tree()->data().focused_tree_id != descendant_tree_id) {
return false; found = false;
continue;
}
found = true;
if (ancestor->IsDesktopTree()) if (ancestor->IsDesktopTree())
return true; return true;
child_of_ancestor = ancestor; descendant_tree_id = ancestor->GetTreeID();
} }
// The only way we end up here is if the tree is detached from any desktop. // We can end up here if the tree is detached from any desktop. This can
// This can occur in tabs-only mode. // occur in tabs-only mode. This is also the codepath for frames with inner
return true; // focus, but which are not focused by ancestor frames.
return found;
} }
ui::AXTree::Selection AutomationAXTreeWrapper::GetUnignoredSelection() { ui::AXTree::Selection AutomationAXTreeWrapper::GetUnignoredSelection() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment