//! Small SVG string helpers shared by the card and the decorations.
/// Escape text for SVG character data and attribute values. Characters XML
/// 1.0 forbids outright (most C0 controls) are dropped, since a single one
/// would make the whole document unparseable.
pub fn esc(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for ch in s.chars() {
match ch {
'&' => out.push_str("&"),
'<' => out.push_str("<"),
'>' => out.push_str(">"),
'"' => out.push_str("""),
'\'' => out.push_str("'"),
'\t' | '\n' | '\r' => out.push(ch),
c if (c as u32) < 0x20 || c == '\u{fffe}' || c == '\u{ffff}' => {}
c => out.push(c),
}
}
out
}
/// Path data for a rectangle with independent top and bottom corner radii.
pub fn round_path(x: f32, y: f32, w: f32, h: f32, rt: f32, rb: f32) -> String {
let rt = rt.min(w / 2.0).min(h / 2.0).max(0.0);
let rb = rb.min(w / 2.0).min(h / 2.0).max(0.0);
let (x1, y1) = (x + w, y + h);
format!(
"M{} {y}H{}A{rt} {rt} 0 0 1 {x1} {}V{}A{rb} {rb} 0 0 1 {} {y1}H{}A{rb} {rb} 0 0 1 {x} {}V{}A{rt} {rt} 0 0 1 {} {y}Z",
x + rt,
x1 - rt,
y + rt,
y1 - rb,
x1 - rb,
x + rb,
y1 - rb,
y + rt,
x + rt,
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn esc_drops_xml_illegal_controls() {
assert_eq!(esc("a\u{0}b<&>\u{1b}"), "ab<&>");
}
}
neiam
/bismuth
MOTHER-FUCKING-BISMUTH
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
1.5 KiB · text
History
487bb12