1
//! Pixel iterators for `SharedImageSurface`.
2
use crate::rect::IRect;
3
use crate::util::clamp;
4

            
5
use super::shared_surface::SharedImageSurface;
6
use super::{EdgeMode, Pixel};
7

            
8
/// Iterator over pixels of a `SharedImageSurface`.
9
pub struct Pixels<'a> {
10
    surface: &'a SharedImageSurface,
11
    bounds: IRect,
12
    x: u32,
13
    y: u32,
14
    offset: isize,
15
}
16

            
17
/// Iterator over a (potentially out of bounds) rectangle of pixels of a `SharedImageSurface`.
18
pub struct PixelRectangle<'a> {
19
    surface: &'a SharedImageSurface,
20
    bounds: IRect,
21
    rectangle: IRect,
22
    edge_mode: EdgeMode,
23
    x: i32,
24
    y: i32,
25
}
26

            
27
impl<'a> Pixels<'a> {
28
    /// Creates an iterator over the image surface pixels
29
    #[inline]
30
32962
    pub fn new(surface: &'a SharedImageSurface) -> Self {
31
32962
        let bounds = IRect::from_size(surface.width(), surface.height());
32

            
33
32962
        Self::within(surface, bounds)
34
32962
    }
35

            
36
    /// Creates an iterator over the image surface pixels, constrained within the given bounds.
37
    #[inline]
38
46778
    pub fn within(surface: &'a SharedImageSurface, bounds: IRect) -> Self {
39
        // Sanity checks.
40
46778
        assert!(bounds.x0 >= 0);
41
46778
        assert!(bounds.x0 <= surface.width());
42
46778
        assert!(bounds.x1 >= bounds.x0);
43
46778
        assert!(bounds.x1 <= surface.width());
44
46778
        assert!(bounds.y0 >= 0);
45
46778
        assert!(bounds.y0 <= surface.height());
46
46778
        assert!(bounds.y1 >= bounds.y0);
47
46778
        assert!(bounds.y1 <= surface.height());
48

            
49
46778
        Self {
50
46778
            surface,
51
46778
            bounds,
52
46778
            x: bounds.x0 as u32,
53
46778
            y: bounds.y0 as u32,
54
46778
            offset: bounds.y0 as isize * surface.stride() + bounds.x0 as isize * 4,
55
46778
        }
56
46778
    }
57
}
58

            
59
impl<'a> PixelRectangle<'a> {
60
    /// Creates an iterator over the image surface pixels
61
    #[inline]
62
2
    pub fn new(surface: &'a SharedImageSurface, rectangle: IRect, edge_mode: EdgeMode) -> Self {
63
2
        let bounds = IRect::from_size(surface.width(), surface.height());
64

            
65
2
        Self::within(surface, bounds, rectangle, edge_mode)
66
2
    }
67

            
68
    /// Creates an iterator over the image surface pixels, constrained within the given bounds.
69
    #[inline]
70
7618222
    pub fn within(
71
7618222
        surface: &'a SharedImageSurface,
72
7618222
        bounds: IRect,
73
7618222
        rectangle: IRect,
74
7618222
        edge_mode: EdgeMode,
75
7618222
    ) -> Self {
76
        // Sanity checks.
77
7618222
        assert!(bounds.x0 >= 0);
78
7618222
        assert!(bounds.x0 <= surface.width());
79
7618222
        assert!(bounds.x1 >= bounds.x0);
80
7618222
        assert!(bounds.x1 <= surface.width());
81
7618222
        assert!(bounds.y0 >= 0);
82
7618222
        assert!(bounds.y0 <= surface.height());
83
7618222
        assert!(bounds.y1 >= bounds.y0);
84
7618222
        assert!(bounds.y1 <= surface.height());
85

            
86
        // Non-None EdgeMode values need at least one pixel available.
87
7618222
        if edge_mode != EdgeMode::None {
88
3219360
            assert!(bounds.x1 > bounds.x0);
89
3219360
            assert!(bounds.y1 > bounds.y0);
90
4398862
        }
91

            
92
7618222
        assert!(rectangle.x1 >= rectangle.x0);
93
7618222
        assert!(rectangle.y1 >= rectangle.y0);
94

            
95
7618222
        Self {
96
7618222
            surface,
97
7618222
            bounds,
98
7618222
            rectangle,
99
7618222
            edge_mode,
100
7618222
            x: rectangle.x0,
101
7618222
            y: rectangle.y0,
102
7618222
        }
103
7618222
    }
104
}
105

            
106
impl<'a> Iterator for Pixels<'a> {
107
    type Item = (u32, u32, Pixel);
108

            
109
    #[inline]
110
2948903208
    fn next(&mut self) -> Option<Self::Item> {
111
        // This means we hit the end on the last iteration.
112
2948903208
        if self.x == self.bounds.x1 as u32 || self.y == self.bounds.y1 as u32 {
113
30298
            return None;
114
2948872910
        }
115

            
116
2948872910
        let rv = Some((
117
2948872910
            self.x,
118
2948872910
            self.y,
119
2948872910
            self.surface.get_pixel_by_offset(self.offset),
120
2948872910
        ));
121

            
122
2948872910
        if self.x + 1 == self.bounds.x1 as u32 {
123
6541596
            self.x = self.bounds.x0 as u32;
124
6541596
            self.y += 1;
125
6541596
            self.offset += self.surface.stride() - (self.bounds.width() - 1) as isize * 4;
126
2942331314
        } else {
127
2942331314
            self.x += 1;
128
2942331314
            self.offset += 4;
129
2942331314
        }
130

            
131
2948872910
        rv
132
2948903208
    }
133
}
134

            
135
impl<'a> Iterator for PixelRectangle<'a> {
136
    type Item = (i32, i32, Pixel);
137

            
138
    #[inline(always)]
139
87378514
    fn next(&mut self) -> Option<Self::Item> {
140
        // This means we hit the end on the last iteration.
141
87378514
        if self.x == self.rectangle.x1 || self.y == self.rectangle.y1 {
142
7618222
            return None;
143
79760292
        }
144

            
145
79760292
        let rv = {
146
79760292
            let get_pixel = |x, y| {
147
79760292
                if !self.bounds.contains(x, y) {
148
1536504
                    match self.edge_mode {
149
939504
                        EdgeMode::None => Pixel {
150
939504
                            r: 0,
151
939504
                            g: 0,
152
939504
                            b: 0,
153
939504
                            a: 0,
154
939504
                        },
155
                        EdgeMode::Duplicate => {
156
383000
                            let x = clamp(x, self.bounds.x0, self.bounds.x1 - 1);
157
383000
                            let y = clamp(y, self.bounds.y0, self.bounds.y1 - 1);
158
383000
                            self.surface.get_pixel(x as u32, y as u32)
159
                        }
160
                        EdgeMode::Wrap => {
161
428000
                            let wrap = |mut x, v| {
162
444080
                                while x < 0 {
163
16080
                                    x += v;
164
16080
                                }
165
428000
                                x % v
166
428000
                            };
167

            
168
214000
                            let x = self.bounds.x0 + wrap(x - self.bounds.x0, self.bounds.width());
169
214000
                            let y = self.bounds.y0 + wrap(y - self.bounds.y0, self.bounds.height());
170
214000
                            self.surface.get_pixel(x as u32, y as u32)
171
                        }
172
                    }
173
                } else {
174
78223788
                    self.surface.get_pixel(x as u32, y as u32)
175
                }
176
79760292
            };
177

            
178
79760292
            Some((self.x, self.y, get_pixel(self.x, self.y)))
179
        };
180

            
181
79760292
        if self.x + 1 == self.rectangle.x1 {
182
26191772
            self.x = self.rectangle.x0;
183
26191772
            self.y += 1;
184
53568520
        } else {
185
53568520
            self.x += 1;
186
53568520
        }
187

            
188
79760292
        rv
189
87378514
    }
190
}
191

            
192
#[cfg(test)]
193
mod tests {
194
    use super::*;
195
    use crate::surface_utils::shared_surface::SurfaceType;
196

            
197
    #[test]
198
2
    fn pixels_count() {
199
        const WIDTH: i32 = 32;
200
        const HEIGHT: i32 = 64;
201

            
202
2
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
203

            
204
        // Full image.
205
2
        assert_eq!(Pixels::new(&surface).count(), (WIDTH * HEIGHT) as usize);
206

            
207
        // 1-wide column.
208
2
        let bounds = IRect::from_size(1, HEIGHT);
209
2
        assert_eq!(Pixels::within(&surface, bounds).count(), HEIGHT as usize);
210

            
211
        // 1-tall row.
212
2
        let bounds = IRect::from_size(WIDTH, 1);
213
2
        assert_eq!(Pixels::within(&surface, bounds).count(), WIDTH as usize);
214

            
215
        // 1×1.
216
2
        let bounds = IRect::from_size(1, 1);
217
2
        assert_eq!(Pixels::within(&surface, bounds).count(), 1);
218

            
219
        // Nothing (x0 == x1).
220
2
        let bounds = IRect::from_size(0, HEIGHT);
221
2
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
222

            
223
        // Nothing (y0 == y1).
224
2
        let bounds = IRect::from_size(WIDTH, 0);
225
2
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
226

            
227
        // Nothing (x0 == x1, y0 == y1).
228
2
        let bounds = IRect::new(0, 0, 0, 0);
229
2
        assert_eq!(Pixels::within(&surface, bounds).count(), 0);
230
2
    }
231

            
232
    #[test]
233
2
    fn pixel_rectangle() {
234
        const WIDTH: i32 = 32;
235
        const HEIGHT: i32 = 64;
236

            
237
2
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
238

            
239
2
        let rect_bounds = IRect::new(-8, -8, 8, 8);
240
2
        assert_eq!(
241
2
            PixelRectangle::new(&surface, rect_bounds, EdgeMode::None).count(),
242
            (16 * 16) as usize
243
        );
244
2
    }
245
}