//! Gradient defs: text gradients span the laid-out text, stroke gradients the stroked area, //! identical gradients share a def named after their swatch, and midpoints survive re-import. // Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md › Robustness). #![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] use vectorcraft_color::{Color, Gradient, GradientKind, GradientPaint, GradientStop, Paint}; use vectorcraft_doc::{Appearance, CharStyle, Document, Node, NodeKind, TextObject}; use vectorcraft_geom::{Point, Rect, shapes}; use vectorcraft_svg::{ExportOptions, export, import}; fn black_to_white() -> GradientPaint { GradientPaint::new(Gradient { kind: GradientKind::Linear, stops: vec![GradientStop::new(0.0, Color::BLACK), GradientStop::new(1.0, Color::WHITE)], }) } fn doc_with(nodes: impl FnOnce(&mut Document) -> Vec) -> Document { let mut d = Document::new(300.0, 200.0); let l = d.layers[0].id; for n in nodes(&mut d) { d.insert(Some(l), usize::MAX, n).unwrap(); } d } /// The value of `name` on the first element whose tag starts with `tag`. fn attr(svg: &str, tag: &str, name: &str) -> f64 { let el = &svg[svg.find(tag).unwrap_or_else(|| panic!("no {tag}: {svg}"))..]; let el = &el[..el.find('>').unwrap()]; let k = format!(" {name}=\""); let i = el.find(&k).unwrap_or_else(|| panic!("no {name} in {el}")) + k.len(); el[i..i + el[i..].find('"').unwrap()].parse().unwrap() } #[test] fn gradient_text_spans_its_layout() { let st = CharStyle { size: 24.0, fill: Paint::Gradient(Box::new(black_to_white())), ..CharStyle::default() }; let t = TextObject::point(Point::new(30.0, 100.0), "Gradient", st); let bounds = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).bounds; let d = doc_with(|d| vec![Node::new(d.alloc_id(), NodeKind::Text(Box::new(t)))]); let svg = export(&d, &ExportOptions::default()); assert!(svg.contains("fill=\"url(#linear-gradient-1)\""), "{svg}"); // Text space is the element's user space: the gradient runs across the glyphs. assert!((attr(&svg, "