use crate::content::graphics_state::{GraphicsStateStack, Matrix};
use crate::content::operators::Operator;
pub fn apply_ctm(stack: &mut GraphicsStateStack, op: &Operator) {
match op {
Operator::SaveState => stack.save(),
Operator::RestoreState => stack.restore(),
Operator::Cm { a, b, c, d, e, f } => {
let m = Matrix {
a: *a,
b: *b,
c: *c,
d: *d,
e: *e,
f: *f,
};
let old = stack.current().ctm;
stack.current_mut().ctm = m.multiply(&old);
}
_ => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn apply_ctm_nested_concatenation_order() {
let mut stack = GraphicsStateStack::new();
apply_ctm(
&mut stack,
&Operator::Cm {
a: 1.0,
b: 0.0,
c: 0.0,
d: 1.0,
e: 100.0,
f: 0.0,
},
);
apply_ctm(
&mut stack,
&Operator::Cm {
a: 2.0,
b: 0.0,
c: 0.0,
d: 2.0,
e: 0.0,
f: 0.0,
},
);
let p = stack.current().ctm.transform_point(5.0, 5.0);
assert!((p.x - 110.0).abs() < 1e-4 && (p.y - 10.0).abs() < 1e-4);
}
#[test]
fn apply_ctm_restore_at_base_is_safe_noop() {
let mut stack = GraphicsStateStack::new();
let d0 = stack.depth();
apply_ctm(&mut stack, &Operator::RestoreState);
apply_ctm(&mut stack, &Operator::RestoreState);
assert_eq!(stack.depth(), d0);
let c = stack.current().ctm;
assert!((c.a - 1.0).abs() < 1e-6 && (c.d - 1.0).abs() < 1e-6);
}
}