use hcie_composite::composite_layers; use hcie_protocol::{BlendMode, Layer, LayerType}; fn make_layer(name: &str, w: u32, h: u32, rgba: [u8; 4]) -> Layer { let mut l = Layer::from_rgba( name, w, h, vec![rgba; (w * h) as usize].into_iter().flatten().collect(), ); l.blend_mode = BlendMode::Normal; l } fn make_group(name: &str, w: u32, h: u32, id: u64) -> Layer { let mut l = Layer::new_transparent(name, w, h); l.layer_type = LayerType::Group; l.blend_mode = BlendMode::PassThrough; l.id = id; l } #[test] fn test_pass_through_group_skipped_in_composite() { let w = 2u32; let h = 2u32; // Background: opaque white let bg = make_layer("bg", w, h, [255, 255, 255, 255]); // Group: PassThrough (no pixels) let group = make_group("group", w, h, 1); // Child: Multiply on grey let mut child = make_layer("child", w, h, [128, 128, 128, 255]); child.blend_mode = BlendMode::Multiply; child.parent_id = Some(1); // Composite order: bg, group, child let layers = vec![bg, group, child]; let out = composite_layers(&layers, w, h); // PassThrough: child blends directly onto bg. // Multiply: 255 * 128 / 255 = 128 for each channel. // Expected: every pixel [128, 128, 128, 255] let expected = vec![ 128u8, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, 255, ]; assert_eq!( out, expected, "PassThrough group should let child blend directly onto backdrop" ); } #[test] fn test_pass_through_group_invisible_children() { let w = 2u32; let h = 2u32; let bg = make_layer("bg", w, h, [255, 255, 255, 255]); let group = make_group("group", w, h, 1); let mut child = make_layer("child", w, h, [128, 128, 128, 255]); child.blend_mode = BlendMode::Multiply; child.parent_id = Some(1); child.visible = false; let layers = vec![bg, group, child]; let out = composite_layers(&layers, w, h); // Child hidden → only bg visible let expected = vec![ 255u8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ]; assert_eq!(out, expected); } #[test] fn test_pass_through_group_with_opacity() { let w = 2u32; let h = 2u32; // Background white let bg = make_layer("bg", w, h, [255, 255, 255, 255]); // Group with 50% opacity (PassThrough) let mut group = make_group("group", w, h, 1); group.opacity = 0.5; // Child with Multiply on grey let mut child = make_layer("child", w, h, [128, 128, 128, 255]); child.blend_mode = BlendMode::Multiply; child.parent_id = Some(1); // In a true PassThrough implementation the group opacity would multiply // the child's effective opacity. Our MVP skips group pixels entirely, // so the child blends at full opacity. We keep this test documenting // current MVP behaviour. let layers = vec![bg, group, child]; let out = composite_layers(&layers, w, h); // Multiply full-strength let expected = vec![ 128u8, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, 255, ]; assert_eq!(out, expected); }