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;
60pub mod release;
61mod resolve;
62mod select;
63mod selection;
64#[cfg(feature = "shadow-dom")]
65mod shadow;
66pub mod stash_policy;
67/// Implementations that interact with servo's style engine
68mod stylo;
69mod stylo_to_cursor_icon;
70mod stylo_to_kurbo;
71mod stylo_to_parley;
72mod traversal;
73/// Versioned storage for the nodes of the DOM tree.
74mod tree;
75
76mod url;
77
78pub use stylo_to_kurbo::resolve_2d_transform;
79
80pub mod net;
81pub mod util;
82
83#[cfg(feature = "accessibility")]
84pub mod accessibility;
85/// The role vocabulary [`accessibility::implicit_role`] answers in.
86///
87/// Re-exported rather than left to the caller to depend on: a second copy of
88/// `accesskit` in the graph makes its `Role` a different type from this one,
89/// and the error that produces names the same enum on both sides of a
90/// mismatch. Anything consuming the role rules gets the vocabulary from the
91/// crate that owns them.
92#[cfg(feature = "accessibility")]
93pub use accesskit;
94
95#[cfg(feature = "custom-widget")]
96pub use crate::node::Widget;
97
98#[cfg(feature = "shadow-dom")]
99pub use crate::node::{
100    CustomElement, CustomElementCtx, CustomElementDefinition, CustomElementRegistry,
101    ShadowRootData, ShadowRootMode,
102};
103pub use blitz_traits::node_id::NodeId;
104pub use config::{DocumentConfig, StyleThreading};
105pub use document::{
106    AnimationPacing, BaseDocument, DocGuard, DocGuardMut, Document, PlainDocument,
107    PreClickActivation,
108};
109/// Per-resolve layout counters. Present only with `log-phase-times`, which is
110/// the same feature that pays for the counting.
111#[cfg(feature = "log-phase-times")]
112pub use layout::layout_counters;
113pub use markup5ever::{
114    LocalName, Namespace, NamespaceStaticSet, Prefix, PrefixStaticSet, QualName, local_name,
115    namespace_prefix, namespace_url, ns,
116};
117pub use mutation_record::DomMutation;
118pub use mutator::DocumentMutator;
119pub use node::{Attribute, DocumentData, ElementData, Node, NodeData, SelectData, TextNodeData};
120pub use paint_damage::PaintDamage;
121pub use range::{LiveRange, RangeBoundary, RangeBounds, RangeContent};
122// Re-exported because `PaintDamage` takes and returns `kurbo::Rect` across the
123// crate boundary. A consumer that pulls kurbo in itself and lands on a
124// different version gets a type mismatch on a name that looks identical.
125pub use kurbo;
126pub use parley::FontContext;
127pub use tree::NodeTree;
128
129/// Convert a Blitz [`NodeId`] into a [`taffy::NodeId`] (which wraps a `u64`).
130#[inline]
131pub fn taffy_node_id(id: NodeId) -> taffy::NodeId {
132    taffy::NodeId::from(id.as_u64())
133}
134
135/// Convert a [`taffy::NodeId`] produced by [`taffy_node_id`] back into a Blitz [`NodeId`].
136#[inline]
137pub fn dom_node_id(id: taffy::NodeId) -> NodeId {
138    NodeId::from_u64(u64::from(id))
139}
140pub use style::Atom;
141pub use style::invalidation::element::restyle_hints::RestyleHint;
142pub use style::media_queries::MediaType;
143pub type SelectorList = selectors::SelectorList<style::selector_parser::SelectorImpl>;
144pub use events::{EventDriver, EventHandler, NoopEventHandler};
145pub use html::{DummyHtmlParserProvider, HtmlParserProvider};
146pub use util::{Point, decode_font_bytes};
147
148/// Convenience builder for the one-font case: produces a [`FontContext`] with
149/// system-font discovery disabled and the supplied font registered as the
150/// fallback for every generic family. The standard setup for WASM, where
151/// browsers don't expose system fonts. WOFF/WOFF2 inputs are decoded
152/// automatically.
153pub fn build_single_font_ctx(font_data: &[u8]) -> FontContext {
154    use parley::fontique::{Blob, Collection, CollectionOptions, GenericFamily, SourceCache};
155    use std::sync::Arc;
156
157    let mut ctx = FontContext {
158        source_cache: SourceCache::new_shared(),
159        collection: Collection::new(CollectionOptions {
160            shared: false,
161            system_fonts: false,
162        }),
163    };
164    let decoded = decode_font_bytes(font_data).into_owned();
165    let registered = ctx
166        .collection
167        .register_fonts(Blob::new(Arc::new(decoded) as _), None);
168    let family_ids: Vec<_> = registered.iter().map(|(id, _)| *id).collect();
169    for generic in [
170        GenericFamily::SansSerif,
171        GenericFamily::Serif,
172        GenericFamily::Monospace,
173        GenericFamily::SystemUi,
174    ] {
175        ctx.collection
176            .append_generic_families(generic, family_ids.iter().copied());
177    }
178    ctx
179}