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#[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::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 } }
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 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#[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}