Skip to content

Commit b182e65

Browse files
authored
Internal: Rethink mutations writer (#731)
* internal: Simplify the `VirtualDOM` polling * internal: Rethink the MutationsWriter impl of freya * clippy
1 parent ff66f74 commit b182e65

File tree

11 files changed

+148
-81
lines changed

11 files changed

+148
-81
lines changed

crates/core/src/dom/dom_adapter.rs

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,56 @@ use torin::prelude::*;
1010

1111
use crate::dom::DioxusDOM;
1212

13+
pub enum DioxusDOMAdapterCache<'a> {
14+
Controlled(&'a mut FxHashMap<NodeId, bool>),
15+
Provided(FxHashMap<NodeId, bool>),
16+
}
17+
18+
impl DioxusDOMAdapterCache<'_> {
19+
fn is_valid(&self, node_id: NodeId) -> Option<bool> {
20+
let map = match self {
21+
Self::Controlled(map) => map,
22+
Self::Provided(map) => map,
23+
};
24+
25+
map.get(&node_id).copied()
26+
}
27+
28+
fn insert(&mut self, node_id: NodeId, is_valid: bool) {
29+
let map = match self {
30+
Self::Controlled(map) => map,
31+
Self::Provided(map) => map,
32+
};
33+
34+
map.insert(node_id, is_valid);
35+
}
36+
}
37+
1338
/// RealDOM adapter for Torin.
1439
pub struct DioxusDOMAdapter<'a> {
1540
pub rdom: &'a DioxusDOM,
1641
pub scale_factor: f32,
17-
valid_nodes_cache: Option<FxHashMap<NodeId, bool>>,
42+
cache: DioxusDOMAdapterCache<'a>,
1843
}
1944

