euv_core/renderer/render/
impl.rs1use crate::*;
2
3impl Renderer {
5 pub fn new(root: Element) -> Self {
15 Renderer {
16 root,
17 current_tree: None,
18 }
19 }
20
21 pub fn render(&mut self, vnode: VirtualNode) {
27 let new_unwrapped: VirtualNode = self.unwrap_component(&vnode);
28 if let Some(old_vnode) = self.try_get_current_tree() {
29 let old_unwrapped: VirtualNode = self.unwrap_component(old_vnode);
30 self.patch_root(&old_unwrapped, &new_unwrapped);
31 } else {
32 let dom_node: Node = self.create_dom_node(&new_unwrapped);
33 while let Some(child) = self.get_root().first_child() {
34 self.get_root().remove_child(&child).unwrap();
35 }
36 self.get_root().append_child(&dom_node).unwrap();
37 }
38 self.set_current_tree(Some(vnode));
39 }
40
41 fn patch_root(&mut self, old_node: &VirtualNode, new_node: &VirtualNode) {
43 let dom_child: Option<Node> = self.get_root().first_child();
44 let is_element: bool = if let Some(ref dom_child) = dom_child {
45 dom_child.dyn_ref::<Element>().is_some()
46 } else {
47 false
48 };
49 if is_element {
50 let element: Element = dom_child.unwrap().dyn_into::<Element>().unwrap();
51 self.patch_node(old_node, new_node, &element);
52 } else if let Some(dom_child) = dom_child {
53 let new_dom: Node = self.create_dom_node(new_node);
54 self.get_root().replace_child(&new_dom, &dom_child).unwrap();
55 } else {
56 let new_dom: Node = self.create_dom_node(new_node);
57 self.get_root().append_child(&new_dom).unwrap();
58 }
59 }
60
61 fn patch_node(
63 &mut self,
64 old_node: &VirtualNode,
65 new_node: &VirtualNode,
66 dom_element: &Element,
67 ) {
68 match (old_node, new_node) {
69 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => {
70 if old_text.get_content() != new_text.get_content() {
71 dom_element.set_text_content(Some(new_text.get_content()));
72 }
73 }
74 (
75 VirtualNode::Element {
76 tag: old_tag,
77 attributes: old_attrs,
78 children: old_children,
79 key: _old_key,
80 },
81 VirtualNode::Element {
82 tag: new_tag,
83 attributes: new_attrs,
84 children: new_children,
85 key: _new_key,
86 },
87 ) => {
88 if !Self::tags_equal(old_tag, new_tag) {
89 let new_dom: Node = self.create_dom_node(new_node);
90 if let Some(parent) = dom_element.parent_node() {
91 parent.replace_child(&new_dom, dom_element).unwrap();
92 }
93 return;
94 }
95 self.patch_attributes(dom_element, old_attrs, new_attrs);
96 self.patch_children(dom_element, old_children, new_children);
97 }
98 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
99 self.patch_children(dom_element, old_children, new_children);
100 }
101 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => {}
102 _ => {
103 let new_dom: Node = self.create_dom_node(new_node);
104 if let Some(parent) = dom_element.parent_node() {
105 parent.replace_child(&new_dom, dom_element).unwrap();
106 }
107 }
108 }
109 }
110
111 fn patch_attributes(
113 &mut self,
114 element: &Element,
115 old_attrs: &[AttributeEntry],
116 new_attrs: &[AttributeEntry],
117 ) {
118 for old_attr in old_attrs {
119 let removed: bool = !new_attrs
120 .iter()
121 .any(|new_attr| new_attr.get_name() == old_attr.get_name());
122 if removed {
123 remove_dom_attribute_or_property(element, old_attr.get_name());
124 }
125 }
126 for new_attr in new_attrs {
127 let old_value: Option<&AttributeValue> = old_attrs
128 .iter()
129 .find(|old_attr| old_attr.get_name() == new_attr.get_name())
130 .map(AttributeEntry::get_value);
131 let should_set: bool = match old_value {
132 Some(old_val) => !Self::attribute_values_equal(old_val, new_attr.get_value()),
133 None => true,
134 };
135 if should_set {
136 match new_attr.get_value() {
137 AttributeValue::Text(value) => {
138 if value.is_empty() {
139 remove_dom_attribute_or_property(element, new_attr.get_name());
140 } else {
141 set_dom_attribute_or_property(element, new_attr.get_name(), value);
142 }
143 }
144 AttributeValue::Signal(signal) => {
145 let value: String = signal.get();
146 if value.is_empty() && !is_boolean_property(new_attr.get_name()) {
147 remove_dom_attribute_or_property(element, new_attr.get_name());
148 } else {
149 set_dom_attribute_or_property(element, new_attr.get_name(), &value);
150 }
151 }
152 AttributeValue::Event(handler) => {
153 self.attach_event_listener(element, handler);
154 }
155 AttributeValue::Dynamic(_) => {}
156 AttributeValue::Css(css_class) => {
157 css_class.inject_style();
158 set_dom_attribute_or_property(
159 element,
160 new_attr.get_name(),
161 css_class.get_name(),
162 );
163 }
164 }
165 }
166 }
167 }
168
169 fn tags_equal(old_tag: &Tag, new_tag: &Tag) -> bool {
171 match (old_tag, new_tag) {
172 (Tag::Element(old_name), Tag::Element(new_name)) => old_name == new_name,
173 (Tag::Component(old_name), Tag::Component(new_name)) => old_name == new_name,
174 _ => false,
175 }
176 }
177
178 fn attribute_values_equal(old_val: &AttributeValue, new_val: &AttributeValue) -> bool {
192 match (old_val, new_val) {
193 (AttributeValue::Text(old_text), AttributeValue::Text(new_text)) => {
194 old_text == new_text
195 }
196 (AttributeValue::Signal(old_signal), AttributeValue::Signal(new_signal)) => {
197 old_signal.get() == new_signal.get()
198 }
199 (AttributeValue::Event(_), AttributeValue::Event(_)) => false,
200 (AttributeValue::Dynamic(old_dyn), AttributeValue::Dynamic(new_dyn)) => {
201 old_dyn == new_dyn
202 }
203 (AttributeValue::Css(old_css), AttributeValue::Css(new_css)) => old_css == new_css,
204 _ => false,
205 }
206 }
207
208 fn get_child_node(parent: &Element, index: u32) -> Option<Node> {
210 let mut current: Option<Node> = parent.first_child();
211 let mut current_index: u32 = 0;
212 while let Some(node) = current {
213 if current_index == index {
214 return Some(node);
215 }
216 current = node.next_sibling();
217 current_index += 1;
218 }
219 None
220 }
221
222 fn patch_children(
224 &mut self,
225 parent: &Element,
226 old_children: &[VirtualNode],
227 new_children: &[VirtualNode],
228 ) {
229 let old_len: usize = old_children.len();
230 let new_len: usize = new_children.len();
231 let common_len: usize = old_len.min(new_len);
232 for index in 0..common_len {
233 let old_child: &VirtualNode = &old_children[index];
234 let new_child: &VirtualNode = &new_children[index];
235 if let Some(dom_child) = Self::get_child_node(parent, index as u32) {
236 if let Some(element) = dom_child.dyn_ref::<Element>() {
237 self.patch_node(old_child, new_child, element);
238 } else if let (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) =
239 (old_child, new_child)
240 {
241 if old_text.get_content() != new_text.get_content() {
242 dom_child.set_text_content(Some(new_text.get_content()));
243 }
244 } else {
245 let new_dom: Node = self.create_dom_node(new_child);
246 if let Some(parent_node) = dom_child.parent_node() {
247 let _ = parent_node.replace_child(&new_dom, &dom_child);
248 }
249 }
250 }
251 }
252 if new_len > old_len {
253 for new_child in new_children.iter().skip(common_len) {
254 let new_dom: Node = self.create_dom_node(new_child);
255 parent.append_child(&new_dom).unwrap();
256 }
257 } else if old_len > new_len {
258 for _ in common_len..old_len {
259 if let Some(last_child) = parent.last_child() {
260 parent.remove_child(&last_child).unwrap();
261 }
262 }
263 }
264 }
265
266 fn create_dom_node(&mut self, node: &VirtualNode) -> Node {
268 let document: Document = window().unwrap().document().unwrap();
269 self.create_dom_node_with_document(node, &document)
270 }
271
272 fn create_dom_node_with_document(&mut self, node: &VirtualNode, document: &Document) -> Node {
274 match node {
275 VirtualNode::Element {
276 tag,
277 attributes,
278 children,
279 ..
280 } => {
281 let element: Element = match tag {
282 Tag::Element(name) => document.create_element(name).unwrap(),
283 Tag::Component(_) => {
284 let unwrapped: VirtualNode = self.unwrap_component(node);
285 return self.create_dom_node_with_document(&unwrapped, document);
286 }
287 };
288 for attr in attributes {
289 match attr.get_value() {
290 AttributeValue::Text(value) => {
291 if !value.is_empty() || is_boolean_property(attr.get_name()) {
292 set_dom_attribute_or_property(&element, attr.get_name(), value);
293 }
294 }
295 AttributeValue::Signal(signal) => {
296 let initial_value: String = signal.get();
297 if !initial_value.is_empty() || is_boolean_property(attr.get_name()) {
298 set_dom_attribute_or_property(
299 &element,
300 attr.get_name(),
301 &initial_value,
302 );
303 }
304 let attr_name: String = attr.get_name().clone();
305 let element_clone: Element = element.clone();
306 let signal_for_sub: Signal<String> = *signal;
307 let signal_inner: Signal<String> = signal_for_sub;
308 signal_for_sub.replace_subscribe(move || {
309 let new_value: String = signal_inner.get();
310 if new_value.is_empty() && !is_boolean_property(&attr_name) {
311 remove_dom_attribute_or_property(&element_clone, &attr_name);
312 } else {
313 set_dom_attribute_or_property(
314 &element_clone,
315 &attr_name,
316 &new_value,
317 );
318 }
319 });
320 }
321 AttributeValue::Event(handler) => {
322 self.attach_event_listener(&element, handler);
323 }
324 AttributeValue::Dynamic(_) => {}
325 AttributeValue::Css(css_class) => {
326 css_class.inject_style();
327 set_dom_attribute_or_property(
328 &element,
329 attr.get_name(),
330 css_class.get_name(),
331 );
332 }
333 }
334 }
335 for child in children {
336 let child_node: Node = self.create_dom_node_with_document(child, document);
337 element.append_child(&child_node).unwrap();
338 }
339 element.into()
340 }
341 VirtualNode::Text(text_node) => {
342 let text: Text = document.create_text_node(text_node.get_content());
343 if let Some(signal) = text_node.try_get_signal() {
344 let text_clone: Text = text.clone();
345 let signal_clone: Signal<String> = *signal;
346 signal_clone.replace_subscribe({
347 let signal_inner: Signal<String> = signal_clone;
348 move || {
349 let new_value: String = signal_inner.get();
350 text_clone.set_text_content(Some(&new_value));
351 }
352 });
353 }
354 text.into()
355 }
356 VirtualNode::Fragment(children) => {
357 let fragment: Element = document.create_element("div").unwrap();
358 for child in children {
359 let child_node: Node = self.create_dom_node_with_document(child, document);
360 fragment.append_child(&child_node).unwrap();
361 }
362 fragment.into()
363 }
364 VirtualNode::Dynamic(dynamic_node) => {
365 let placeholder: Element = document.create_element("div").unwrap();
366 let style: &str = "display: contents;";
367 let _ = placeholder.set_attribute("style", style);
368 let dynamic_id: usize = Self::assign_dynamic_id(&placeholder);
369 let initial_dom: Node =
370 self.setup_dynamic_node(dynamic_node, dynamic_id, &placeholder, true);
371 placeholder.append_child(&initial_dom).unwrap();
372 placeholder.into()
373 }
374 VirtualNode::Empty => document.create_text_node("").into(),
375 }
376 }
377
378 fn setup_dynamic_node(
381 &mut self,
382 dynamic_node: &DynamicNode,
383 dynamic_id: usize,
384 placeholder: &Element,
385 skip_equal: bool,
386 ) -> Node {
387 let mut hook_context: HookContext = dynamic_node.get_hook_context_value();
388 hook_context.reset_hook_index();
389 let initial_vnode: VirtualNode = with_hook_context(hook_context, || dynamic_node.render());
390 let initial_unwrapped: VirtualNode = self.unwrap_component(&initial_vnode);
391 let initial_dom: Node = self.create_dom_node(&initial_unwrapped);
392 let render_fn_addr: usize = usize::from(dynamic_node);
393 let placeholder_clone: Element = placeholder.clone();
394 let mut renderer_for_sub: Renderer = Renderer::new(placeholder_clone.clone());
395 renderer_for_sub.set_current_tree(Some(initial_unwrapped));
396 let renderer_addr: usize = Box::leak(Box::new(renderer_for_sub)) as *mut Renderer as usize;
397 let closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
398 if placeholder_clone.parent_node().is_none() {
399 return;
400 }
401 hook_context.reset_hook_index();
402 let new_vnode: VirtualNode = with_hook_context(hook_context, || {
403 let inner: &mut RenderFnInner = render_fn_addr.into();
404 (inner.render_fn)()
405 });
406 if skip_equal {
407 let renderer: &Renderer = renderer_addr.into();
408 if let Some(old_vnode) = renderer.try_get_current_tree() {
409 let new_unwrapped: VirtualNode = Renderer::unwrap_component_static(&new_vnode);
410 if old_vnode == &new_unwrapped {
411 return;
412 }
413 }
414 }
415 let renderer: &mut Renderer = renderer_addr.into();
416 renderer.render(new_vnode);
417 }));
418 register_dynamic_listener(dynamic_id, closure);
419 initial_dom
420 }
421
422 fn unwrap_component(&self, node: &VirtualNode) -> VirtualNode {
424 match node {
425 VirtualNode::Element {
426 tag: Tag::Component(_),
427 children,
428 ..
429 } => {
430 if children.len() == 1 {
431 self.unwrap_component(&children[0])
432 } else {
433 VirtualNode::Fragment(children.clone())
434 }
435 }
436 VirtualNode::Element {
437 tag,
438 attributes,
439 children,
440 key,
441 } => {
442 let unwrapped_children: Vec<VirtualNode> = children
443 .iter()
444 .map(|child| self.unwrap_component(child))
445 .collect();
446 VirtualNode::Element {
447 tag: tag.clone(),
448 attributes: attributes.clone(),
449 children: unwrapped_children,
450 key: key.clone(),
451 }
452 }
453 VirtualNode::Fragment(children) => {
454 let unwrapped_children: Vec<VirtualNode> = children
455 .iter()
456 .map(|child| self.unwrap_component(child))
457 .collect();
458 VirtualNode::Fragment(unwrapped_children)
459 }
460 other => other.clone(),
461 }
462 }
463
464 fn unwrap_component_static(node: &VirtualNode) -> VirtualNode {
468 match node {
469 VirtualNode::Element {
470 tag: Tag::Component(_),
471 children,
472 ..
473 } => {
474 if children.len() == 1 {
475 Self::unwrap_component_static(&children[0])
476 } else {
477 VirtualNode::Fragment(children.clone())
478 }
479 }
480 VirtualNode::Element {
481 tag,
482 attributes,
483 children,
484 key,
485 } => {
486 let unwrapped_children: Vec<VirtualNode> =
487 children.iter().map(Self::unwrap_component_static).collect();
488 VirtualNode::Element {
489 tag: tag.clone(),
490 attributes: attributes.clone(),
491 children: unwrapped_children,
492 key: key.clone(),
493 }
494 }
495 VirtualNode::Fragment(children) => {
496 let unwrapped_children: Vec<VirtualNode> =
497 children.iter().map(Self::unwrap_component_static).collect();
498 VirtualNode::Fragment(unwrapped_children)
499 }
500 other => other.clone(),
501 }
502 }
503
504 fn assign_dynamic_id(placeholder: &Element) -> usize {
506 let dynamic_id: usize = NEXT_EUV_DYNAMIC_ID.fetch_add(1, Ordering::Relaxed);
507 let _ = placeholder.set_attribute("data-euv-dynamic-id", &dynamic_id.to_string());
508 dynamic_id
509 }
510
511 fn attach_event_listener(&self, element: &Element, handler: &NativeEventHandler) {
513 let euv_id: usize = match element.get_attribute(DATA_EUV_ID) {
514 Some(id_str) => id_str.parse::<usize>().unwrap_or_else(|_| {
515 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
516 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
517 new_id
518 }),
519 None => {
520 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
521 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
522 new_id
523 }
524 };
525 let event_name: String = handler.get_event_name().clone();
526 let key: (usize, String) = (euv_id, event_name.clone());
527 let registry: &mut HashMap<(usize, String), HandlerEntry> = get_handler_registry();
528 if let Some(existing_ptr) = registry.get(&key) {
529 let existing: &mut HandlerSlot = (*existing_ptr as usize).into();
530 existing.set_handler(Some(handler.clone()));
531 } else {
532 let handler_slot: Box<HandlerSlot> = Box::new(HandlerSlot {
533 handler: Some(handler.clone()),
534 });
535 let handler_entry: HandlerEntry = Box::leak(handler_slot) as *mut HandlerSlot;
536 let handler_addr: usize = handler_entry as usize;
537 let closure: Closure<dyn FnMut(Event)> =
538 Closure::wrap(Box::new(move |event: Event| {
539 let slot: &mut HandlerSlot = handler_addr.into();
540 let active_handler: NativeEventHandler = slot.get_handler();
541 active_handler.handle(event);
542 }));
543 element
544 .add_event_listener_with_callback(&event_name, closure.as_ref().unchecked_ref())
545 .unwrap();
546 closure.forget();
547 registry.insert(key, handler_entry);
548 }
549 }
550}
551
552impl From<usize> for &'static mut Renderer {
554 #[inline(always)]
569 fn from(address: usize) -> Self {
570 unsafe { &mut *(address as *mut Renderer) }
571 }
572}
573
574impl From<usize> for &'static Renderer {
576 #[inline(always)]
591 fn from(address: usize) -> Self {
592 unsafe { &*(address as *const Renderer) }
593 }
594}