Skip to main content

use_svg/
size.rs

1use crate::document::{extract_height, extract_width};
2
3#[derive(Debug, Clone, Default, PartialEq)]
4pub struct SvgSize {
5    pub width: Option<f64>,
6    pub height: Option<f64>,
7    pub width_unit: Option<String>,
8    pub height_unit: Option<String>,
9}
10
11#[must_use]
12pub fn extract_size(input: &str) -> SvgSize {
13    let width = extract_width(input);
14    let height = extract_height(input);
15
16    let (width, width_unit) = width
17        .as_deref()
18        .and_then(parse_dimension)
19        .map_or((None, None), |(value, unit)| (Some(value), unit));
20    let (height, height_unit) = height
21        .as_deref()
22        .and_then(parse_dimension)
23        .map_or((None, None), |(value, unit)| (Some(value), unit));
24
25    SvgSize {
26        width,
27        height,
28        width_unit,
29        height_unit,
30    }
31}
32
33pub(crate) fn parse_dimension(value: &str) -> Option<(f64, Option<String>)> {
34    let trimmed = value.trim();
35
36    if trimmed.is_empty() {
37        return None;
38    }
39
40    for split in (1..=trimmed.len()).rev() {
41        if !trimmed.is_char_boundary(split) {
42            continue;
43        }
44
45        let number = trimmed[..split].trim();
46        let unit = trimmed[split..].trim();
47        let Ok(parsed) = number.parse::<f64>() else {
48            continue;
49        };
50
51        if !parsed.is_finite() {
52            return None;
53        }
54
55        return Some((parsed, (!unit.is_empty()).then(|| unit.to_string())));
56    }
57
58    None
59}