Skip to content

Commit 52abefe

Browse files
committed
Move coalesced damaged calculation to util
1 parent 1ccd3eb commit 52abefe

File tree

2 files changed

+60
-46
lines changed

2 files changed

+60
-46
lines changed

src/util.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Not needed on all platforms
22
#![allow(dead_code)]
33

4+
use std::cmp;
5+
use std::num::NonZeroU32;
6+
7+
use crate::Rect;
48
use crate::SoftBufferError;
59

610
/// Takes a mutable reference to a container and a function deriving a
@@ -44,6 +48,41 @@ impl<'a, T: 'static + ?Sized, U: 'static + ?Sized> BorrowStack<'a, T, U> {
4448
}
4549
}
4650

51+
/// Calculates the smallest `Rect` necessary to represent all damaged `Rect`s.
52+
pub(crate) fn union_damage(damage: &[Rect]) -> Option<Rect> {
53+
struct Region {
54+
left: u32,
55+
top: u32,
56+
bottom: u32,
57+
right: u32,
58+
}
59+
60+
let region = damage
61+
.iter()
62+
.map(|rect| Region {
63+
left: rect.x,
64+
top: rect.y,
65+
right: rect.x + rect.width.get(),
66+
bottom: rect.y + rect.height.get(),
67+
})
68+
.reduce(|mut prev, next| {
69+
prev.left = cmp::min(prev.left, next.left);
70+
prev.top = cmp::min(prev.top, next.top);
71+
prev.right = cmp::max(prev.right, next.right);
72+
prev.bottom = cmp::max(prev.bottom, next.bottom);
73+
prev
74+
})?;
75+
76+
Some(Rect {
77+
x: region.left,
78+
y: region.top,
79+
width: NonZeroU32::new(region.right - region.left)
80+
.expect("`right` must always be bigger then `left`"),
81+
height: NonZeroU32::new(region.bottom - region.top)
82+
.expect("`bottom` must always be bigger then `top`"),
83+
})
84+
}
85+
4786
#[cfg(test)]
4887
mod tests {
4988
use super::*;

src/web.rs

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
#![allow(clippy::uninlined_format_args)]
44

5-
use std::cmp;
65
use std::convert::TryInto;
76
use std::marker::PhantomData;
87
use std::num::NonZeroU32;
@@ -15,7 +14,7 @@ use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
1514
use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
1615

1716
use crate::error::SwResultExt;
18-
use crate::{Rect, SoftBufferError};
17+
use crate::{util, Rect, SoftBufferError};
1918

2019
/// Display implementation for the web platform.
2120
///
@@ -144,60 +143,36 @@ impl WebImpl {
144143
.size
145144
.expect("Must set size of surface before calling `present_with_damage()`");
146145

147-
let mut damage_iter = damage.iter();
148-
149-
let first_rect = if let Some(rect) = damage_iter.next() {
146+
let union_damage = if let Some(rect) = util::union_damage(damage) {
150147
rect
151148
} else {
152-
// If there is no damage, there is nothing to do
153149
return Ok(());
154150
};
155151

156-
struct UnionRegion {
157-
top: u32,
158-
left: u32,
159-
bottom: u32,
160-
right: u32,
161-
}
162-
163-
let union_region = UnionRegion {
164-
top: first_rect.y,
165-
left: first_rect.x,
166-
bottom: (first_rect.y + first_rect.height.get()),
167-
right: (first_rect.x + first_rect.width.get()),
168-
};
169-
170-
let union_region = damage_iter.fold(union_region, |mut union, rect| {
171-
union.top = cmp::min(union.top, rect.y);
172-
union.left = cmp::min(union.left, rect.x);
173-
union.bottom = cmp::max(union.bottom, rect.y + rect.height.get());
174-
union.right = cmp::max(union.right, rect.x + rect.width.get());
175-
union
176-
});
177-
178-
debug_assert!(union_region.right <= buffer_width.get());
179-
debug_assert!(union_region.bottom <= _buffer_height.get());
180-
181-
let union_region_left = union_region.left as usize;
182-
let union_region_top = union_region.top as usize;
183-
let union_region_width = (union_region.right - union_region.left) as usize;
184-
let union_region_height = (union_region.bottom - union_region.top) as usize;
185-
186152
// Create a bitmap from the buffer.
187153
let bitmap: Vec<_> = self
188154
.buffer
189155
.chunks_exact(buffer_width.get() as usize)
190-
.skip(union_region_top)
191-
.take(union_region_height)
192-
.flat_map(|row| row.iter().skip(union_region_left).take(union_region_width))
156+
.skip(union_damage.y as usize)
157+
.take(union_damage.height.get() as usize)
158+
.flat_map(|row| {
159+
row.iter()
160+
.skip(union_damage.x as usize)
161+
.take(union_damage.width.get() as usize)
162+
})
193163
.copied()
194164
.flat_map(|pixel| [(pixel >> 16) as u8, (pixel >> 8) as u8, pixel as u8, 255])
195165
.collect();
196166

197-
debug_assert_eq!(bitmap.len(), union_region_height * union_region_width * 4);
167+
debug_assert_eq!(
168+
bitmap.len() as u32,
169+
union_damage.width.get() * union_damage.height.get() * 4
170+
);
198171

199172
#[cfg(target_feature = "atomics")]
200173
let result = {
174+
// When using atomics, the underlying memory becomes `SharedArrayBuffer`,
175+
// which can't be shared with `ImageData`.
201176
use js_sys::{Uint8Array, Uint8ClampedArray};
202177
use wasm_bindgen::prelude::wasm_bindgen;
203178

@@ -213,14 +188,14 @@ impl WebImpl {
213188
let array = Uint8Array::new_with_length(bitmap.len() as u32);
214189
array.copy_from(&bitmap);
215190
let array = Uint8ClampedArray::new(&array);
216-
ImageDataExt::new(array, union_region_width as u32)
191+
ImageDataExt::new(array, union_damage.width.get())
217192
.map(JsValue::from)
218193
.map(ImageData::unchecked_from_js)
219194
};
220195
#[cfg(not(target_feature = "atomics"))]
221196
let result = ImageData::new_with_u8_clamped_array(
222197
wasm_bindgen::Clamped(&bitmap),
223-
union_region_width as u32,
198+
union_damage.width.get(),
224199
);
225200
// This should only throw an error if the buffer we pass's size is incorrect.
226201
let image_data = result.unwrap();
@@ -230,10 +205,10 @@ impl WebImpl {
230205
self.canvas
231206
.put_image_data(
232207
&image_data,
233-
union_region.left.into(),
234-
union_region.top.into(),
235-
(rect.x - union_region.left).into(),
236-
(rect.y - union_region.top).into(),
208+
union_damage.x.into(),
209+
union_damage.y.into(),
210+
(rect.x - union_damage.x).into(),
211+
(rect.y - union_damage.y).into(),
237212
rect.width.get().into(),
238213
rect.height.get().into(),
239214
)

0 commit comments

Comments
 (0)