Preserve document and history when Fade cannot allocate its buffers. (#4593)
This commit is contained in:
parent
f389d4ee64
commit
b52115fc0a
|
|
@ -151,14 +151,14 @@ fn surface_of(doc: &Document, id: LayerId, mask: bool) -> Option<&Surface> {
|
|||
|
||||
/// Blend `after` back towards `before` over `area`: `before + opacity × (B(before, after) − before)`
|
||||
/// with blend mode `mode` (premultiplied, so alpha changes fade too).
|
||||
pub fn fade_surface(before: &Surface, after: &mut Surface, area: Rect, mode: BlendMode, opacity: f32) {
|
||||
pub fn fade_surface(before: &Surface, after: &mut Surface, area: Rect, mode: BlendMode, opacity: f32) -> Result<()> {
|
||||
let fmt = after.format();
|
||||
let n = fmt.channels();
|
||||
if area.is_empty() || n == 0 {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
let b = before.read_region(area);
|
||||
let mut a = after.read_region(area);
|
||||
let b = crate::allocation::read_region(before, area, "fading pixels")?;
|
||||
let mut a = crate::allocation::read_region(after, area, "fading pixels")?;
|
||||
let k = opacity.clamp(0.0, 1.0);
|
||||
let lerp_premul = |pb: &[f32], pa: &[f32], out: &mut [f32], alpha: bool| {
|
||||
let m = out.len();
|
||||
|
|
@ -176,7 +176,7 @@ pub fn fade_surface(before: &Surface, after: &mut Surface, area: Rect, mode: Ble
|
|||
}
|
||||
out[m - 1] = ao;
|
||||
};
|
||||
let mut tmp = vec![0.0f32; n];
|
||||
let mut tmp = crate::allocation::filled(n, 0.0f32, "fading pixels")?;
|
||||
for (pa, pb) in a.chunks_exact_mut(n).zip(b.chunks_exact(n)) {
|
||||
if mode == BlendMode::Normal || n == 1 {
|
||||
lerp_premul(pb, pa, &mut tmp, fmt.alpha);
|
||||
|
|
@ -192,7 +192,8 @@ pub fn fade_surface(before: &Surface, after: &mut Surface, area: Rect, mode: Ble
|
|||
pa.copy_from_slice(&enc[..n]);
|
||||
}
|
||||
}
|
||||
after.write_region(area, &a);
|
||||
after.try_write_region(area, &a)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fade(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
|
@ -212,7 +213,7 @@ fn fade(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
s.edit(&label, |doc, _| {
|
||||
let l = doc.layer_mut(src.layer).ok_or(EngineError::NoLayer(src.layer))?;
|
||||
let surf = if src.mask { l.mask.as_mut().map(|m| &mut m.surface) } else { l.surface_mut() }.ok_or(EngineError::NoLayer(src.layer))?;
|
||||
fade_surface(&before, surf, area, mode, opacity);
|
||||
fade_surface(&before, surf, area, mode, opacity)?;
|
||||
surf.prune();
|
||||
Ok(())
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -544,3 +544,23 @@ fn backward_change_find_moves_past_the_replaced_text() {
|
|||
assert_eq!((r["changed"]["start"].as_u64(), r["changed"]["end"].as_u64()), (Some(0), Some(3)), "{r}");
|
||||
assert_eq!((r["found"]["start"].as_u64(), r["found"]["end"].as_u64()), (Some(8), Some(11)), "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fade_allocation_failure_keeps_document_and_history() {
|
||||
for depth in [8, 16, 32] {
|
||||
let mut s = session(depth);
|
||||
s.execute("edit.fill", json!({"color": "#000000"})).unwrap();
|
||||
let before = s.active().unwrap().doc.clone();
|
||||
let history = s.active().unwrap().history.entries();
|
||||
crate::allocation::fail_next_for_test();
|
||||
let result = s.execute("edit.fade", json!({"opacity": 25}));
|
||||
let _ = crate::allocation::capacity::<u8>(0, "reset failpoint");
|
||||
assert!(result.is_err());
|
||||
assert_eq!(*s.active().unwrap().doc, *before);
|
||||
assert_eq!(s.active().unwrap().history.entries(), history);
|
||||
assert!(s.is_enabled("edit.fade"));
|
||||
s.execute("edit.fade", json!({"opacity": 25})).unwrap();
|
||||
assert!(s.undo());
|
||||
assert_eq!(*s.active().unwrap().doc, *before);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue