freya_core/dom/
dom_adapter.rs1use freya_native_core::{
2 prelude::NodeType,
3 real_dom::NodeImmutable,
4 tree::TreeRef,
5 NodeId,
6};
7use rustc_hash::FxHashMap;
8use torin::prelude::*;
9
10use crate::{
11 dom::DioxusDOM,
12 states::LayoutState,
13};
14
15pub struct DioxusDOMAdapter<'a> {
17 pub rdom: &'a DioxusDOM,
18 pub scale_factor: f32,
19 cache: FxHashMap<NodeId, bool>,
20}
21
22impl<'a> DioxusDOMAdapter<'a> {
23 pub fn new(rdom: &'a DioxusDOM, scale_factor: f32) -> Self {
24 Self {
25 rdom,
26 scale_factor,
27 cache: FxHashMap::default(),
28 }
29 }
30}
31
32impl DOMAdapter<NodeId> for DioxusDOMAdapter<'_> {
33 fn get_node(&self, node_id: &NodeId) -> Option<Node> {
34 let node = self.rdom.get(*node_id)?;
35 let contains_text = node
36 .node_type()
37 .tag()
38 .map(|t| t.contains_text())
39 .unwrap_or_default();
40
41 let mut layout = node.get::<LayoutState>()?.clone();
42
43 if *node_id == self.rdom.root_id() {
45 layout.width = Size::Percentage(Length::new(100.0));
46 layout.height = Size::Percentage(Length::new(100.0));
47 }
48
49 let mut node = Node {
50 width: layout.width,
51 height: layout.height,
52 minimum_width: layout.minimum_width,
53 minimum_height: layout.minimum_height,
54 maximum_width: layout.maximum_width,
55 maximum_height: layout.maximum_height,
56 visible_width: layout.visible_width,
57 visible_height: layout.visible_height,
58 direction: layout.direction,
59 padding: layout.padding,
60 margin: layout.margin,
61 main_alignment: layout.main_alignment,
62 cross_alignment: layout.cross_alignment,
63 offset_x: layout.offset_x,
64 offset_y: layout.offset_y,
65 has_layout_references: layout.node_ref.is_some(),
66 position: layout.position,
67 content: layout.content,
68 contains_text,
69 spacing: layout.spacing,
70 };
71
72 node.scale_if_needed(self.scale_factor);
73
74 Some(node)
75 }
76
77 fn height(&self, node_id: &NodeId) -> Option<u16> {
78 self.rdom.tree_ref().height(*node_id)
79 }
80
81 fn parent_of(&self, node_id: &NodeId) -> Option<NodeId> {
82 self.rdom.tree_ref().parent_id(*node_id)
83 }
84
85 fn children_of(&mut self, node_id: &NodeId) -> Vec<NodeId> {
86 let mut children = self.rdom.tree_ref().children_ids(*node_id);
87 children.retain(|id| is_node_valid(self.rdom, &mut self.cache, id));
88 children
89 }
90
91 fn is_node_valid(&mut self, node_id: &NodeId) -> bool {
92 is_node_valid(self.rdom, &mut self.cache, node_id)
93 }
94
95 fn root_id(&self) -> NodeId {
96 self.rdom.root_id()
97 }
98}
99
100fn is_node_valid(rdom: &DioxusDOM, cache: &mut FxHashMap<NodeId, bool>, node_id: &NodeId) -> bool {
102 if let Some(is_valid) = cache.get(node_id) {
104 return *is_valid;
105 }
106
107 let node = rdom.get(*node_id);
108
109 let is_valid = 'validation: {
110 if let Some(node) = node {
111 let is_placeholder = matches!(*node.node_type(), NodeType::Placeholder);
112
113 if is_placeholder {
115 break 'validation false;
116 }
117
118 let tree = rdom.tree_ref();
122 let mut current = *node_id;
123 loop {
124 let height = tree.height(current);
125 if let Some(height) = height {
126 if height == 0 {
127 break;
128 }
129 }
130
131 let parent_current = tree.parent_id(current);
132 if let Some(parent_current) = parent_current {
133 current = parent_current;
134 }
135 }
136
137 current == rdom.root_id()
138 } else {
139 false
140 }
141 };
142
143 cache.insert(*node_id, is_valid);
145
146 is_valid
147}