use log::warn;
use roxmltree::Node;
use svgtypes::{Length, LengthListParser};
use super::ConversionVisitor;
use crate::Turtle;
pub const CSS_DEFAULT_DPI: f64 = 96.;
#[derive(Clone, Copy)]
pub enum DimensionHint {
Horizontal,
Vertical,
Other,
}
impl<'a, T: Turtle> ConversionVisitor<'a, T> {
pub fn length_attr_to_user_units(&self, node: &Node, attr: &str) -> Option<f64> {
let l = node
.attribute(attr)
.map(LengthListParser::from)
.and_then(|mut parser| parser.next())
.transpose()
.ok()
.flatten()?;
Some(self.length_to_user_units(
l,
match attr {
"x" | "x1" | "x2" | "cx" | "rx" | "width" => DimensionHint::Horizontal,
"y" | "y1" | "y2" | "cy" | "ry" | "height" => DimensionHint::Vertical,
_ => DimensionHint::Other,
},
))
}
pub fn length_to_user_units(&self, l: Length, hint: DimensionHint) -> f64 {
use svgtypes::LengthUnit::*;
use uom::si::{f64::Length, length::*};
match l.unit {
Cm => Length::new::<centimeter>(l.number).get::<inch>() * CSS_DEFAULT_DPI,
Mm => Length::new::<millimeter>(l.number).get::<inch>() * CSS_DEFAULT_DPI,
In => Length::new::<inch>(l.number).get::<inch>() * CSS_DEFAULT_DPI,
Pc => Length::new::<pica_computer>(l.number).get::<inch>() * CSS_DEFAULT_DPI,
Pt => Length::new::<point_computer>(l.number).get::<inch>() * CSS_DEFAULT_DPI,
Px | None => l.number,
Em | Ex => {
warn!("Converting from em/ex to millimeters assumes 1em/ex = 16px");
16. * l.number
}
Percent => {
if let Some([width, height]) = self.viewport_dim_stack.last() {
let scale = match hint {
DimensionHint::Horizontal => *width,
DimensionHint::Vertical => *height,
DimensionHint::Other => {
(width.powi(2) + height.powi(2)).sqrt() / 2.0_f64.sqrt()
}
};
l.number / 100. * scale
} else {
warn!("A percentage without an established viewport is not valid!");
l.number / 100.
}
}
}
}
}