2045
impl<'a> DioxusDOMAdapter<'a> {
21-
pub fn new_with_cache(rdom: &'a DioxusDOM, scale_factor: f32) -> Self {
46+
pub fn new(rdom: &'a DioxusDOM, scale_factor: f32) -> Self {
2247
Self {
2348
rdom,
2449
scale_factor,
25-
valid_nodes_cache: Some(FxHashMap::default()),
50+
cache: DioxusDOMAdapterCache::Provided(FxHashMap::default()),
51+
}
52+
}
53+
54+
pub fn new_with_cache(
55+
rdom: &'a mut DioxusDOM,
56+
scale_factor: f32,
57+
cache: DioxusDOMAdapterCache<'a>,
58+
) -> Self {
59+
Self {
60+
rdom,
61+
scale_factor,
62+
cache,
2663
}
2764
}
2865
}
@@ -79,12 +116,12 @@ impl DOMAdapter<NodeId> for DioxusDOMAdapter<'_> {
79116

80117
fn children_of(&mut self, node_id: &NodeId) -> Vec<NodeId> {
81118
let mut children = self.rdom.tree_ref().children_ids(*node_id);
82-
children.retain(|id| is_node_valid(self.rdom, &mut self.valid_nodes_cache, id));
119+
children.retain(|id| is_node_valid(self.rdom, &mut self.cache, id));
83120
children
84121
}
85122

86123
fn is_node_valid(&mut self, node_id: &NodeId) -> bool {
87-
is_node_valid(self.rdom, &mut self.valid_nodes_cache, node_id)
124+
is_node_valid(self.rdom, &mut self.cache, node_id)
88125
}
89126

90127
fn root_id(&self) -> NodeId {
@@ -93,16 +130,10 @@ impl DOMAdapter<NodeId> for DioxusDOMAdapter<'_> {
93130
}
94131

95132
/// Check is the given Node is valid or not, this means not being a placeholder or an unconnected Node.
96-
fn is_node_valid(
97-
rdom: &DioxusDOM,
98-
valid_nodes_cache: &mut Option<FxHashMap<NodeId, bool>>,
99-
node_id: &NodeId,
100-
) -> bool {
133+
fn is_node_valid(rdom: &DioxusDOM, cache: &mut DioxusDOMAdapterCache, node_id: &NodeId) -> bool {
101134
// Check if Node was valid from cache
102-
if let Some(valid_nodes_cache) = valid_nodes_cache {
103-
if let Some(is_valid) = valid_nodes_cache.get(node_id) {
104-
return *is_valid;
105-
}
135+
if let Some(is_valid) = cache.is_valid(*node_id) {
136+
return is_valid;
106137
}
107138

108139
let node = rdom.get(*node_id);
@@ -142,9 +173,7 @@ fn is_node_valid(
142173
};
143174

144175
// Save the validation result in the cache
145-
if let Some(valid_nodes_cache) = valid_nodes_cache {
146-
valid_nodes_cache.insert(*node_id, is_valid);
147-
}
176+
cache.insert(*node_id, is_valid);
148177

149178
is_valid
150179
}

crates/core/src/dom/doms.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use freya_node_state::{
3434
TransformState,
3535
ViewportState,
3636
};
37+
use rustc_hash::FxHashMap;
3738
use torin::prelude::*;
3839
use tracing::info;
3940

@@ -162,12 +163,12 @@ impl FreyaDOM {
162163
pub fn init_dom(&mut self, vdom: &mut VirtualDom, scale_factor: f32) {
163164
// Build the RealDOM
164165
vdom.rebuild(&mut MutationsWriter {
165-
native_writer: self
166-
.dioxus_integration_state
167-
.create_mutation_writer(&mut self.rdom),
166+
dioxus_integration_state: &mut self.dioxus_integration_state,
168167
layout: &mut self.torin.lock().unwrap(),
169168
layers: &self.layers,
170169
paragraphs: &self.paragraphs,
170+
rdom: &mut self.rdom,
171+
dioxus_dom_adapter_cache: &mut FxHashMap::default(),
171172
scale_factor,
172173
});
173174

@@ -183,12 +184,12 @@ impl FreyaDOM {
183184
pub fn render_mutations(&mut self, vdom: &mut VirtualDom, scale_factor: f32) -> (bool, bool) {
184185
// Update the RealDOM
185186
vdom.render_immediate(&mut MutationsWriter {
186-
native_writer: self
187-
.dioxus_integration_state
188-
.create_mutation_writer(&mut self.rdom),
187+
dioxus_integration_state: &mut self.dioxus_integration_state,
189188
layout: &mut self.torin.lock().unwrap(),
190189
layers: &self.layers,
191190
paragraphs: &self.paragraphs,
191+
rdom: &mut self.rdom,
192+
dioxus_dom_adapter_cache: &mut FxHashMap::default(),
192193
scale_factor,
193194
});
194195

@@ -229,7 +230,7 @@ impl FreyaDOM {
229230
}
230231

231232
/// Measure all the paragraphs registered under the given TextId
232-
pub fn measure_paragraphs(&self, text_measurement: TextGroupMeasurement, scale_factor: f32) {
233+
pub fn measure_paragraphs(&self, text_measurement: TextGroupMeasurement, scale_factor: f64) {
233234
let paragraphs = self.paragraphs.paragraphs();
234235
let group = paragraphs.get(&text_measurement.text_id);
235236
let layout = self.layout();

crates/core/src/dom/mutations_writer.rs

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,62 @@ use freya_common::{
77
ParagraphElements,
88
};
99
use freya_native_core::{
10-
dioxus::DioxusNativeCoreMutationWriter,
11-
prelude::NodeImmutable,
10+
prelude::{
11+
DioxusState,
12+
NodeImmutable,
13+
},
1214
tree::TreeRef,
1315
NodeId,
1416
};
1517
use freya_node_state::{
1618
CursorState,
17-
CustomAttributeValues,
1819
LayerState,
1920
};
21+
use rustc_hash::FxHashMap;
2022
use torin::torin::Torin;
2123

22-
use crate::prelude::DioxusDOMAdapter;
24+
use crate::prelude::{
25+
DioxusDOM,
26+
DioxusDOMAdapter,
27+
DioxusDOMAdapterCache,
28+
};
29+
30+
macro_rules! create_mutation_writer {
31+
($self:ident) => {
32+
$self
33+
.dioxus_integration_state
34+
.create_mutation_writer(&mut $self.rdom)
35+
};
36+
}
2337

2438
pub struct MutationsWriter<'a> {
25-
pub native_writer: DioxusNativeCoreMutationWriter<'a, CustomAttributeValues>,
39+
pub dioxus_integration_state: &'a mut DioxusState,
2640
pub layout: &'a mut Torin<NodeId>,
2741
pub layers: &'a Layers,
2842
pub paragraphs: &'a ParagraphElements,
43+
pub dioxus_dom_adapter_cache: &'a mut FxHashMap<NodeId, bool>,
2944
pub scale_factor: f32,
45+
pub rdom: &'a mut DioxusDOM,
3046
}
3147

3248
impl<'a> MutationsWriter<'a> {
3349
pub fn remove(&mut self, id: ElementId) {
34-
let node_id = self.native_writer.state.element_to_node_id(id);
35-
let mut dom_adapter =
36-
DioxusDOMAdapter::new_with_cache(self.native_writer.rdom, self.scale_factor);
50+
let node_id = self.dioxus_integration_state.element_to_node_id(id);
51+
52+
let mut dom_adapter = DioxusDOMAdapter::new_with_cache(
53+
self.rdom,
54+
self.scale_factor,
55+
DioxusDOMAdapterCache::Controlled(self.dioxus_dom_adapter_cache),
56+
);
3757

3858
// Remove from layout
3959
self.layout.remove(node_id, &mut dom_adapter, true);
4060

4161
// Remove from layers and paragraph elements
4262
let mut stack = vec![node_id];
43-
let tree = self.native_writer.rdom.tree_ref();
63+
let tree = self.rdom.tree_ref();
4464
while let Some(node_id) = stack.pop() {
45-
if let Some(node) = self.native_writer.rdom.get(node_id) {
65+
if let Some(node) = self.rdom.get(node_id) {
4666
if !node.node_type().is_visible_element() {
4767
continue;
4868
}
@@ -75,51 +95,63 @@ impl<'a> MutationsWriter<'a> {
7595

7696
impl<'a> WriteMutations for MutationsWriter<'a> {
7797
fn register_template(&mut self, template: dioxus_core::prelude::Template) {
78-
self.native_writer.register_template(template);
98+
let mut native_writer = create_mutation_writer!(self);
99+
native_writer.register_template(template);
79100
}
80101

81102
fn append_children(&mut self, id: dioxus_core::ElementId, m: usize) {
82-
self.native_writer.append_children(id, m);
103+
let mut native_writer = create_mutation_writer!(self);
104+
native_writer.append_children(id, m);
83105
}
84106

85107
fn assign_node_id(&mut self, path: &'static [u8], id: dioxus_core::ElementId) {
86-
self.native_writer.assign_node_id(path, id);
108+
let mut native_writer = create_mutation_writer!(self);
109+
native_writer.assign_node_id(path, id);
87110
}
88111

89112
fn create_placeholder(&mut self, id: dioxus_core::ElementId) {
90-
self.native_writer.create_placeholder(id);
113+
let mut native_writer = create_mutation_writer!(self);
114+
native_writer.create_placeholder(id);
91115
}
92116

93117
fn create_text_node(&mut self, value: &str, id: dioxus_core::ElementId) {
94-
self.native_writer.create_text_node(value, id);
118+
let mut native_writer = create_mutation_writer!(self);
119+
native_writer.create_text_node(value, id);
95120
}
96121

97122
fn hydrate_text_node(&mut self, path: &'static [u8], value: &str, id: dioxus_core::ElementId) {
98-
self.native_writer.hydrate_text_node(path, value, id);
123+
let mut native_writer = create_mutation_writer!(self);
124+
native_writer.hydrate_text_node(path, value, id);
99125
}
100126

101127
fn load_template(&mut self, name: &'static str, index: usize, id: dioxus_core::ElementId) {
102-
self.native_writer.load_template(name, index, id);
128+
let mut native_writer = create_mutation_writer!(self);
129+
native_writer.load_template(name, index, id);
103130
}
104131

105132
fn replace_node_with(&mut self, id: dioxus_core::ElementId, m: usize) {
106133
if m > 0 {
107134
self.remove(id);
108135
}
109136

110-
self.native_writer.replace_node_with(id, m);
137+
let mut native_writer = create_mutation_writer!(self);
138+
139+
native_writer.replace_node_with(id, m);
111140
}
112141

113142
fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
114-
self.native_writer.replace_placeholder_with_nodes(path, m);
143+
let mut native_writer = create_mutation_writer!(self);
144+
native_writer.replace_placeholder_with_nodes(path, m);
115145
}
116146

117147
fn insert_nodes_after(&mut self, id: dioxus_core::ElementId, m: usize) {
118-
self.native_writer.insert_nodes_after(id, m);
148+
let mut native_writer = create_mutation_writer!(self);
149+
native_writer.insert_nodes_after(id, m);
119150
}
120151

121152
fn insert_nodes_before(&mut self, id: dioxus_core::ElementId, m: usize) {
122-
self.native_writer.insert_nodes_before(id, m);
153+
let mut native_writer = create_mutation_writer!(self);
154+
native_writer.insert_nodes_before(id, m);
123155
}
124156

125157
fn set_attribute(
@@ -129,29 +161,33 @@ impl<'a> WriteMutations for MutationsWriter<'a> {
129161
value: &dioxus_core::AttributeValue,
130162
id: dioxus_core::ElementId,
131163
) {
132-
self.native_writer.set_attribute(name, ns, value, id);
164+
let mut native_writer = create_mutation_writer!(self);
165+
native_writer.set_attribute(name, ns, value, id);
133166
}
134167

135168
fn set_node_text(&mut self, value: &str, id: dioxus_core::ElementId) {
136-
self.layout
137-
.invalidate(self.native_writer.state.element_to_node_id(id));
138-
self.native_writer.set_node_text(value, id);
169+
let mut native_writer = create_mutation_writer!(self);
170+
native_writer.set_node_text(value, id);
139171
}
140172

141173
fn create_event_listener(&mut self, name: &'static str, id: dioxus_core::ElementId) {
142-
self.native_writer.create_event_listener(name, id);
174+
let mut native_writer = create_mutation_writer!(self);
175+
native_writer.create_event_listener(name, id);
143176
}
144177

145178
fn remove_event_listener(&mut self, name: &'static str, id: dioxus_core::ElementId) {
146-
self.native_writer.remove_event_listener(name, id);
179+
let mut native_writer = create_mutation_writer!(self);
180+
native_writer.remove_event_listener(name, id);
147181
}
148182

149183
fn remove_node(&mut self, id: dioxus_core::ElementId) {
150184
self.remove(id);
151-
self.native_writer.remove_node(id);
185+
let mut native_writer = create_mutation_writer!(self);
186+
native_writer.remove_node(id);
152187
}
153188

154189
fn push_root(&mut self, id: dioxus_core::ElementId) {
155-
self.native_writer.push_root(id);
190+
let mut native_writer = create_mutation_writer!(self);
191+
native_writer.push_root(id);
156192
}
157193
}

crates/core/src/layout.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ pub fn process_layout(
1111
fdom: &FreyaDOM,
1212
area: Area,
1313
font_collection: &mut FontCollection,
14-
scale_factor: f32,
14+
scale_factor: f64,
1515
default_fonts: &[String],
1616
) {
1717
{
1818
let rdom = fdom.rdom();
19-
let mut dom_adapter = DioxusDOMAdapter::new_with_cache(rdom, scale_factor);
20-
let skia_measurer = SkiaMeasurer::new(rdom, font_collection, default_fonts, scale_factor);
19+
let mut dom_adapter = DioxusDOMAdapter::new(rdom, scale_factor as f32);
20+
let skia_measurer =
21+
SkiaMeasurer::new(rdom, font_collection, default_fonts, scale_factor as f32);
2122

2223
// Finds the best Node from where to start measuring
2324
fdom.layout().find_best_root(&mut dom_adapter);

crates/core/src/platform_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub struct NativePlatformState {
99
pub preferred_theme: PreferredTheme,
1010
pub navigation_mode: NavigationMode,
1111
pub information: PlatformInformation,
12-
pub scale_factor: f32,
12+
pub scale_factor: f64,
1313
}
1414

1515
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]

0 commit comments

Comments
 (0)