blob: a9102f2a1d5b4727ce827170191ba1b6285dd808 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_SCENIC_LIB_VIEW_TREE_SNAPSHOT_TYPES_H_
#define SRC_UI_SCENIC_LIB_VIEW_TREE_SNAPSHOT_TYPES_H_
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/fit/function.h>
#include <zircon/types.h>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "src/ui/lib/glm_workaround/glm_workaround.h"
namespace view_tree {
class Snapshot;
struct SubtreeHitTestResult;
using OnNewViewTree = fit::function<void(std::shared_ptr<const Snapshot>)>;
// Hit tester for a subtree.
// |start_node| defines the root of the hit testing tree walk. It can be any arbitrary node.
// |is_semantic_hit_test| defines if this is a semantic hit test, and this if it should follow the
// special accessibility hit testing rules or not.
using SubtreeHitTester = fit::function<SubtreeHitTestResult(
zx_koid_t start_node, glm::vec2 local_point, bool is_semantic_hit_test)>;
// Represents an element in a View hierarchy, used in both Snapshot and SubtreeSnapshot (both of
// which are defined below).
struct ViewNode {
zx_koid_t parent = ZX_KOID_INVALID;
std::unordered_set<zx_koid_t> children = {};
glm::mat4 local_from_world_transform = glm::mat4(1.f);
bool is_focusable = true;
// TODO(fxbug.dev/72832): This will cause a lot of copies. Investigate if it's a potential
// performance issue, in which case we might need to store them by shared_ptr or something.
fuchsia::ui::views::ViewRef view_ref;
bool operator==(const ViewNode& other) const {
return parent == other.parent &&
local_from_world_transform == other.local_from_world_transform &&
is_focusable == other.is_focusable && children == other.children;
}
};
// The results of a hit test from a single SubtreeHitTester.
struct SubtreeHitTestResult {
// Hit views in order of increasing distance.
// The hits are scoped to this subtree, and do not contain hits from continuations.
std::vector<zx_koid_t> hits;
// Views to continue hit testing from (in other subtrees), and the position in |hits| to insert
// the subtree hits in front of. If multiple continuations have the same index then they maintain
// their ordering in the multimap (insertion order).
// Assumption: An embedded subtree is rendered to a quad, i.e. all points in the subtree are in
// the same 2D dimensional plane in the parent tree; so all hits in a subtree are at the same
// distance from the parent tree's point of view.
std::multimap</*index*/ size_t, zx_koid_t> continuations;
};
// Output of ViewTreeSnapshotter.
// Snapshot of a ViewTree
class Snapshot {
public:
// The root of the tree. Must be present in |view_tree|.
zx_koid_t root = ZX_KOID_INVALID;
// The |view_tree| must be fully connected and only contain nodes reachable from |root|.
// Cannot contain ViewNodes with dangling children.
std::unordered_map<zx_koid_t, ViewNode> view_tree;
// Must be fully disjoint from |view_tree|.
std::unordered_set<zx_koid_t> unconnected_views;
// List of hit testers provided by all subtrees. When performing hit tests each hit tester is
// tried until a hit is found. This lets each subtree have customized hit testing.
// It's legal for one subtree to supply multiple hit testers.
// No one should be querying |hit_testers| directly. Only through view_tree::HitTest().
std::vector<SubtreeHitTester> hit_testers;
// Perform a hit test on |snapshot| starting from |start_node|.
// Returns a list of hit views in order of increasing distance.
// Recursively called on each tree boundary, so that the result is a full traversal of the tree.
// |start_node| defines the root of the hit testing tree walk. It can be any arbitrary node.
// |is_semantic| defines if this is a semantic hit test, and this if it should follow the special
// accessibility hit testing rules or not.
//
// Complexity is O(number of subtrees * O(hit_testers))
std::vector<zx_koid_t> HitTest(zx_koid_t start_node, glm::vec2 world_space_point,
bool is_semantic) const;
bool operator==(const Snapshot& other) const {
return root == other.root && view_tree == other.view_tree &&
unconnected_views == other.unconnected_views;
}
};
// Input to ViewTreeSnapshotter.
// Representation of a ViewTree subtree.
struct SubtreeSnapshot {
// The root of the tree. Must be present in |view_tree|.
zx_koid_t root = ZX_KOID_INVALID;
// The |view_tree| must be fully connected and only contain nodes reachable from |root|.
// May contain ViewNodes with dangling children.
std::unordered_map<zx_koid_t, ViewNode> view_tree;
// Must be fully disjoint from |view_tree|.
std::unordered_set<zx_koid_t> unconnected_views;
// Hit tester for this subtree.
SubtreeHitTester hit_tester;
// Map of leaf nodes in this subtree to their children in other subtrees. Keys must be dangling
// children in |view_tree| and values must be roots in other subtrees.
// Multimap so that one key can have multiple children.
std::multimap<zx_koid_t, zx_koid_t> tree_boundaries;
};
std::ostream& operator<<(std::ostream& os, const ViewNode& node);
std::ostream& operator<<(std::ostream& os, const Snapshot& snapshot);
} // namespace view_tree
#endif // SRC_UI_SCENIC_LIB_VIEW_TREE_SNAPSHOT_TYPES_H_