1use core::any::TypeId;
7use core::ptr::NonNull;
8
9use crate::data_storage::DataStorage;
10use crate::dom::document_cell::DocumentCell;
11use crate::dom::element_data::ElementData;
12use crate::dom::handle::Handle;
13use crate::dom::node::{NodeFlags, NodeMeta};
14use crate::dom::traits::Element;
15use crate::dom::traits::HasHandle;
16use crate::events::EventListenerMap;
17use crate::events::listener::RegisteredListener;
18use crate::events::store::EventStore;
19use crate::id::{INVALID, IdAllocator, RawId};
20use crate::layout::node_data::LayoutNodeData;
21use crate::styling::StyleEngine;
22use crate::tree;
23use crate::tree::TreeData;
24use crate::{Text, TextData};
25use kozan_primitives::arena::Storage;
26
27pub struct Document {
35 pub(crate) ids: IdAllocator,
37
38 pub(crate) meta: Storage<NodeMeta>,
40 pub(crate) tree: Storage<TreeData>,
41 pub(crate) element_data: Storage<ElementData>,
42 pub(crate) data: DataStorage,
43
44 pub(crate) layout: Storage<LayoutNodeData>,
47
48 pub(crate) style_engine: StyleEngine,
50
51 pub(crate) event_store: EventStore,
53
54 pub(crate) root: u32,
56 pub(crate) body: u32,
57
58 pub(crate) needs_tree_rebuild: bool,
61
62 pub(crate) dirty_layout_nodes: Vec<u32>,
64
65 pub(crate) needs_style_recalc: bool,
68
69 #[cfg(debug_assertions)]
71 pub(crate) alive: bool,
72}
73
74impl Document {
75 #[must_use]
77 pub fn new() -> Self {
78 let mut doc = Self {
79 ids: IdAllocator::new(),
80 meta: Storage::new(),
81 tree: Storage::new(),
82 element_data: Storage::new(),
83 data: DataStorage::new(),
84 layout: Storage::new(),
85 style_engine: StyleEngine::new(),
86 event_store: EventStore::new(),
87 root: 0,
88 body: 0,
89 needs_tree_rebuild: true,
90 dirty_layout_nodes: Vec::new(),
91 needs_style_recalc: false,
92 #[cfg(debug_assertions)]
93 alive: true,
94 };
95
96 let (root_index, _gen) = doc.alloc_node(NodeFlags::document(), TypeId::of::<()>());
98 doc.root = root_index;
99
100 doc
101 }
102
103 pub fn init_body(&mut self) {
109 if self.body != 0 {
110 return; }
112 let body = self.create::<crate::html::HtmlBodyElement>();
113 self.root().append(body);
114 self.body = body.handle().raw().index();
115 }
116
117 pub(crate) fn cell(&self) -> DocumentCell {
121 DocumentCell::new(NonNull::from(self))
122 }
123
124 pub(crate) fn alloc_node(&mut self, flags: NodeFlags, data_type_id: TypeId) -> (u32, u32) {
126 let raw = self.ids.alloc();
127 let (index, generation) = (raw.index(), raw.generation());
128 self.meta.set(
129 index,
130 NodeMeta {
131 flags,
132 data_type_id,
133 },
134 );
135 self.tree.set(index, TreeData::detached());
136 self.layout.set(index, LayoutNodeData::new());
137 self.event_store.ensure_slot(index);
138
139 unsafe {
140 self.meta.get_unchecked_mut(index).flags.mark_style_dirty();
141 self.meta.get_unchecked_mut(index).flags.mark_tree_dirty();
142 }
143
144 (index, generation)
145 }
146
147 pub(crate) fn is_alive_id(&self, id: RawId) -> bool {
151 self.ids.is_alive(id)
152 }
153
154 pub(crate) fn generation(&self, index: u32) -> Option<u32> {
156 if (index as usize) < self.ids.capacity() {
157 Some(unsafe { self.ids.generation_unchecked(index) })
158 } else {
159 None
160 }
161 }
162
163 pub(crate) fn raw_id(&self, index: u32) -> Option<RawId> {
165 if (index as usize) >= self.ids.capacity() {
166 return None;
167 }
168 let generation = unsafe { self.ids.generation_unchecked(index) };
169 let id = RawId::new(index, generation);
170 if self.ids.is_alive(id) {
171 Some(id)
172 } else {
173 None
174 }
175 }
176
177 pub(crate) fn node_meta(&self, id: RawId) -> Option<crate::dom::node::NodeMeta> {
179 if !self.ids.is_alive(id) {
180 return None;
181 }
182 self.meta.get(id.index()).copied()
183 }
184
185 pub(crate) fn node_kind(&self, id: RawId) -> Option<crate::dom::node::NodeType> {
187 self.node_meta(id).map(|m| m.flags.node_type())
188 }
189
190 pub(crate) fn tree_data(&self, id: RawId) -> Option<crate::tree::TreeData> {
192 if !self.ids.is_alive(id) {
193 return None;
194 }
195 self.tree.get(id.index()).copied()
196 }
197
198 pub(crate) fn children_ids(&self, id: RawId) -> Vec<RawId> {
200 if !self.ids.is_alive(id) {
201 return Vec::new();
202 }
203 let indices = unsafe { tree::ops::children(&self.tree, id.index()) };
204 indices
205 .into_iter()
206 .map(|idx| {
207 let child_gen = unsafe { self.ids.generation_unchecked(idx) };
208 RawId::new(idx, child_gen)
209 })
210 .collect()
211 }
212
213 pub(crate) fn read_data<D: 'static, R: 'static>(
215 &self,
216 id: RawId,
217 f: impl FnOnce(&D) -> R,
218 ) -> Option<R> {
219 if !self.ids.is_alive(id) {
220 return None;
221 }
222 let meta = self.meta.get(id.index())?;
223 if meta.data_type_id != TypeId::of::<D>() {
224 return None;
225 }
226 let data = unsafe { self.data.get::<D>(id.index()) };
227 Some(f(data))
228 }
229
230 pub(crate) fn write_data<D: 'static, R: 'static>(
232 &mut self,
233 id: RawId,
234 f: impl FnOnce(&mut D) -> R,
235 ) -> Option<R> {
236 if !self.ids.is_alive(id) {
237 return None;
238 }
239 let meta = self.meta.get(id.index())?;
240 if meta.data_type_id != TypeId::of::<D>() {
241 return None;
242 }
243 let data = unsafe { self.data.get_mut::<D>(id.index()) };
244 let result = f(data);
245 unsafe {
246 self.meta
247 .get_unchecked_mut(id.index())
248 .flags
249 .mark_paint_dirty();
250 }
251 Some(result)
252 }
253
254 pub(crate) fn read_element_data<R: 'static>(
256 &self,
257 id: RawId,
258 f: impl FnOnce(&ElementData) -> R,
259 ) -> Option<R> {
260 if !self.ids.is_alive(id) {
261 return None;
262 }
263 let meta = self.meta.get(id.index())?;
264 if !meta.flags.is_element() {
265 return None;
266 }
267 let ed = self.element_data.get(id.index())?;
268 Some(f(ed))
269 }
270
271 pub(crate) fn write_element_data<R: 'static>(
273 &mut self,
274 id: RawId,
275 f: impl FnOnce(&mut ElementData) -> R,
276 ) -> Option<R> {
277 if !self.ids.is_alive(id) {
278 return None;
279 }
280 let meta = self.meta.get(id.index())?;
281 if !meta.flags.is_element() {
282 return None;
283 }
284 let ed = self.element_data.get_mut(id.index())?;
285 let result = f(ed);
286 unsafe {
287 self.meta
288 .get_unchecked_mut(id.index())
289 .flags
290 .mark_style_dirty();
291 }
292 self.propagate_dirty_ancestors(id.index());
294 Some(result)
295 }
296
297 pub(crate) fn propagate_dirty_ancestors(&mut self, index: u32) {
300 let mut current = self
301 .tree
302 .get(index)
303 .map_or(crate::id::INVALID, |t| t.parent);
304 while current != crate::id::INVALID {
305 if let Some(ed) = self.element_data.get(current) {
306 if ed.dirty_descendants.get() {
307 break; }
309 ed.dirty_descendants.set(true);
310 }
311 current = self
312 .tree
313 .get(current)
314 .map_or(crate::id::INVALID, |t| t.parent);
315 }
316 }
317
318 pub(crate) fn append_child(&mut self, parent: RawId, child: RawId) {
322 if !self.ids.is_alive(parent) {
323 return;
324 }
325 if !self.ids.is_alive(child) {
326 return;
327 }
328 if let Some(meta) = self.meta.get(parent.index()) {
329 if !meta.flags.is_container() {
330 return;
331 }
332 } else {
333 return;
334 }
335 if unsafe { tree::ops::is_ancestor(&self.tree, child.index(), parent.index()) } {
336 return;
337 }
338 unsafe {
339 tree::ops::append(&mut self.tree, parent.index(), child.index());
340 self.meta
341 .get_unchecked_mut(parent.index())
342 .flags
343 .mark_tree_dirty();
344 self.meta
345 .get_unchecked_mut(child.index())
346 .flags
347 .mark_tree_dirty();
348 }
349 self.needs_tree_rebuild = true;
350 }
351
352 pub(crate) fn insert_before(&mut self, ref_id: RawId, child: RawId) {
354 if !self.ids.is_alive(ref_id) {
355 return;
356 }
357 if !self.ids.is_alive(child) {
358 return;
359 }
360 if let Some(tree) = self.tree.get(ref_id.index()) {
361 if !tree.has_parent() {
362 return;
363 }
364 } else {
365 return;
366 }
367 if unsafe { tree::ops::is_ancestor(&self.tree, child.index(), ref_id.index()) } {
368 return;
369 }
370 unsafe {
371 tree::ops::insert_before(&mut self.tree, ref_id.index(), child.index());
372 self.meta
373 .get_unchecked_mut(child.index())
374 .flags
375 .mark_tree_dirty();
376 }
377 self.needs_tree_rebuild = true;
378 }
379
380 pub(crate) fn detach_node(&mut self, id: RawId) {
382 if !self.ids.is_alive(id) {
383 return;
384 }
385 let parent = self
386 .tree
387 .get(id.index())
388 .map_or(crate::id::INVALID, |t| t.parent);
389 unsafe {
390 tree::ops::detach(&mut self.tree, id.index());
391 }
392 if parent != crate::id::INVALID {
393 unsafe {
394 self.meta.get_unchecked_mut(parent).flags.mark_tree_dirty();
395 }
396 self.needs_tree_rebuild = true;
397 }
398 }
399
400 pub(crate) fn destroy_node(&mut self, id: RawId) {
402 if !self.ids.is_alive(id) {
403 return;
404 }
405 self.detach_node(id);
406 if let Some(meta) = self.meta.get(id.index()).copied() {
408 if meta.data_type_id != TypeId::of::<()>() {
409 self.data.remove(meta.data_type_id, id.index());
410 }
411 }
412 if let Some(ed) = self.element_data.get_mut(id.index()) {
414 ed.stylo_data = style::data::ElementDataWrapper::default();
415 }
416 self.layout.clear_slot(id.index());
418 self.event_store.remove_node(id.index());
420 self.ids.free(id);
422 }
423
424 pub(crate) fn node_meta_by_index(&self, index: u32) -> Option<crate::dom::node::NodeMeta> {
428 self.meta.get(index).copied()
429 }
430
431 pub(crate) fn tag_name(&self, index: u32) -> Option<&'static str> {
433 Some(self.element_data.get(index)?.tag_name)
434 }
435
436 pub(crate) fn tree_data_by_index(&self, index: u32) -> Option<TreeData> {
438 self.tree.get(index).copied()
439 }
440
441 #[allow(dead_code)]
443 pub(crate) fn attribute(&self, index: u32, name: &str) -> Option<String> {
444 self.element_data
445 .get(index)?
446 .attributes
447 .get(name)
448 .map(|v| v.to_string())
449 }
450
451 #[allow(dead_code)]
453 pub(crate) fn children_indices_raw(&self, index: u32) -> Vec<u32> {
454 if !self.tree.is_initialized(index) {
455 return Vec::new();
456 }
457 unsafe { tree::ops::children(&self.tree, index) }
458 }
459
460 #[allow(dead_code)]
462 pub(crate) fn text_content(&self, index: u32) -> Option<String> {
463 let meta = self.meta.get(index)?;
464 if meta.data_type_id != TypeId::of::<TextData>() {
465 return None;
466 }
467 let data = unsafe { self.data.get::<TextData>(index) };
468 Some(data.content.clone())
469 }
470
471 pub fn computed_style(
475 &self,
476 index: u32,
477 ) -> Option<servo_arc::Arc<style::properties::ComputedValues>> {
478 let ed = self.element_data.get(index)?;
479 let data = ed.stylo_data.borrow();
480 if data.has_styles() {
481 Some(data.styles.primary().clone())
482 } else {
483 None
484 }
485 }
486
487 #[allow(dead_code)] pub(crate) fn intrinsic_sizing(&self, _index: u32) -> Option<crate::layout::IntrinsicSizes> {
490 None
491 }
492
493 pub(crate) fn ensure_event_listeners(&mut self, index: u32) -> &mut EventListenerMap {
497 self.event_store.ensure_listeners(index)
498 }
499
500 pub(crate) fn event_listeners_mut(&mut self, index: u32) -> Option<&mut EventListenerMap> {
502 self.event_store.get_mut(index)
503 }
504
505 pub(crate) fn take_event_listeners(
507 &mut self,
508 index: u32,
509 type_id: TypeId,
510 ) -> Option<Vec<RegisteredListener>> {
511 self.event_store.take(index, type_id)
512 }
513
514 pub(crate) fn put_event_listeners(
516 &mut self,
517 index: u32,
518 type_id: TypeId,
519 listeners: Vec<RegisteredListener>,
520 ) {
521 self.event_store.put(index, type_id, listeners);
522 }
523
524 pub(crate) fn init_typed_data<T: Default + 'static>(&mut self, index: u32) {
526 self.data.init::<T>(index);
527 }
528
529 pub(crate) fn set_element_data_new(&mut self, index: u32, data: ElementData) {
531 self.element_data.set(index, data);
532 }
533
534 pub(crate) fn set_text_content_new(&mut self, index: u32, content: &str) {
536 unsafe {
537 self.data.get_mut::<TextData>(index).content = content.to_string();
538 }
539 }
540
541 fn make_handle(&self, index: u32, generation: u32) -> Handle {
544 Handle::new(RawId::new(index, generation), self.cell())
545 }
546
547 pub fn div(&self) -> crate::html::HtmlDivElement {
550 self.create::<crate::html::HtmlDivElement>()
551 }
552 pub fn span(&self) -> crate::html::HtmlSpanElement {
553 self.create::<crate::html::HtmlSpanElement>()
554 }
555 pub fn p(&self) -> crate::html::HtmlParagraphElement {
556 self.create::<crate::html::HtmlParagraphElement>()
557 }
558 pub fn button(&self) -> crate::html::HtmlButtonElement {
559 self.create::<crate::html::HtmlButtonElement>()
560 }
561 pub fn img(&self) -> crate::html::HtmlImageElement {
562 self.create::<crate::html::HtmlImageElement>()
563 }
564 pub fn input(&self) -> crate::html::HtmlInputElement {
565 self.create::<crate::html::HtmlInputElement>()
566 }
567 pub fn label(&self) -> crate::html::HtmlLabelElement {
568 self.create::<crate::html::HtmlLabelElement>()
569 }
570 pub fn h1(&self) -> crate::html::HtmlHeadingElement {
571 self.create_heading(1)
572 }
573 pub fn h2(&self) -> crate::html::HtmlHeadingElement {
574 self.create_heading(2)
575 }
576 pub fn h3(&self) -> crate::html::HtmlHeadingElement {
577 self.create_heading(3)
578 }
579 pub fn text_node(&self, content: &str) -> Text {
580 self.create_text(content)
581 }
582
583 pub fn div_in(&self, parent: impl Into<Handle>) -> crate::html::HtmlDivElement {
584 let el = self.div();
585 parent.into().append(el);
586 el
587 }
588
589 pub fn span_in(&self, parent: impl Into<Handle>) -> crate::html::HtmlSpanElement {
590 let el = self.span();
591 parent.into().append(el);
592 el
593 }
594
595 pub fn text_in(&self, parent: impl Into<Handle>, content: &str) -> Text {
596 let t = self.text_node(content);
597 parent.into().append(t);
598 t
599 }
600
601 pub fn create<T: Element>(&self) -> T {
604 assert!(
605 !T::TAG_NAME.is_empty(),
606 "Element type has no fixed tag — use create_with_tag() instead"
607 );
608 self.create_with_tag::<T>(T::TAG_NAME)
609 }
610
611 pub fn create_with_tag<T: Element>(&self, tag: &'static str) -> T {
612 let cell = self.cell();
613 let (index, generation) = cell.write(|doc| {
614 let (index, generation) =
615 doc.alloc_node(NodeFlags::element(T::IS_FOCUSABLE), TypeId::of::<T::Data>());
616 doc.set_element_data_new(index, ElementData::new(tag, T::IS_FOCUSABLE));
617 if TypeId::of::<T::Data>() != TypeId::of::<()>() {
618 doc.init_typed_data::<T::Data>(index);
619 }
620 (index, generation)
621 });
622
623 T::from_handle(self.make_handle(index, generation))
624 }
625
626 pub fn create_heading(&self, level: u8) -> crate::html::HtmlHeadingElement {
627 assert!(
628 (1..=6).contains(&level),
629 "heading level must be 1-6, got {level}"
630 );
631 let tag: &'static str = match level {
632 1 => "h1",
633 2 => "h2",
634 3 => "h3",
635 4 => "h4",
636 5 => "h5",
637 6 => "h6",
638 _ => unreachable!(),
639 };
640 let elem = self.create_with_tag::<crate::html::HtmlHeadingElement>(tag);
641 elem.set_level(level);
642 elem
643 }
644
645 pub fn create_text(&self, content: &str) -> Text {
646 let cell = self.cell();
647 let content_owned = content.to_string();
648 let (index, generation) = cell.write(|doc| {
649 let (index, generation) = doc.alloc_node(NodeFlags::text(), TypeId::of::<TextData>());
650 doc.init_typed_data::<TextData>(index);
651 doc.set_text_content_new(index, &content_owned);
652 (index, generation)
653 });
654
655 Text::from_raw(self.make_handle(index, generation))
656 }
657
658 pub fn root(&self) -> Handle {
661 Handle::new(RawId::new(self.root, 0), self.cell())
662 }
663
664 pub fn body(&self) -> Handle {
672 debug_assert!(self.body != 0, "body() called before init_body()");
673 Handle::new(RawId::new(self.body, 0), self.cell())
674 }
675
676 pub fn resolve(&self, raw: RawId) -> Option<Handle> {
677 if self.ids.is_alive(raw) {
678 Some(Handle::new(raw, self.cell()))
679 } else {
680 None
681 }
682 }
683
684 pub fn node_count(&self) -> u32 {
685 self.ids.count()
686 }
687
688 pub fn root_index(&self) -> u32 {
689 self.root
690 }
691
692 pub fn needs_visual_update(&self) -> bool {
697 self.needs_style_recalc || self.needs_tree_rebuild || !self.dirty_layout_nodes.is_empty()
698 }
699
700 pub(crate) fn take_layout_dirty(&mut self) -> bool {
706 let dirty = self.needs_style_recalc || self.needs_tree_rebuild;
707 self.needs_style_recalc = false;
708 self.needs_tree_rebuild = false;
709 self.dirty_layout_nodes.clear();
710 dirty
711 }
712
713 pub fn handle_for_index(&self, index: u32) -> Option<Handle> {
721 let generation = self.ids.live_generation(index)?;
722 Some(Handle::new(RawId::new(index, generation), self.cell()))
723 }
724
725 #[allow(dead_code)] pub(crate) fn set_hover_state(&self, index: u32, hovered: bool) {
732 let Some(generation) = self.ids.live_generation(index) else {
733 return;
734 };
735 let id = RawId::new(index, generation);
736 self.cell().write(|doc| {
737 doc.write_element_data(id, |ed| {
738 if hovered {
739 ed.element_state.insert(style_dom::ElementState::HOVER);
740 } else {
741 ed.element_state.remove(style_dom::ElementState::HOVER);
742 }
743 });
744 doc.mark_for_restyle(index);
747 });
748 }
749
750 pub(crate) fn set_hover_chain(&self, index: u32, hovered: bool) {
756 self.set_state_chain(index, style_dom::ElementState::HOVER, hovered);
757 }
758
759 pub(crate) fn set_active_chain(&self, index: u32, active: bool) {
764 self.set_state_chain(index, style_dom::ElementState::ACTIVE, active);
765 }
766
767 fn set_state_chain(&self, index: u32, flag: style_dom::ElementState, active: bool) {
770 self.cell().write(|doc| {
771 let mut current = index;
772 loop {
773 if let Some(ed) = doc.element_data.get_mut(current) {
774 if active {
775 ed.element_state.insert(flag);
776 } else {
777 ed.element_state.remove(flag);
778 }
779 }
780 doc.mark_for_restyle(current);
781
782 match doc.tree.get(current) {
783 Some(td) if td.parent != INVALID => current = td.parent,
784 _ => break,
785 }
786 }
787 });
788 }
789
790 pub(crate) fn mark_for_restyle(&mut self, index: u32) {
800 self.needs_style_recalc = true;
801
802 if let Some(ed) = self.element_data.get(index) {
803 ed.mark_for_restyle();
804 }
805
806 self.propagate_dirty_ancestors(index);
807 }
808
809 #[allow(dead_code)] pub(crate) fn layout_data(&self, index: u32) -> Option<&LayoutNodeData> {
814 self.layout.get(index)
815 }
816
817 #[allow(dead_code)] pub(crate) fn layout_data_mut(&mut self, index: u32) -> Option<&mut LayoutNodeData> {
820 self.layout.get_mut(index)
821 }
822
823 pub(crate) fn mark_layout_dirty(&mut self, index: u32) {
831 let mut current = index;
832 while let Some(data) = self.layout.get_mut(current) {
833 data.clear_cache();
834 let Some(parent) = data.layout_parent() else {
835 break;
836 };
837 current = parent;
838 }
839 }
840
841 #[allow(dead_code)]
842 pub(crate) fn cell_for_layout(&self) -> DocumentCell {
843 self.cell()
844 }
845
846 pub fn recalc_styles(&mut self) {
849 let cell = self.cell();
852 let root = self.root;
853 self.style_engine.recalc_styles(cell, root);
854 }
855
856 pub fn add_stylesheet(&self, css: &str) {
867 let cell = self.cell();
868 let css_owned = css.to_string();
869 cell.write(|doc| {
870 doc.style_engine.add_stylesheet(&css_owned);
871 });
872 }
873
874 pub(crate) fn set_viewport(&mut self, width: f32, height: f32) {
875 self.style_engine.set_viewport(width, height);
876 }
877}
878
879impl Default for Document {
880 fn default() -> Self {
881 Self::new()
882 }
883}
884
885impl Drop for Document {
886 fn drop(&mut self) {
887 #[cfg(debug_assertions)]
888 {
889 self.alive = false;
890 }
891 }
892}
893
894#[cfg(test)]
895mod tests {
896 use super::*;
897 use crate::dom::traits::HasHandle;
898
899 #[test]
900 fn new_creates_exactly_one_root_node() {
901 let doc = Document::new();
902 assert_eq!(doc.node_count(), 1);
903 }
904
905 #[test]
906 fn created_element_handle_is_alive() {
907 let doc = Document::new();
908 let div = doc.div();
909 assert!(div.handle().is_alive());
910 }
911
912 #[test]
913 fn destroy_makes_handle_dead() {
914 let doc = Document::new();
915 let div = doc.div();
916 let handle = div.handle();
917 handle.destroy();
918 assert!(!handle.is_alive());
919 }
920
921 #[test]
922 fn handle_raw_index_matches_arena_slot() {
923 let doc = Document::new();
924 let div = doc.div();
926 let raw = div.handle().raw();
927 assert!(doc.ids.is_alive(raw));
928 }
929}