Files
vectorcraft/crates/pdf/src/tests/textstroke.rs
T

58 lines
3.1 KiB
Rust

//! Strokes on type keep every stroke option in PDF: the characters' cap, join, miter limit and
//! dash array, and the alignment of the object's own strokes.
use vectorcraft_color::{Color, Paint};
use vectorcraft_doc::{AppearanceItem, CharStyle, Dash, Document, LineCap, LineJoin, Node, NodeKind, StrokeAlign, StrokeLayer, TextObject};
use vectorcraft_geom::Point;
use crate::*;
#[test]
fn text_strokes_keep_cap_join_miter_dashes_and_alignment() {
let style = CharStyle {
size: 48.0,
stroke: Paint::solid(Color::BLACK),
stroke_width: 1.5,
stroke_cap: LineCap::Round,
stroke_join: LineJoin::Miter,
stroke_miter_limit: 7.0,
stroke_dash: Some(Dash { pattern: vec![4.0, 2.0], ..Default::default() }),
..Default::default()
};
let mut d = Document::new(240.0, 100.0);
let mut n = Node::new(d.alloc_id(), NodeKind::Text(Box::new(TextObject::point(Point::new(10.0, 70.0), "Wave", style))));
let mut own = StrokeLayer::new(Paint::solid(Color::rgb8(0, 0, 255)), 3.0);
own.align = StrokeAlign::Inside;
n.appearance.items.push(AppearanceItem::Stroke(own));
let l = d.layers[0].id;
d.insert(Some(l), 0, n).unwrap();
let pdf = export(&d, &PdfOptions::uncompressed()).unwrap();
assert!(String::from_utf8_lossy(&pdf).contains("7 M 1 J[4 2]0 d"), "the characters' miter limit, cap and dash array");
let back = import(&pdf).unwrap();
let mut strokes = vec![];
back.walk(|n| strokes.extend(n.appearance.items.iter().filter_map(|i| if let AppearanceItem::Stroke(s) = i { Some(s.clone()) } else { None })));
let chars = strokes.iter().find(|s| s.dash.is_some()).expect("the characters' stroke");
assert_eq!((chars.cap, chars.join), (LineCap::Round, LineJoin::Miter));
assert!((chars.miter_limit - 7.0).abs() < 1e-3, "miter limit {}", chars.miter_limit);
// An inside stroke is drawn twice as wide, clipped to the glyphs.
assert!(strokes.iter().any(|s| s.dash.is_none() && (s.width - 6.0).abs() < 1e-3), "{strokes:?}");
}
/// Align Stroke on live type: the characters' stroke drawn twice as wide, clipped inside or
/// outside the glyphs, as on the canvas; the type stays text.
#[test]
fn an_aligned_character_stroke_is_clipped_to_its_side_of_the_glyphs() {
for (align, clip) in [(StrokeAlign::Inside, false), (StrokeAlign::Outside, true)] {
let style = CharStyle { size: 48.0, stroke: Paint::solid(Color::BLACK), stroke_width: 1.5, stroke_align: align, ..Default::default() };
let mut d = Document::new(240.0, 100.0);
let n = Node::new(d.alloc_id(), NodeKind::Text(Box::new(TextObject::point(Point::new(10.0, 70.0), "Wave", style))));
let l = d.layers[0].id;
d.insert(Some(l), 0, n).unwrap();
let pdf = String::from_utf8_lossy(&export(&d, &PdfOptions::uncompressed()).unwrap()).into_owned();
let ops: Vec<&str> = pdf.split_ascii_whitespace().collect();
assert!(ops.windows(2).any(|w| w == ["3", "w"]), "{align:?}: twice the weight");
assert!(ops.contains(&"BT"), "{align:?}: the type stays text");
assert!(ops.contains(&if clip { "W*" } else { "W" }), "{align:?}: clipped to its side");
}
}