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
1629
    pub fn new(surface: &'a SharedImageSurface) -> Self {
31
1629
        let bounds = IRect::from_size(surface.width(), surface.height());
32

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

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

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

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

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

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

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

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

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

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

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

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

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

            
131
118614637
        rv
132
187344720
    }
133
}
134

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

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

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

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

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

            
181
3945790
        if self.x + 1 == self.rectangle.x1 {
182
1296798
            self.x = self.rectangle.x0;
183
1296798
            self.y += 1;
184
        } else {
185
2648992
            self.x += 1;
186
        }
187

            
188
3945790
        rv
189
4321082
    }
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
1
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
203

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

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

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

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

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

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

            
227
        // Nothing (x0 == x1, y0 == y1).
228
1
        let bounds = IRect::new(0, 0, 0, 0);
229
1
        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
1
        let surface = SharedImageSurface::empty(WIDTH, HEIGHT, SurfaceType::SRgb).unwrap();
238

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