Skip to main content

bliss_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, Copy, 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::ShadowRoot { host } => println!("#shadow-root (host={host}) {id}"),
75
76        NodeData::Element(data) => {
77            print!("<{} {id}", data.name.local);
78            for attr in data.attrs.iter() {
79                print!(" {}=\"{}\"", attr.name.local, attr.value);
80            }
81            if !node.children.is_empty() {
82                println!(">");
83            } else {
84                println!("/>");
85            }
86        } // NodeData::Doctype {
87          //     ref name,
88          //     ref public_id,
89          //     ref system_id,
90          // } => println!("<!DOCTYPE {} \"{}\" \"{}\">", name, public_id, system_id),
91          // NodeData::ProcessingInstruction { .. } => unreachable!(),
92    }
93
94    if !node.children.is_empty() {
95        for child_id in node.children.iter() {
96            walk_tree(indent + 2, node.with(*child_id));
97        }
98
99        if let NodeData::Element(data) = &node.data {
100            println!("{}</{}>", " ".repeat(indent), data.name.local);
101        }
102    }
103}
104
105#[cfg(feature = "svg")]
106pub(crate) fn parse_svg(source: &[u8]) -> Result<usvg::Tree, usvg::Error> {
107    let options = usvg::Options {
108        fontdb: Arc::clone(&*FONT_DB),
109        ..Default::default()
110    };
111
112    let tree = usvg::Tree::from_data(source, &options)?;
113    Ok(tree)
114}
115
116pub trait ToColorColor {
117    /// Converts a color into the `AlphaColor<Srgb>` type from the `color` crate
118    fn as_color_color(&self) -> Color;
119}
120impl ToColorColor for AbsoluteColor {
121    fn as_color_color(&self) -> Color {
122        Color::new(
123            *self
124                .to_color_space(style::color::ColorSpace::Srgb)
125                .raw_components(),
126        )
127    }
128}
129
130/// Creates an markup5ever::QualName.
131/// Given a local name and an optional namespace
132#[macro_export]
133macro_rules! qual_name {
134    ($local:tt $(, $ns:ident)?) => {
135        $crate::QualName {
136            prefix: None,
137            ns: $crate::ns!($($ns)?),
138            local: $crate::local_name!($local),
139        }
140    };
141}