1use crate::events::handle_event;
2use crate::layout::construct::collect_layout_children;
3use crate::mutator::ViewportMut;
4use crate::node::{ImageData, NodeSpecificData, RasterImageData, Status, TextBrush};
5use crate::stylo_to_cursor_icon::stylo_to_cursor_icon;
6use crate::traversal::{AncestorTraverser, TreeTraverser};
7use crate::util::{ImageType, resolve_url};
8use crate::{DocumentMutator, ElementNodeData, Node, NodeData, TextNodeData};
9use app_units::Au;
10use blitz_traits::events::UiEvent;
11use blitz_traits::navigation::{DummyNavigationProvider, NavigationProvider};
12use blitz_traits::net::{DummyNetProvider, SharedProvider};
13use blitz_traits::shell::{DummyShellProvider, ShellProvider};
14use blitz_traits::{ColorScheme, Devtools, Viewport};
15use blitz_traits::{DomEvent, HitResult};
16use cursor_icon::CursorIcon;
17use markup5ever::local_name;
18use parley::FontContext;
19use peniko::{Blob, kurbo};
20use string_cache::Atom;
21use style::attr::{AttrIdentifier, AttrValue};
22use style::data::{ElementData, ElementStyles};
23use style::properties::ComputedValues;
24use style::properties::style_structs::Font;
25use style::values::GenericAtomIdent;
26use style::values::computed::Overflow;
27use crate::net::{Resource, StylesheetLoader};
29use selectors::{Element, matching::QuirksMode};
30use slab::Slab;
31use std::any::Any;
32use std::collections::{BTreeMap, Bound, HashMap, HashSet};
33use std::ops::{Deref, DerefMut};
34use std::sync::Arc;
35use std::sync::atomic::{AtomicUsize, Ordering};
36use style::media_queries::MediaType;
37use style::queries::values::PrefersColorScheme;
38use style::selector_parser::ServoElementSnapshot;
39use style::servo::media_queries::FontMetricsProvider;
40use style::servo_arc::Arc as ServoArc;
41use style::{
42 dom::{TDocument, TNode},
43 media_queries::{Device, MediaList},
44 selector_parser::SnapshotMap,
45 shared_lock::{SharedRwLock, StylesheetGuards},
46 stylesheets::{AllowImportRules, DocumentStyleSheet, Origin, Stylesheet, UrlExtraData},
47 stylist::Stylist,
48};
49use taffy::AvailableSpace;
50use url::Url;
51
52pub trait Document: Deref<Target = BaseDocument> + DerefMut + 'static {
53 fn poll(&mut self, cx: std::task::Context) -> bool {
54 let _ = cx;
56 false
57 }
58
59 fn handle_event(&mut self, event: UiEvent) {
60 let _ = event;
62 }
63
64 fn as_any_mut(&mut self) -> &mut dyn Any;
65
66 fn id(&self) -> usize;
67}
68
69#[derive(Debug, Clone)]
71struct DummyFontMetricsProvider;
72impl FontMetricsProvider for DummyFontMetricsProvider {
73 fn query_font_metrics(
74 &self,
75 _vertical: bool,
76 _font: &Font,
77 _base_size: style::values::computed::CSSPixelLength,
78 _flags: style::values::computed::font::QueryFontMetricsFlags,
79 ) -> style::font_metrics::FontMetrics {
80 Default::default()
81 }
82
83 fn base_size_for_generic(
84 &self,
85 generic: style::values::computed::font::GenericFontFamily,
86 ) -> style::values::computed::Length {
87 let size = match generic {
88 style::values::computed::font::GenericFontFamily::Monospace => 13.0,
89 _ => 16.0,
90 };
91 style::values::computed::Length::from(Au::from_f32_px(size))
92 }
93}
94
95pub struct BaseDocument {
96 id: usize,
97
98 pub nodes: Box<Slab<Node>>,
105
106 pub guard: SharedRwLock,
108
109 pub(crate) stylist: Stylist,
111
112 pub(crate) snapshots: SnapshotMap,
114
115 pub nodes_to_id: HashMap<String, usize>,
117
118 pub base_url: Option<url::Url>,
120
121 pub(crate) viewport: Viewport,
126 pub(crate) devtool_settings: Devtools,
128
129 pub(crate) viewport_scroll: kurbo::Point,
131
132 pub(crate) ua_stylesheets: HashMap<String, DocumentStyleSheet>,
135
136 pub(crate) nodes_to_stylesheet: BTreeMap<usize, DocumentStyleSheet>,
137
138 pub font_ctx: parley::FontContext,
140
141 pub layout_ctx: parley::LayoutContext<TextBrush>,
143
144 pub(crate) hover_node_id: Option<usize>,
146 pub(crate) focus_node_id: Option<usize>,
148 pub(crate) active_node_id: Option<usize>,
150 pub(crate) mousedown_node_id: Option<usize>,
152
153 pub changed: HashSet<usize>,
154
155 pub controls_to_form: HashMap<usize, usize>,
157
158 pub net_provider: SharedProvider<Resource>,
160
161 pub navigation_provider: Arc<dyn NavigationProvider>,
164
165 pub shell_provider: Arc<dyn ShellProvider>,
167}
168
169pub(crate) fn make_device(viewport: &Viewport) -> Device {
170 let width = viewport.window_size.0 as f32 / viewport.scale();
171 let height = viewport.window_size.1 as f32 / viewport.scale();
172 let viewport_size = euclid::Size2D::new(width, height);
173 let device_pixel_ratio = euclid::Scale::new(viewport.scale());
174
175 Device::new(
176 MediaType::screen(),
177 selectors::matching::QuirksMode::NoQuirks,
178 viewport_size,
179 device_pixel_ratio,
180 Box::new(DummyFontMetricsProvider),
181 ComputedValues::initial_values_with_font_override(Font::initial_values()),
182 match viewport.color_scheme {
183 ColorScheme::Light => PrefersColorScheme::Light,
184 ColorScheme::Dark => PrefersColorScheme::Dark,
185 },
186 )
187}
188
189impl BaseDocument {
190 pub fn handle_event<F: FnMut(DomEvent)>(&mut self, event: &mut DomEvent, dispatch_event: F) {
191 handle_event(self, event, dispatch_event)
192 }
193 pub fn as_any_mut(&mut self) -> &mut dyn Any {
194 self
195 }
196}
197
198impl BaseDocument {
199 pub fn new(viewport: Viewport) -> Self {
200 Self::with_font_ctx(viewport, parley::FontContext::default())
201 }
202
203 pub fn with_font_ctx(viewport: Viewport, mut font_ctx: FontContext) -> Self {
204 static ID_GENERATOR: AtomicUsize = AtomicUsize::new(1);
205
206 let id = ID_GENERATOR.fetch_add(1, Ordering::SeqCst);
207 let device = make_device(&viewport);
208 let stylist = Stylist::new(device, QuirksMode::NoQuirks);
209 let snapshots = SnapshotMap::new();
210 let nodes = Box::new(Slab::new());
211 let guard = SharedRwLock::new();
212 let nodes_to_id = HashMap::new();
213
214 style_config::set_bool("layout.flexbox.enabled", true);
216 style_config::set_bool("layout.grid.enabled", true);
217 style_config::set_bool("layout.legacy_layout", true);
218 style_config::set_bool("layout.unimplemented", true);
219 style_config::set_bool("layout.columns.enabled", true);
220
221 font_ctx
222 .collection
223 .register_fonts(Blob::new(Arc::new(crate::BULLET_FONT) as _), None);
224
225 let mut doc = Self {
226 id,
227 guard,
228 nodes,
229 stylist,
230 snapshots,
231 nodes_to_id,
232 viewport,
233 devtool_settings: Devtools::default(),
234 viewport_scroll: kurbo::Point::ZERO,
235 base_url: None,
236 ua_stylesheets: HashMap::new(),
238 nodes_to_stylesheet: BTreeMap::new(),
239 font_ctx,
240 layout_ctx: parley::LayoutContext::new(),
241
242 hover_node_id: None,
243 focus_node_id: None,
244 active_node_id: None,
245 mousedown_node_id: None,
246 changed: HashSet::new(),
247 controls_to_form: HashMap::new(),
248 net_provider: Arc::new(DummyNetProvider),
249 navigation_provider: Arc::new(DummyNavigationProvider),
250 shell_provider: Arc::new(DummyShellProvider),
251 };
252
253 doc.create_node(NodeData::Document);
255
256 let stylo_element_data = ElementData {
258 styles: ElementStyles {
259 primary: Some(
260 ComputedValues::initial_values_with_font_override(Font::initial_values())
261 .to_arc(),
262 ),
263 ..Default::default()
264 },
265 ..Default::default()
266 };
267 *doc.root_node().stylo_element_data.borrow_mut() = Some(stylo_element_data);
268
269 doc
270 }
271
272 pub fn set_net_provider(&mut self, net_provider: SharedProvider<Resource>) {
274 self.net_provider = net_provider;
275 }
276
277 pub fn set_navigation_provider(&mut self, navigation_provider: Arc<dyn NavigationProvider>) {
279 self.navigation_provider = navigation_provider;
280 }
281
282 pub fn set_shell_provider(&mut self, shell_provider: Arc<dyn ShellProvider>) {
284 self.shell_provider = shell_provider;
285 }
286
287 pub fn set_base_url(&mut self, url: &str) {
289 self.base_url = Some(Url::parse(url).unwrap());
290 }
291
292 pub fn guard(&self) -> &SharedRwLock {
293 &self.guard
294 }
295
296 pub fn tree(&self) -> &Slab<Node> {
297 &self.nodes
298 }
299
300 pub fn id(&self) -> usize {
301 self.id
302 }
303
304 pub fn get_node(&self, node_id: usize) -> Option<&Node> {
305 self.nodes.get(node_id)
306 }
307
308 pub fn get_node_mut(&mut self, node_id: usize) -> Option<&mut Node> {
309 self.nodes.get_mut(node_id)
310 }
311
312 pub fn get_focussed_node_id(&self) -> Option<usize> {
313 self.focus_node_id
314 .or(self.try_root_element().map(|el| el.id))
315 }
316
317 pub fn mutate<'doc>(&'doc mut self) -> DocumentMutator<'doc> {
318 DocumentMutator::new(self)
319 }
320
321 pub fn label_bound_input_element(&self, label_node_id: usize) -> Option<&Node> {
328 let label_element = self.nodes[label_node_id].element_data()?;
329 if let Some(target_element_dom_id) = label_element.attr(local_name!("for")) {
330 TreeTraverser::new(self)
331 .filter_map(|id| {
332 let node = self.get_node(id)?;
333 let element_data = node.element_data()?;
334 if element_data.name.local != local_name!("input") {
335 return None;
336 }
337 let id = element_data.id.as_ref()?;
338 if *id == *target_element_dom_id {
339 Some(node)
340 } else {
341 None
342 }
343 })
344 .next()
345 } else {
346 TreeTraverser::new_with_root(self, label_node_id)
347 .filter_map(|child_id| {
348 let node = self.get_node(child_id)?;
349 let element_data = node.element_data()?;
350 if element_data.name.local == local_name!("input") {
351 Some(node)
352 } else {
353 None
354 }
355 })
356 .next()
357 }
358 }
359
360 pub fn toggle_checkbox(el: &mut ElementNodeData) -> bool {
361 let Some(is_checked) = el.checkbox_input_checked_mut() else {
362 return false;
363 };
364 *is_checked = !*is_checked;
365
366 *is_checked
367 }
368
369 pub fn toggle_radio(&mut self, radio_set_name: String, target_radio_id: usize) {
370 for i in 0..self.nodes.len() {
371 let node = &mut self.nodes[i];
372 if let Some(node_data) = node.data.downcast_element_mut() {
373 if node_data.attr(local_name!("name")) == Some(&radio_set_name) {
374 let was_clicked = i == target_radio_id;
375 let Some(is_checked) = node_data.checkbox_input_checked_mut() else {
376 continue;
377 };
378 *is_checked = was_clicked;
379 }
380 }
381 }
382 }
383
384 pub fn root_node(&self) -> &Node {
385 &self.nodes[0]
386 }
387
388 pub fn try_root_element(&self) -> Option<&Node> {
389 TDocument::as_node(&self.root_node()).first_element_child()
390 }
391
392 pub fn root_element(&self) -> &Node {
393 TDocument::as_node(&self.root_node())
394 .first_element_child()
395 .unwrap()
396 .as_element()
397 .unwrap()
398 }
399
400 pub fn create_node(&mut self, node_data: NodeData) -> usize {
401 let slab_ptr = self.nodes.as_mut() as *mut Slab<Node>;
402 let guard = self.guard.clone();
403
404 let entry = self.nodes.vacant_entry();
405 let id = entry.key();
406 entry.insert(Node::new(slab_ptr, id, guard, node_data));
407
408 self.changed.insert(id);
410 id
411 }
412
413 pub fn create_text_node(&mut self, text: &str) -> usize {
414 let content = text.to_string();
415 let data = NodeData::Text(TextNodeData::new(content));
416 self.create_node(data)
417 }
418
419 pub fn deep_clone_node(&mut self, node_id: usize) -> usize {
420 let node = &self.nodes[node_id];
422 let data = node.data.clone();
423 let children = node.children.clone();
424
425 let new_node_id = self.create_node(data);
427
428 let new_children: Vec<usize> = children
430 .into_iter()
431 .map(|child_id| self.deep_clone_node(child_id))
432 .collect();
433 for &child_id in &new_children {
434 self.nodes[child_id].parent = Some(new_node_id);
435 }
436 self.nodes[new_node_id].children = new_children;
437
438 new_node_id
439 }
440
441 pub fn insert_before(&mut self, node_id: usize, inserted_node_ids: &[usize]) {
442 let node = &self.nodes[node_id];
447
448 let parent_id = node.parent.unwrap();
449 let parent = &mut self.nodes[parent_id];
450 let node_child_idx = parent
451 .children
452 .iter()
453 .position(|id| *id == node_id)
454 .unwrap();
455
456 self.changed.insert(parent_id);
458
459 let mut children = std::mem::take(&mut parent.children);
460 children.splice(
461 node_child_idx..node_child_idx,
462 inserted_node_ids.iter().copied(),
463 );
464
465 let mut child_idx = node_child_idx;
467 while child_idx < children.len() {
468 let child_id = children[child_idx];
469 let node = &mut self.nodes[child_id];
470 node.parent = Some(parent_id);
471 child_idx += 1;
472 }
473
474 self.nodes[parent_id].children = children;
475 }
476
477 pub fn append(&mut self, node_id: usize, appended_node_ids: &[usize]) {
478 let node = &self.nodes[node_id];
479 let parent_id = node.parent.unwrap();
480 self.nodes[parent_id]
481 .children
482 .extend_from_slice(appended_node_ids);
483
484 for &child_id in appended_node_ids {
486 self.nodes[child_id].parent = Some(parent_id);
487 }
488 }
489
490 pub fn remove_node(&mut self, node_id: usize) {
492 let node = &mut self.nodes[node_id];
493
494 if let Some(parent_id) = node.parent.take() {
496 let parent = &mut self.nodes[parent_id];
497 parent.children.retain(|id| *id != node_id);
498 }
499 }
500
501 pub fn remove_and_drop_node(&mut self, node_id: usize) -> Option<Node> {
502 fn remove_node_ignoring_parent(doc: &mut BaseDocument, node_id: usize) -> Option<Node> {
503 let node = doc.nodes.try_remove(node_id);
504 if let Some(node) = &node {
505 for &child in &node.children {
506 remove_node_ignoring_parent(doc, child);
507 }
508 }
509 node
510 }
511
512 let node = remove_node_ignoring_parent(self, node_id);
513
514 if let Some(parent_id) = node.as_ref().and_then(|node| node.parent) {
516 let parent = &mut self.nodes[parent_id];
517 parent.children.retain(|id| *id != node_id);
518 }
519
520 node
521 }
522
523 pub fn resolve_url(&self, raw: &str) -> url::Url {
524 resolve_url(&self.base_url, raw).unwrap_or_else(|| {
525 panic!(
526 "to be able to resolve {raw} with the base_url: {base_url:?}",
527 base_url = self.base_url
528 )
529 })
530 }
531
532 pub fn print_tree(&self) {
533 crate::util::walk_tree(0, self.root_node());
534 }
535
536 pub fn print_subtree(&self, node_id: usize) {
537 crate::util::walk_tree(0, &self.nodes[node_id]);
538 }
539
540 pub fn process_style_element(&mut self, target_id: usize) {
541 let css = self.nodes[target_id].text_content();
542 let css = html_escape::decode_html_entities(&css);
543 let sheet = self.make_stylesheet(&css, Origin::Author);
544 self.add_stylesheet_for_node(sheet, target_id);
545 }
546
547 pub fn remove_user_agent_stylesheet(&mut self, contents: &str) {
548 if let Some(sheet) = self.ua_stylesheets.remove(contents) {
549 self.stylist.remove_stylesheet(sheet, &self.guard.read());
550 }
551 }
552
553 pub fn add_user_agent_stylesheet(&mut self, css: &str) {
554 let sheet = self.make_stylesheet(css, Origin::UserAgent);
555 self.ua_stylesheets.insert(css.to_string(), sheet.clone());
556 self.stylist.append_stylesheet(sheet, &self.guard.read());
557 }
558
559 pub fn make_stylesheet(&self, css: impl AsRef<str>, origin: Origin) -> DocumentStyleSheet {
560 let data = Stylesheet::from_str(
561 css.as_ref(),
562 UrlExtraData::from(self.base_url.clone().unwrap_or_else(|| {
563 "data:text/css;charset=utf-8;base64,"
564 .parse::<Url>()
565 .unwrap()
566 })),
567 origin,
568 ServoArc::new(self.guard.wrap(MediaList::empty())),
569 self.guard.clone(),
570 Some(&StylesheetLoader(self.id, self.net_provider.clone())),
571 None,
572 QuirksMode::NoQuirks,
573 AllowImportRules::Yes,
574 );
575
576 DocumentStyleSheet(ServoArc::new(data))
577 }
578
579 pub fn upsert_stylesheet_for_node(&mut self, node_id: usize) {
580 let raw_styles = self.nodes[node_id].text_content();
581 let sheet = self.make_stylesheet(raw_styles, Origin::Author);
582 self.add_stylesheet_for_node(sheet, node_id);
583 }
584
585 pub fn add_stylesheet_for_node(&mut self, stylesheet: DocumentStyleSheet, node_id: usize) {
586 let old = self.nodes_to_stylesheet.insert(node_id, stylesheet.clone());
587
588 if let Some(old) = old {
589 self.stylist.remove_stylesheet(old, &self.guard.read())
590 }
591
592 let insertion_point = self
594 .nodes_to_stylesheet
595 .range((Bound::Excluded(node_id), Bound::Unbounded))
596 .next()
597 .map(|(_, sheet)| sheet);
598
599 if let Some(insertion_point) = insertion_point {
600 self.stylist.insert_stylesheet_before(
601 stylesheet,
602 insertion_point.clone(),
603 &self.guard.read(),
604 )
605 } else {
606 self.stylist
607 .append_stylesheet(stylesheet, &self.guard.read())
608 }
609 }
610
611 pub fn load_resource(&mut self, resource: Resource) {
612 match resource {
613 Resource::Css(node_id, css) => {
614 self.add_stylesheet_for_node(css, node_id);
615 }
616 Resource::Image(node_id, kind, width, height, image_data) => {
617 let node = self.get_node_mut(node_id).unwrap();
618
619 match kind {
620 ImageType::Image => {
621 node.element_data_mut().unwrap().node_specific_data =
622 NodeSpecificData::Image(Box::new(ImageData::Raster(
623 RasterImageData::new(width, height, image_data),
624 )));
625
626 node.cache.clear();
628 }
629 ImageType::Background(idx) => {
630 if let Some(Some(bg_image)) = node
631 .element_data_mut()
632 .and_then(|el| el.background_images.get_mut(idx))
633 {
634 bg_image.status = Status::Ok;
635 bg_image.image =
636 ImageData::Raster(RasterImageData::new(width, height, image_data))
637 }
638 }
639 }
640 }
641 #[cfg(feature = "svg")]
642 Resource::Svg(node_id, kind, tree) => {
643 let node = self.get_node_mut(node_id).unwrap();
644
645 match kind {
646 ImageType::Image => {
647 node.element_data_mut().unwrap().node_specific_data =
648 NodeSpecificData::Image(Box::new(ImageData::Svg(tree)));
649
650 node.cache.clear();
652 }
653 ImageType::Background(idx) => {
654 if let Some(Some(bg_image)) = node
655 .element_data_mut()
656 .and_then(|el| el.background_images.get_mut(idx))
657 {
658 bg_image.status = Status::Ok;
659 bg_image.image = ImageData::Svg(tree);
660 }
661 }
662 }
663 }
664 Resource::Font(bytes) => {
665 self.font_ctx
668 .collection
669 .register_fonts(Blob::new(Arc::new(bytes)) as _, None);
670 }
671 Resource::None => {
672 }
674 _ => {}
675 }
676 }
677
678 pub fn snapshot_node(&mut self, node_id: usize) {
679 let node = &mut self.nodes[node_id];
680 let opaque_node_id = TNode::opaque(&&*node);
681 node.has_snapshot = true;
682 node.snapshot_handled
683 .store(false, std::sync::atomic::Ordering::SeqCst);
684
685 if let Some(_existing_snapshot) = self.snapshots.get_mut(&opaque_node_id) {
687 } else {
690 let attrs: Option<Vec<_>> = node.attrs().map(|attrs| {
691 attrs
692 .iter()
693 .map(|attr| {
694 let ident = AttrIdentifier {
695 local_name: GenericAtomIdent(attr.name.local.clone()),
696 name: GenericAtomIdent(attr.name.local.clone()),
697 namespace: GenericAtomIdent(attr.name.ns.clone()),
698 prefix: None,
699 };
700
701 let value = if attr.name.local == local_name!("id") {
702 AttrValue::Atom(Atom::from(&*attr.value))
703 } else if attr.name.local == local_name!("class") {
704 let classes = attr
705 .value
706 .split_ascii_whitespace()
707 .map(Atom::from)
708 .collect();
709 AttrValue::TokenList(attr.value.clone(), classes)
710 } else {
711 AttrValue::String(attr.value.clone())
712 };
713
714 (ident, value)
715 })
716 .collect()
717 });
718
719 let changed_attrs = attrs
720 .as_ref()
721 .map(|attrs| attrs.iter().map(|attr| attr.0.name.clone()).collect())
722 .unwrap_or_default();
723
724 self.snapshots.insert(
725 opaque_node_id,
726 ServoElementSnapshot {
727 state: Some(node.element_state),
728 attrs,
729 changed_attrs,
730 class_changed: true,
731 id_changed: true,
732 other_attributes_changed: true,
733 },
734 );
735 }
736 }
737
738 pub fn snapshot_node_and(&mut self, node_id: usize, cb: impl FnOnce(&mut Node)) {
739 self.snapshot_node(node_id);
740 cb(&mut self.nodes[node_id]);
741 }
742
743 pub fn resolve(&mut self) {
745 if TDocument::as_node(&&self.nodes[0])
746 .first_element_child()
747 .is_none()
748 {
749 println!("No DOM - not resolving");
750 return;
751 }
752
753 self.resolve_stylist();
755
756 self.resolve_layout_children();
758
759 self.flush_styles_to_layout(self.root_element().id);
761
762 self.resolve_layout();
764 }
765
766 pub fn hit(&self, x: f32, y: f32) -> Option<HitResult> {
768 if TDocument::as_node(&&self.nodes[0])
769 .first_element_child()
770 .is_none()
771 {
772 println!("No DOM - not resolving");
773 return None;
774 }
775
776 self.root_element().hit(x, y)
777 }
778
779 pub fn non_anon_ancestor_if_anon(&self, mut node_id: usize) -> usize {
782 loop {
783 let node = &self.nodes[node_id];
784
785 if !node.is_anonymous() {
786 return node.id;
787 }
788
789 let Some(parent_id) = node.layout_parent.get() else {
790 panic!("Node does not exist or does not have a non-anonymous parent");
793 };
794
795 node_id = parent_id;
796 }
797 }
798
799 pub fn iter_children_mut(
800 &mut self,
801 node_id: usize,
802 mut cb: impl FnMut(usize, &mut BaseDocument),
803 ) {
804 let children = std::mem::take(&mut self.nodes[node_id].children);
805 for child_id in children.iter().cloned() {
806 cb(child_id, self);
807 }
808 self.nodes[node_id].children = children;
809 }
810
811 pub fn iter_subtree_mut(
812 &mut self,
813 node_id: usize,
814 mut cb: impl FnMut(usize, &mut BaseDocument),
815 ) {
816 cb(node_id, self);
817 iter_subtree_mut_inner(self, node_id, &mut cb);
818 fn iter_subtree_mut_inner(
819 doc: &mut BaseDocument,
820 node_id: usize,
821 cb: &mut impl FnMut(usize, &mut BaseDocument),
822 ) {
823 let children = std::mem::take(&mut doc.nodes[node_id].children);
824 for child_id in children.iter().cloned() {
825 cb(child_id, doc);
826 iter_subtree_mut_inner(doc, child_id, cb);
827 }
828 doc.nodes[node_id].children = children;
829 }
830 }
831
832 pub fn iter_children_and_pseudos_mut(
833 &mut self,
834 node_id: usize,
835 mut cb: impl FnMut(usize, &mut BaseDocument),
836 ) {
837 let before = self.nodes[node_id].before.take();
838 if let Some(before_node_id) = before {
839 cb(before_node_id, self)
840 }
841 self.nodes[node_id].before = before;
842
843 self.iter_children_mut(node_id, &mut cb);
844
845 let after = self.nodes[node_id].after.take();
846 if let Some(after_node_id) = after {
847 cb(after_node_id, self)
848 }
849 self.nodes[node_id].after = after;
850 }
851
852 pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<usize> {
853 let start_id = start.id;
854 let mut node = start;
855 let mut look_in_children = true;
856 loop {
857 let next = if look_in_children && !node.children.is_empty() {
859 let node_id = node.children[0];
860 &self.nodes[node_id]
861 }
862 else if let Some(parent) = node.parent_node() {
864 let self_idx = parent
865 .children
866 .iter()
867 .position(|id| *id == node.id)
868 .unwrap();
869 if let Some(sibling_id) = parent.children.get(self_idx + 1) {
871 look_in_children = true;
872 &self.nodes[*sibling_id]
873 }
874 else {
876 look_in_children = false;
877 node = parent;
878 continue;
879 }
880 }
881 else {
883 look_in_children = true;
884 self.root_node()
885 };
886
887 if filter(next) {
888 return Some(next.id);
889 } else if next.id == start_id {
890 return None;
891 }
892
893 node = next;
894 }
895 }
896
897 pub fn node_layout_ancestors(&self, node_id: usize) -> Vec<usize> {
898 let mut ancestors = Vec::with_capacity(12);
899 let mut maybe_id = Some(node_id);
900 while let Some(id) = maybe_id {
901 ancestors.push(id);
902 maybe_id = self.nodes[id].layout_parent.get();
903 }
904 ancestors.reverse();
905 ancestors
906 }
907
908 pub fn maybe_node_layout_ancestors(&self, node_id: Option<usize>) -> Vec<usize> {
909 node_id
910 .map(|id| self.node_layout_ancestors(id))
911 .unwrap_or_default()
912 }
913
914 pub fn focus_next_node(&mut self) -> Option<usize> {
915 let focussed_node_id = self.get_focussed_node_id()?;
916 let id = self.next_node(&self.nodes[focussed_node_id], |node| node.is_focussable())?;
917 self.set_focus_to(id);
918 Some(id)
919 }
920
921 pub fn clear_focus(&mut self) {
923 if let Some(id) = self.focus_node_id {
924 self.snapshot_node_and(id, |node| node.blur());
925 self.focus_node_id = None;
926 }
927 }
928
929 pub fn set_mousedown_node_id(&mut self, node_id: Option<usize>) {
930 self.mousedown_node_id = node_id;
931 }
932 pub fn set_focus_to(&mut self, focus_node_id: usize) -> bool {
933 if Some(focus_node_id) == self.focus_node_id {
934 return false;
935 }
936
937 println!("Focussed node {focus_node_id}");
938
939 if let Some(id) = self.focus_node_id {
941 self.snapshot_node_and(id, |node| node.blur());
942 }
943
944 self.snapshot_node_and(focus_node_id, |node| node.focus());
946
947 self.focus_node_id = Some(focus_node_id);
948
949 true
950 }
951
952 pub fn active_node(&mut self) -> bool {
953 let Some(hover_node_id) = self.get_hover_node_id() else {
954 return false;
955 };
956
957 if let Some(active_node_id) = self.active_node_id {
958 if active_node_id == hover_node_id {
959 return true;
960 }
961 self.unactive_node();
962 }
963
964 let active_node_id = Some(hover_node_id);
965
966 let node_path = self.maybe_node_layout_ancestors(active_node_id);
967 for &id in node_path.iter() {
968 self.snapshot_node_and(id, |node| node.active());
969 }
970
971 self.active_node_id = active_node_id;
972
973 true
974 }
975
976 pub fn unactive_node(&mut self) -> bool {
977 let Some(active_node_id) = self.active_node_id.take() else {
978 return false;
979 };
980
981 let node_path = self.maybe_node_layout_ancestors(Some(active_node_id));
982 for &id in node_path.iter() {
983 self.snapshot_node_and(id, |node| node.unactive());
984 }
985
986 true
987 }
988
989 pub fn set_hover_to(&mut self, x: f32, y: f32) -> bool {
990 let hit = self.hit(x, y);
991 let hover_node_id = hit.map(|hit| hit.node_id);
992
993 if hover_node_id == self.hover_node_id {
995 return false;
996 }
997
998 let old_node_path = self.maybe_node_layout_ancestors(self.hover_node_id);
999 let new_node_path = self.maybe_node_layout_ancestors(hover_node_id);
1000 let same_count = old_node_path
1001 .iter()
1002 .zip(&new_node_path)
1003 .take_while(|(o, n)| o == n)
1004 .count();
1005 for &id in old_node_path.iter().skip(same_count) {
1006 self.snapshot_node_and(id, |node| node.unhover());
1007 }
1008 for &id in new_node_path.iter().skip(same_count) {
1009 self.snapshot_node_and(id, |node| node.hover());
1010 }
1011
1012 self.hover_node_id = hover_node_id;
1013
1014 let cursor = self.get_cursor().unwrap_or_default();
1016 self.shell_provider.set_cursor(cursor);
1017
1018 self.shell_provider.request_redraw();
1020
1021 true
1022 }
1023
1024 pub fn get_hover_node_id(&self) -> Option<usize> {
1025 self.hover_node_id
1026 }
1027
1028 pub fn set_viewport(&mut self, viewport: Viewport) {
1029 self.viewport = viewport;
1030 self.set_stylist_device(make_device(&self.viewport));
1031 self.scroll_viewport_by(0.0, 0.0); }
1033
1034 pub fn viewport(&self) -> &Viewport {
1035 &self.viewport
1036 }
1037
1038 pub fn viewport_mut(&mut self) -> ViewportMut<'_> {
1039 ViewportMut::new(self)
1040 }
1041
1042 pub fn zoom_by(&mut self, increment: f32) {
1043 *self.viewport.zoom_mut() += increment;
1044 self.set_viewport(self.viewport.clone());
1045 }
1046
1047 pub fn zoom_to(&mut self, zoom: f32) {
1048 *self.viewport.zoom_mut() = zoom;
1049 self.set_viewport(self.viewport.clone());
1050 }
1051
1052 pub fn get_viewport(&self) -> Viewport {
1053 self.viewport.clone()
1054 }
1055
1056 pub fn devtools(&self) -> &Devtools {
1057 &self.devtool_settings
1058 }
1059
1060 pub fn devtools_mut(&mut self) -> &mut Devtools {
1061 &mut self.devtool_settings
1062 }
1063
1064 pub fn set_stylist_device(&mut self, device: Device) {
1066 let origins = {
1067 let guard = &self.guard;
1068 let guards = StylesheetGuards {
1069 author: &guard.read(),
1070 ua_or_user: &guard.read(),
1071 };
1072 self.stylist.set_device(device, &guards)
1073 };
1074 self.stylist.force_stylesheet_origins_dirty(origins);
1075 }
1076
1077 pub fn stylist_device(&mut self) -> &Device {
1078 self.stylist.device()
1079 }
1080
1081 pub fn resolve_layout_children(&mut self) {
1083 resolve_layout_children_recursive(self, self.root_node().id);
1084
1085 fn resolve_layout_children_recursive(doc: &mut BaseDocument, node_id: usize) {
1086 let mut layout_children = Vec::new();
1088 let mut anonymous_block: Option<usize> = None;
1089 collect_layout_children(doc, node_id, &mut layout_children, &mut anonymous_block);
1090
1091 for child_id in layout_children.iter().copied() {
1093 resolve_layout_children_recursive(doc, child_id);
1094 doc.nodes[child_id].layout_parent.set(Some(node_id));
1095 }
1096
1097 *doc.nodes[node_id].layout_children.borrow_mut() = Some(layout_children.clone());
1098 *doc.nodes[node_id].paint_children.borrow_mut() = Some(layout_children);
1099 }
1101 }
1102
1103 pub fn resolve_layout(&mut self) {
1109 let size = self.stylist.device().au_viewport_size();
1110
1111 let available_space = taffy::Size {
1112 width: AvailableSpace::Definite(size.width.to_f32_px()),
1113 height: AvailableSpace::Definite(size.height.to_f32_px()),
1114 };
1115
1116 let root_element_id = taffy::NodeId::from(self.root_element().id);
1117
1118 taffy::compute_root_layout(self, root_element_id, available_space);
1121 taffy::round_layout(self, root_element_id);
1122
1123 }
1126
1127 pub fn set_document(&mut self, _content: String) {}
1128
1129 pub fn add_element(&mut self) {}
1130
1131 pub fn get_cursor(&self) -> Option<CursorIcon> {
1132 let node = &self.nodes[self.get_hover_node_id()?];
1134
1135 let style = node.primary_styles()?;
1136 let keyword = stylo_to_cursor_icon(style.clone_cursor().keyword);
1137
1138 if keyword != CursorIcon::Default {
1140 return Some(keyword);
1141 }
1142
1143 if node.is_text_node()
1145 || node
1146 .element_data()
1147 .is_some_and(|e| e.text_input_data().is_some())
1148 {
1149 return Some(CursorIcon::Text);
1150 }
1151
1152 let mut maybe_node = Some(node);
1154 while let Some(node) = maybe_node {
1155 if node.is_link() {
1156 return Some(CursorIcon::Pointer);
1157 }
1158
1159 maybe_node = node.layout_parent.get().map(|node_id| node.with(node_id));
1160 }
1161
1162 Some(CursorIcon::Default)
1164 }
1165
1166 pub fn scroll_node_by(&mut self, node_id: usize, x: f64, y: f64) {
1170 let Some(node) = self.nodes.get_mut(node_id) else {
1171 return;
1172 };
1173
1174 let is_html_or_body = node.data.downcast_element().is_some_and(|e| {
1175 let tag = &e.name.local;
1176 tag == "html" || tag == "body"
1177 });
1178
1179 let (can_x_scroll, can_y_scroll) = node
1180 .primary_styles()
1181 .map(|styles| {
1182 (
1183 matches!(styles.clone_overflow_x(), Overflow::Scroll | Overflow::Auto),
1184 matches!(styles.clone_overflow_y(), Overflow::Scroll | Overflow::Auto)
1185 || (styles.clone_overflow_y() == Overflow::Visible && is_html_or_body),
1186 )
1187 })
1188 .unwrap_or((false, false));
1189
1190 let new_x = node.scroll_offset.x - x;
1191 let new_y = node.scroll_offset.y - y;
1192
1193 let mut bubble_x = 0.0;
1194 let mut bubble_y = 0.0;
1195
1196 let scroll_width = node.final_layout.scroll_width() as f64;
1197 let scroll_height = node.final_layout.scroll_height() as f64;
1198
1199 if !can_x_scroll {
1201 bubble_x = x
1202 } else if new_x < 0.0 {
1203 bubble_x = -new_x;
1204 node.scroll_offset.x = 0.0;
1205 } else if new_x > scroll_width {
1206 bubble_x = scroll_width - new_x;
1207 node.scroll_offset.x = scroll_width;
1208 } else {
1209 node.scroll_offset.x = new_x;
1210 }
1211
1212 if !can_y_scroll {
1213 bubble_y = y
1214 } else if new_y < 0.0 {
1215 bubble_y = -new_y;
1216 node.scroll_offset.y = 0.0;
1217 } else if new_y > scroll_height {
1218 bubble_y = scroll_height - new_y;
1219 node.scroll_offset.y = scroll_height;
1220 } else {
1221 node.scroll_offset.y = new_y;
1222 }
1223
1224 if bubble_x != 0.0 || bubble_y != 0.0 {
1225 if let Some(parent) = node.parent {
1226 self.scroll_node_by(parent, bubble_x, bubble_y);
1227 } else {
1228 self.scroll_viewport_by(bubble_x, bubble_y);
1229 }
1230 }
1231 }
1232
1233 pub fn scroll_viewport_by(&mut self, x: f64, y: f64) {
1235 let content_size = self.root_element().final_layout.size;
1236 let new_scroll = (self.viewport_scroll.x - x, self.viewport_scroll.y - y);
1237 let window_width = self.viewport.window_size.0 as f64 / self.viewport.scale() as f64;
1238 let window_height = self.viewport.window_size.1 as f64 / self.viewport.scale() as f64;
1239 self.viewport_scroll.x = f64::max(
1240 0.0,
1241 f64::min(new_scroll.0, content_size.width as f64 - window_width),
1242 );
1243 self.viewport_scroll.y = f64::max(
1244 0.0,
1245 f64::min(new_scroll.1, content_size.height as f64 - window_height),
1246 )
1247 }
1248
1249 pub fn viewport_scroll(&self) -> kurbo::Point {
1250 self.viewport_scroll
1251 }
1252
1253 pub fn set_viewport_scroll(&mut self, scroll: kurbo::Point) {
1254 self.viewport_scroll = scroll;
1255 }
1256
1257 pub fn visit<F>(&self, mut visit: F)
1258 where
1259 F: FnMut(usize, &Node),
1260 {
1261 TreeTraverser::new(self).for_each(|node_id| visit(node_id, &self.nodes[node_id]));
1262 }
1263
1264 pub fn node_chain(&self, node_id: usize) -> Vec<usize> {
1266 let mut chain = Vec::with_capacity(16);
1267 chain.push(node_id);
1268 chain.extend(
1269 AncestorTraverser::new(self, node_id).filter(|id| self.nodes[*id].is_element()),
1270 );
1271 chain
1272 }
1273}
1274
1275impl AsRef<BaseDocument> for BaseDocument {
1276 fn as_ref(&self) -> &BaseDocument {
1277 self
1278 }
1279}
1280
1281impl AsMut<BaseDocument> for BaseDocument {
1282 fn as_mut(&mut self) -> &mut BaseDocument {
1283 self
1284 }
1285}