Skip to main content

apace_dom/
lib.rs

1//! The core DOM abstraction in Apace
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/apace-html/latest/apace_html/struct.HtmlDocument.html) from the [apace-html](https://docs.rs/apace-html) crate.
7//!    Allows you to parse HTML (or XHTML) into a Apace [`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 ([apace-html](https://docs.rs/apace-html)), networking ([apace-net](https://docs.rs/apace-html)),
14//! rendering ([apace-paint](https://docs.rs/apace-paint)) and windowing ([apace-shell](https://docs.rs/apace-shell)).
15//!
16//! Most of the functionality in this crates is provided through the  struct.
17//!
18//! `apace-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;
43/// CSSOM stylesheet access (`document.styleSheets`, `CSSStyleSheet`, `CSSRule`)
44mod cssom;
45mod debug;
46mod events;
47mod font_metrics;
48mod form;
49mod html;
50/// Loading of `<iframe>` elements into sub-documents.
51mod iframe;
52/// Integration of takia and the DOM.
53mod layout;
54#[cfg(all(test, feature = "system-fonts"))]
55mod layout_drop_tests;
56#[cfg(test)]
57mod layout_move_tests;
58mod mutator;
59mod placeholder;
60#[cfg(all(test, feature = "system-fonts"))]
61mod placeholder_tests;
62pub mod profile;
63mod query_selector;
64mod radio;
65#[cfg(test)]
66mod radio_tests;
67mod resolve;
68mod resource_queue;
69mod resources;
70#[cfg(all(test, feature = "system-fonts"))]
71mod style_damage_tests;
72pub use resources::{
73    ImageLoadEvent, ImageLoadStatus, ImageRequestId, ResourceLimits, ResourceStats,
74};
75/// Computation of resolved CSS property values (`getComputedStyle()`)
76mod resolved_style;
77/// Scrolling of nodes and the viewport, and scroll animations.
78mod scrolling;
79mod selection;
80/// Implementations that interact with servo's style engine
81mod stylo;
82mod stylo_device;
83mod stylo_to_cursor_icon;
84mod stylo_to_kurbo;
85mod stylo_to_parley;
86mod top_layer;
87pub mod traversal;
88/// Versioned storage for the nodes of the DOM tree.
89mod tree;
90pub use top_layer::{MAX_TOP_LAYERS, TopLayer, TopLayerConfig, TopLayerError};
91#[cfg(all(test, feature = "system-fonts"))]
92mod top_layer_tests;
93
94mod url;
95
96pub use cssom::{CssRuleInfo, CssomError};
97pub use resolved_style::{
98    css_property_is_supported, parse_transform_matrix, resolved_style_property_names,
99};
100pub use stylo_to_kurbo::resolve_2d_transform;
101
102pub mod net;
103pub mod util;
104
105#[cfg(feature = "accessibility")]
106mod accessibility;
107
108pub use crate::layout::paint_tree::{HoistedPaintChild, StackingContext, hoisted_child_position};
109pub use crate::layout::replaced::IntrinsicSizes;
110pub use crate::layout::text_transform::{full_size_kana, full_width};
111#[cfg(feature = "custom-widget")]
112pub use crate::node::Widget;
113
114pub use apace_traits::node_id::NodeId;
115// Re-export takia: it is part of apace-dom's public API (e.g. `Node::style`,
116// `Node::final_layout`)
117pub use config::{DocumentConfig, StyleThreading};
118pub use document::{
119    BaseDocument, BoundingRect, DocGuard, DocGuardMut, Document, PlainDocument, UserAgentStylesheet,
120};
121pub use markup5ever::{
122    LocalName, Namespace, NamespaceStaticSet, Prefix, PrefixStaticSet, QualName, local_name,
123    namespace_prefix, namespace_url, ns,
124};
125pub use mutator::DocumentMutator;
126pub use node::{Attribute, DocumentData, ElementData, Node, NodeData, TextNodeData};
127pub use parley::FontContext;
128pub use scrolling::{ScrollBehavior, ScrollLogicalPosition};
129pub use tree::NodeTree;
130
131/// Convert a Apace [`NodeId`] into a [`takia::NodeId`] (which wraps a `u64`).
132#[inline]
133pub fn takia_node_id(id: NodeId) -> takia::NodeId {
134    takia::NodeId::from(id.as_u64())
135}
136
137/// Convert a [`takia::NodeId`] produced by [`takia_node_id`] back into a Apace [`NodeId`].
138#[inline]
139pub fn dom_node_id(id: takia::NodeId) -> NodeId {
140    NodeId::from_u64(u64::from(id))
141}
142pub use style::Atom;
143pub use style::invalidation::element::restyle_hints::RestyleHint;
144pub use style::media_queries::MediaType;
145pub use style::stylist::RegisterCustomPropertyResult;
146pub type SelectorList = selectors::SelectorList<style::selector_parser::SelectorImpl>;
147pub use events::{EventDriver, EventHandler, NoopEventHandler};
148pub use html::{DummyHtmlParserProvider, HtmlParserProvider};
149pub use util::{Point, decode_font_bytes};
150
151/// Convenience builder for the one-font case: produces a [`FontContext`] with
152/// system-font discovery disabled and the supplied font registered as the
153/// fallback for every generic family. The standard setup for WASM, where
154/// browsers don't expose system fonts. WOFF/WOFF2 inputs are decoded
155/// automatically.
156pub fn build_single_font_ctx(font_data: &[u8]) -> FontContext {
157    use parley::fontique::{Blob, Collection, CollectionOptions, GenericFamily, SourceCache};
158    use std::sync::Arc;
159
160    let mut ctx = FontContext {
161        source_cache: SourceCache::new_shared(),
162        collection: Collection::new(CollectionOptions {
163            shared: false,
164            system_fonts: false,
165        }),
166    };
167    let decoded = decode_font_bytes(font_data).into_owned();
168    let registered = ctx
169        .collection
170        .register_fonts(Blob::new(Arc::new(decoded) as _), None);
171    let family_ids: Vec<_> = registered.iter().map(|(id, _)| *id).collect();
172    for generic in [
173        GenericFamily::SansSerif,
174        GenericFamily::Serif,
175        GenericFamily::Monospace,
176        GenericFamily::SystemUi,
177    ] {
178        ctx.collection
179            .append_generic_families(generic, family_ids.iter().copied());
180    }
181    ctx
182}
183
184#[cfg(test)]
185mod indeterminate_tests;
186
187#[cfg(test)]
188mod animation_retirement_tests;
189#[cfg(test)]
190mod layout_contents_tests;