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#[derive(Clone, Debug, Copy, Eq, PartialEq)]
26pub struct Point<T> {
27 pub x: T,
29 pub y: T,
31}
32
33impl Point<f64> {
34 pub const ZERO: Self = Point { x: 0.0, y: 0.0 };
35}
36
37pub fn walk_tree(indent: usize, node: &Node) {
39 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 } }
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 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#[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}