Skip to content

Commit 3cbf9a9

Browse files
authored
Merge pull request #711 from cospectrum/draw-filled-rect
fix `draw_filled_rect` panic for empty image
2 parents ef42fd6 + 8f84089 commit 3cbf9a9

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

src/drawing/rect.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,17 @@ pub fn draw_filled_rect_mut<C>(canvas: &mut C, rect: Rect, color: C::Pixel)
5252
where
5353
C: Canvas,
5454
{
55+
if canvas.width() == 0 || canvas.height() == 0 {
56+
return;
57+
}
5558
let canvas_bounds = Rect::at(0, 0).of_size(canvas.width(), canvas.height());
5659
if let Some(intersection) = canvas_bounds.intersect(rect) {
5760
for dy in 0..intersection.height() {
5861
for dx in 0..intersection.width() {
5962
let x = intersection.left() as u32 + dx;
6063
let y = intersection.top() as u32 + dy;
64+
debug_assert!(x < canvas.width());
65+
debug_assert!(y < canvas.height());
6166
canvas.draw_pixel(x, y, color);
6267
}
6368
}
@@ -139,6 +144,31 @@ mod tests {
139144
}
140145
}
141146

147+
#[cfg(not(miri))]
148+
#[cfg(test)]
149+
mod proptests {
150+
use super::*;
151+
use crate::{proptest_utils::arbitrary_image, rect::Rect};
152+
use image::Luma;
153+
use proptest::prelude::*;
154+
155+
proptest! {
156+
#[test]
157+
fn proptest_draw_filled_rect_luma(
158+
image in arbitrary_image::<Luma<u8>>(0..50, 0..50),
159+
(x, y) in (-50..50, -50..50),
160+
(w, h) in (1..50u32, 1..50u32),
161+
color in 0..255u8,
162+
) {
163+
let rect = Rect::at(x, y).of_size(w, h);
164+
let color = Luma([color]);
165+
166+
let out = draw_filled_rect(&image, rect, color);
167+
assert_eq!(out.dimensions(), image.dimensions());
168+
}
169+
}
170+
}
171+
142172
#[cfg(not(miri))]
143173
#[cfg(test)]
144174
mod benches {

src/rect.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Basic manipulation of rectangles.
22
3-
use std::cmp;
4-
53
/// A rectangular region of non-zero width and height.
64
/// # Examples
75
/// ```
@@ -62,14 +60,14 @@ impl Rect {
6260
///
6361
/// See the [struct-level documentation](Rect) for examples.
6462
pub fn bottom(&self) -> i32 {
65-
self.top + (self.height as i32) - 1
63+
self.top + i32::try_from(self.height).unwrap() - 1
6664
}
6765

6866
/// Greatest x-coordinate reached by rect.
6967
///
7068
/// See the [struct-level documentation](Rect) for examples.
7169
pub fn right(&self) -> i32 {
72-
self.left + (self.width as i32) - 1
70+
self.left + i32::try_from(self.width).unwrap() - 1
7371
}
7472

7573
/// Width of rect.
@@ -105,21 +103,18 @@ impl Rect {
105103
/// assert_eq!(r.intersect(s), None);
106104
/// ```
107105
pub fn intersect(&self, other: Rect) -> Option<Rect> {
108-
let left = cmp::max(self.left, other.left);
109-
let top = cmp::max(self.top, other.top);
110-
let right = cmp::min(self.right(), other.right());
111-
let bottom = cmp::min(self.bottom(), other.bottom());
106+
let left = self.left.max(other.left);
107+
let top = self.top.max(other.top);
108+
let right = self.right().min(other.right());
109+
let bottom = self.bottom().min(other.bottom());
112110

113111
if right < left || bottom < top {
114112
return None;
115113
}
116114

117-
Some(Rect {
118-
left,
119-
top,
120-
width: (right - left) as u32 + 1,
121-
height: (bottom - top) as u32 + 1,
122-
})
115+
let width = u32::try_from(right - left).unwrap() + 1;
116+
let height = u32::try_from(bottom - top).unwrap() + 1;
117+
Some(Rect::at(left, top).of_size(width, height))
123118
}
124119
}
125120

@@ -189,3 +184,29 @@ mod tests {
189184
assert!(!r.contains(10.1f32, 10f32));
190185
}
191186
}
187+
188+
#[cfg(not(miri))]
189+
#[cfg(test)]
190+
mod proptests {
191+
use super::*;
192+
use proptest::prelude::*;
193+
194+
proptest! {
195+
#[test]
196+
fn proptest_intersect(
197+
(x1, y1) in (-50..50, -50..50),
198+
(w1, h1) in (1..50u32, 1..50u32),
199+
200+
(x2, y2) in (-50..50, -50..50),
201+
(w2, h2) in (1..50u32, 1..50u32),
202+
) {
203+
let rect1 = Rect::at(x1, y1).of_size(w1, h1);
204+
let rect2 = Rect::at(x2, y2).of_size(w2, h2);
205+
206+
if let Some(intersect) = rect1.intersect(rect2) {
207+
assert!(intersect.width() > 0);
208+
assert!(intersect.height() > 0);
209+
};
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)