Skip to main content

blitz_dom/
lib.rs

1//! The core DOM abstraction in Blitz
2//!
3//! This crate implements a flexible headless DOM ([`BaseDocument`]), which is designed to emebedded in and "driven" by external code. Most users will want
4//! to use a wrapper:
5//!
6//!  - [`HtmlDocument`](https://docs.rs/blitz-html/latest/blitz_html/struct.HtmlDocument.html) from the [blitz-html](https://docs.rs/blitz-html) crate.
7//!    Allows you to parse HTML (or XHTML) into a Blitz [`BaseDocument`], and can be combined with a markdown-to-html converter like [comrak](https://docs.rs/comrak)
8//!    or [pulldown-cmark](https://docs.rs/pulldown-cmark)) to render/process markdown.
9//!  - [`DioxusDocument`](https://docs.rs/dioxus-native/latest/dioxus_native/struct.DioxusDocument.html) from the [dioxus-native](https://docs.rs/dioxus-native) crate.
10//!    Combines a [`BaseDocument`] with a Dioxus `VirtualDom` to enable dynamic rendering and event handling.
11//!
12//! It includes: A DOM tree respresentation, CSS parsing and resolution, layout and event handling. Additional functionality is available in
13//! separate crates, including html parsing ([blitz-html](https://docs.rs/blitz-html)), networking ([blitz-net](https://docs.rs/blitz-html)),
14//! rendering ([blitz-paint](https://docs.rs/blitz-paint)) and windowing ([blitz-shell](https://docs.rs/blitz-shell)).
15//!
16//! Most of the functionality in this crates is provided through the  struct.
17//!
18//! `blitz-dom` has a native Rust API that is designed for higher-level abstractions to be built on top (although it can also be used directly).
19//!
20//! The goal behind this crate is that any implementor can interact with the DOM and render it out using any renderer
21//! they want.
22//!
23
24#![allow(clippy::collapsible_if)]
25
26// TODO: Document features
27// ## Feature flags
28//  - `default`: Enables the features listed below.
29//  - `tracing`: Enables tracing support.
30
31pub const DEFAULT_CSS: &str = include_str!("../assets/default.css");
32pub const BULLET_FONT: &[u8] = include_bytes!("../assets/moz-bullet-font.otf");
33
34/// The DOM implementation.
35///
36/// This is the primary entry point for this crate.
37mod document;
38
39/// The nodes themsleves, and their data.
40pub mod node;
41
42mod config;
43mod debug;
44mod events;
45pub mod font_fallback;
46mod font_metrics;
47mod form;
48mod html;
49/// Loading of `<iframe>` elements into sub-documents.
50mod iframe;
51/// Integration of taffy and the DOM.
52mod layout;
53mod mutation_record;
54mod mutator;
55pub mod paint_damage;
56/// Engine-backed CSSOM operations used by script bindings.
57pub mod platform;
58mod query_selector;
59pub mod range;
60mod resolve;
61mod select;
62mod selection;
63#[cfg(feature = "shadow-dom")]
64mod shadow;
65/// Implementations that interact with servo's style engine
66mod stylo;
67mod stylo_to_cursor_icon;
68mod stylo_to_kurbo;
69mod stylo_to_parley;
70mod traversal;
71/// Versioned storage for the nodes of the DOM tree.
72mod tree;
73
74mod url;
75
76pub use stylo_to_kurbo::resolve_2d_transform;
77
78pub mod net;
79pub mod util;
80
81#[cfg(feature = "accessibility")]
82pub mod accessibility;
83/// The role vocabulary [`accessibility::implicit_role`] answers in.
84///
85/// Re-exported rather than left to the caller to depend on: a second copy of
86/// `accesskit` in the graph makes its `Role` a different type from this one,
87/// and the error that produces names the same enum on both sides of a
88/// mismatch. Anything consuming the role rules gets the vocabulary from the
89/// crate that owns them.
90#[cfg(feature = "accessibility")]
91pub use accesskit;
92
93#[cfg(feature = "custom-widget")]
94pub use crate::node::Widget;
95
96#[cfg(feature = "shadow-dom")]
97pub use crate::node::{
98    CustomElement, CustomElementCtx, CustomElementDefinition, CustomElementRegistry,
99    ShadowRootData, ShadowRootMode,
100};
101pub use blitz_traits::node_id::NodeId;
102pub use config::{DocumentConfig, StyleThreading};
103pub use document::{
104    AnimationPacing, BaseDocument, DocGuard, DocGuardMut, Document, PlainDocument,
105    PreClickActivation,
106};
107/// Per-resolve layout counters. Present only with `log-phase-times`, which is
108/// the same feature that pays for the counting.
109#[cfg(feature = "log-phase-times")]
110pub use layout::layout_counters;
111pub use markup5ever::{
112    LocalName, Namespace, NamespaceStaticSet, Prefix, PrefixStaticSet, QualName, local_name,
113    namespace_prefix, namespace_url, ns,
114};
115pub use mutation_record::DomMutation;
116pub use mutator::DocumentMutator;
117pub use node::{Attribute, DocumentData, ElementData, Node, NodeData, SelectData, TextNodeData};
118pub use paint_damage::PaintDamage;
119pub use range::{LiveRange, RangeBoundary, RangeBounds, RangeContent};
120// Re-exported because `PaintDamage` takes and returns `kurbo::Rect` across the
121// crate boundary. A consumer that pulls kurbo in itself and lands on a
122// different version gets a type mismatch on a name that looks identical.
123pub use kurbo;
124pub use parley::FontContext;
125pub use tree::NodeTree;
126
127/// Convert a Blitz [`NodeId`] into a [`taffy::NodeId`] (which wraps a `u64`).
128#[inline]
129pub fn taffy_node_id(id: NodeId) -> taffy::NodeId {
130    taffy::NodeId::from(id.as_u64())
131}
132
133/// Convert a [`taffy::NodeId`] produced by [`taffy_node_id`] back into a Blitz [`NodeId`].
134#[inline]
135pub fn dom_node_id(id: taffy::NodeId) -> NodeId {
136    NodeId::from_u64(u64::from(id))
137}
138pub use style::Atom;
139pub use style::invalidation::element::restyle_hints::RestyleHint;
140pub use style::media_queries::MediaType;
141pub type SelectorList = selectors::SelectorList<style::selector_parser::SelectorImpl>;
142pub use events::{EventDriver, EventHandler, NoopEventHandler};
143pub use html::{DummyHtmlParserProvider, HtmlParserProvider};
144pub use util::{Point, decode_font_bytes};
145
146/// Convenience builder for the one-font case: produces a [`FontContext`] with
147/// system-font discovery disabled and the supplied font registered as the
148/// fallback for every generic family. The standard setup for WASM, where
149/// browsers don't expose system fonts. WOFF/WOFF2 inputs are decoded
150/// automatically.
151pub fn build_single_font_ctx(font_data: &[u8]) -> FontContext {
152    use parley::fontique::{Blob, Collection, CollectionOptions, GenericFamily, SourceCache};
153    use std::sync::Arc;
154
155    let mut ctx = FontContext {
156        source_cache: SourceCache::new_shared(),
157        collection: Collection::new(CollectionOptions {
158            shared: false,
159            system_fonts: false,
160        }),
161    };
162    let decoded = decode_font_bytes(font_data).into_owned();
163    let registered = ctx
164        .collection
165        .register_fonts(Blob::new(Arc::new(decoded) as _), None);
166    let family_ids: Vec<_> = registered.iter().map(|(id, _)| *id).collect();
167    for generic in [
168        GenericFamily::SansSerif,
169        GenericFamily::Serif,
170        GenericFamily::Monospace,
171        GenericFamily::SystemUi,
172    ] {
173        ctx.collection
174            .append_generic_families(generic, family_ids.iter().copied());
175    }
176    ctx
177}