hitTest method
The nodes under a point, outermost first.
Answers "what is at these pixels", which is one question asked by two
callers: a panel turning a click into a selection, and an agent turning a
screenshot into a node id. Both get the chain rather than the innermost
hit, because the useful answer is usually a few levels out — the thing
under the cursor is a RenderParagraph and the thing you meant is the
button around it.
x and y are in the guest's own coordinates, the same space
InspectLayout.x reports and a capture is taken in.
Implementation
List<String> hitTest(double x, double y) {
var (:tree, :byRenderObject) = _build();
if (tree.root == null) return const [];
var root = rootOf()?.renderObject;
if (root is! RenderBox || !root.hasSize) return const [];
// In the demo root's own coordinates — the window's for an embedder
// guest, whose root is the window, and the picture's for a guest drawn
// inside its host. The boxes the tree reports are in the same space.
var result = BoxHitTestResult();
root.hitTest(result, position: Offset(x, y));
// Innermost first out of the framework, and reversed on the way out: a
// caller reading a chain wants it the way the tree reads.
var ids = <String>[];
for (var entry in result.path) {
var id = byRenderObject[entry.target];
// The hit path is render objects, and most of them belong to widgets no
// summary tree mentions. Those are not "no answer", they are the
// framework's internals, so they are skipped rather than reported.
if (id != null && !ids.contains(id)) ids.add(id);
}
return ids.reversed.toList();
}