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// Debug print an RcDom
25pub fn walk_tree(indent: usize, node: &Node) {
26    // Skip all-whitespace text nodes entirely
27    if let NodeData::Text(data) = &node.data {
28        if data.content.chars().all(|c| c.is_ascii_whitespace()) {
29            return;
30        }
31    }
32
33    print!("{}", " ".repeat(indent));
34    let id = node.id;
35    match &node.data {
36        NodeData::Document => println!("#Document {id}"),
37
38        NodeData::Text(data) => {
39            if data.content.chars().all(|c| c.is_ascii_whitespace()) {
40                println!("{id} #text: <whitespace>");
41            } else {
42                let content = data.content.trim();
43                if content.len() > 10 {
44                    println!(
45                        "#text {id}: {}...",
46                        content
47                            .split_at(content.char_indices().take(10).last().unwrap().0)
48                            .0
49                            .escape_default()
50                    )
51                } else {
52                    println!("#text {id}: {}", data.content.trim().escape_default())
53                }
54            }
55        }
56
57        NodeData::Comment => println!("<!-- COMMENT {id} -->"),
58
59        NodeData::AnonymousBlock(_) => println!("{id} AnonymousBlock"),
60
61        NodeData::Element(data) => {
62            print!("<{} {id}", data.name.local);
63            for attr in data.attrs.iter() {
64                print!(" {}=\"{}\"", attr.name.local, attr.value);
65            }
66            if !node.children.is_empty() {
67                println!(">");
68            } else {
69                println!("/>");
70            }
71        } // NodeData::Doctype {
72          //     ref name,
73          //     ref public_id,
74          //     ref system_id,
75          // } => println!("<!DOCTYPE {} \"{}\" \"{}\">", name, public_id, system_id),
76          // NodeData::ProcessingInstruction { .. } => unreachable!(),
77    }
78
79    if !node.children.is_empty() {
80        for child_id in node.children.iter() {
81            walk_tree(indent + 2, node.with(*child_id));
82        }
83
84        if let NodeData::Element(data) = &node.data {
85            println!("{}</{}>", " ".repeat(indent), data.name.local);
86        }
87    }
88}
89
90#[cfg(feature = "svg")]
91pub(crate) fn parse_svg(source: &[u8]) -> Result<usvg::Tree, usvg::Error> {
92    let options = usvg::Options {
93        fontdb: Arc::clone(&*FONT_DB),
94        ..Default::default()
95    };
96
97    let tree = usvg::Tree::from_data(source, &options)?;
98    Ok(tree)
99}
100
101pub trait ToColorColor {
102    /// Converts a color into the `AlphaColor<Srgb>` type from the `color` crate
103    fn as_color_color(&self) -> Color;
104}
105impl ToColorColor for AbsoluteColor {
106    fn as_color_color(&self) -> Color {
107        Color::new(
108            *self
109                .to_color_space(style::color::ColorSpace::Srgb)
110                .raw_components(),
111        )
112    }
113}
114
115/// Creates an markup5ever::QualName.
116/// Given a local name and an optional namespace
117#[macro_export]
118macro_rules! qual_name {
119    ($local:tt $(, $ns:ident)?) => {
120        $crate::QualName {
121            prefix: None,
122            ns: $crate::ns!($($ns)?),
123            local: $crate::local_name!($local),
124        }
125    };
126}