Skip to main content

vello_cpu/filter/
offset.rs

1// Copyright 2026 the Vello Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! `feOffset` filter primitive implementation.
5
6use vello_common::pixmap::Pixmap;
7
8use super::FilterEffect;
9use super::shift::offset_pixels;
10use crate::layer_manager::LayerManager;
11
12/// Translation/shift filter.
13///
14/// This shifts the input image by `(dx, dy)` in device pixel space.
15#[derive(Clone, Copy, Debug)]
16pub(crate) struct Offset {
17    dx: f32,
18    dy: f32,
19}
20
21impl Offset {
22    pub(crate) fn new(dx: f32, dy: f32) -> Self {
23        Self { dx, dy }
24    }
25
26    fn execute(self, pixmap: &mut Pixmap, _layer_manager: &mut LayerManager) {
27        offset_pixels(pixmap, self.dx, self.dy);
28    }
29}
30
31impl FilterEffect for Offset {
32    fn execute_lowp(&self, pixmap: &mut Pixmap, layer_manager: &mut LayerManager) {
33        self.execute(pixmap, layer_manager);
34    }
35
36    fn execute_highp(&self, pixmap: &mut Pixmap, layer_manager: &mut LayerManager) {
37        self.execute(pixmap, layer_manager);
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::Offset;
44    use crate::filter::FilterEffect;
45    use crate::layer_manager::LayerManager;
46    use vello_common::peniko::color::PremulRgba8;
47    use vello_common::pixmap::Pixmap;
48
49    #[test]
50    fn offset_moves_pixels_and_clears_uncovered_area() {
51        let mut layer_manager = LayerManager::new();
52        let mut pixmap = Pixmap::new(4, 3);
53        pixmap.set_pixel(1, 1, PremulRgba8::from_u32(0xff_00_00_ff)); // premul red, opaque
54
55        Offset::new(2.0, -1.0).execute_lowp(&mut pixmap, &mut layer_manager);
56
57        // Original pixel (1,1) moved to (3,0).
58        assert_eq!(pixmap.sample(3, 0), PremulRgba8::from_u32(0xff_00_00_ff));
59        // Original location cleared.
60        assert_eq!(pixmap.sample(1, 1), PremulRgba8::from_u32(0));
61    }
62}