blitz_dom/
util.rs

1use crate::node::{Node, NodeData};
2use color::{AlphaColor, Srgb};
3use style::color::AbsoluteColor;
4
5pub type Color = AlphaColor<Srgb>;
6
7#[cfg(feature = "svg")]
8use std::sync::{Arc, LazyLock};
9#[cfg(feature = "svg")]
10use usvg::fontdb;
11#[cfg(feature = "svg")]
12pub(crate) static FONT_DB: LazyLock<Arc<fontdb::Database>> = LazyLock::new(|| {
13    let mut db = fontdb::Database::new();
14    db.load_system_fonts();
15    Arc::new(db)
16});
17
18#[derive(Clone, Debug)]
19pub enum ImageType {
20    Image,
21    Background(usize),
22}
23
24/// A point
25#[derive(Clone, Debug, Copy, Eq, PartialEq)]
26pub struct Point<T> {
27    /// The x coordinate
28    pub x: T,
29    /// The y coordinate
30    pub y: T,
31}
32
33impl Point<f64> {
34    pub const ZERO: Self = Point { x: 0.0, y: 0.0 };
35}
36
37// Debug print an RcDom
38pub fn walk_tree(indent: usize, node: &Node) {
39    // Skip all-whitespace text nodes entirely
40    if let NodeData::Text(data) = &node.data {
41        if data.content.chars().all(|c| c.is_ascii_whitespace()) {
42            return;
43        }
44    }
45
46    print!("{}", " ".repeat(indent));
47    let id = node.id;
48    match &node.data {
49        NodeData::Document => println!("#Document {id}"),
50
51        NodeData::Text(data) => {
52            if data.content.chars().all(|c| c.is_ascii_whitespace()) {
53                println!("{id} #text: <whitespace>");
54            } else {
55                let content = data.content.trim();
56                if content.len() > 10 {
57                    println!(
58                        "#text {id}: {}...",
59                        content
60                            .split_at(content.char_indices().take(10).last().unwrap().0)
61                            .0
62                            .escape_default()
63                    )
64                } else {
65                    println!("#text {id}: {}", data.content.trim().escape_default())
66                }
67            }
68        }
69
70        NodeData::Comment => println!("<!-- COMMENT {id} -->"),
71
72        NodeData::AnonymousBlock(_) => println!("{id} AnonymousBlock"),
73
74        NodeData::Element(data) => {
75            print!("<{} {id}", data.name.local);
76            for attr in data.attrs.iter() {
77                print!(" {}=\"{}\"", attr.name.local, attr.value);
78            }
79            if !node.children.is_empty() {
80                println!(">");
81            } else {
82                println!("/>");
83            }
84        } // NodeData::Doctype {
85          //     ref name,
86          //     ref public_id,
87          //     ref system_id,
88          // } => println!("<!DOCTYPE {} \"{}\" \"{}\">", name, public_id, system_id),
89          // NodeData::ProcessingInstruction { .. } => unreachable!(),
90    }
91
92    if !node.children.is_empty() {
93        for child_id in node.children.iter() {
94            walk_tree(indent + 2, node.with(*child_id));
95        }
96
97        if let NodeData::Element(data) = &node.data {
98            println!("{}</{}>", " ".repeat(indent), data.name.local);
99        }
100    }
101}
102
103#[cfg(feature = "svg")]
104pub(crate) fn parse_svg(source: &[u8]) -> Result<usvg::Tree, usvg::Error> {
105    let options = usvg::Options {
106        fontdb: Arc::clone(&*FONT_DB),
107        ..Default::default()
108    };
109
110    let tree = usvg::Tree::from_data(source, &options)?;
111    Ok(tree)
112}
113
114pub trait ToColorColor {
115    /// Converts a color into the `AlphaColor<Srgb>` type from the `color` crate
116    fn as_color_color(&self) -> Color;
117}
118impl ToColorColor for AbsoluteColor {
119    fn as_color_color(&self) -> Color {
120        Color::new(
121            *self
122                .to_color_space(style::color::ColorSpace::Srgb)
123                .raw_components(),
124        )
125    }
126}
127
128/// Creates an markup5ever::QualName.
129/// Given a local name and an optional namespace
130#[macro_export]
131macro_rules! qual_name {
132    ($local:tt $(, $ns:ident)?) => {
133        $crate::QualName {
134            prefix: None,
135            ns: $crate::ns!($($ns)?),
136            local: $crate::local_name!($local),
137        }
138    };
139}