mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 15:49:48 +00:00
Merge pull request #1630 from samhyun/perf/partial-damage-margin
M8: an edit renders where the changed layer paints, its effects' margin once
This commit is contained in:
2 files changed
+37
-6
No files matched your search
@@ -550,14 +550,15 @@ pub fn effect_margin(n: &Node) -> f64 {
|
||||
layer + others
|
||||
}
|
||||
|
||||
/// Everything node `id` can paint, in page coordinates: its paint bounds (glyphs of overflowing
|
||||
/// text included) grown by its effects' margin. What a change to the node can affect on screen.
|
||||
/// Everything node `id` can paint, in page coordinates: its paint bounds, effects and glyphs of
|
||||
/// overflowing text included. What a change to the node can affect on screen. Its effects' margin
|
||||
/// (what they read from outside, see [`effect_margin`]) isn't added again: drawing the area
|
||||
/// takes in what lies that far off, as culling does.
|
||||
pub fn paint_bounds(doc: &Document, id: NodeId) -> Option<Rect> {
|
||||
let n = doc.node(id)?;
|
||||
let m = effect_margin(n).abs();
|
||||
let world = doc.world_transform(id);
|
||||
let local = local_paint_bounds(doc, n, world, 0, None);
|
||||
Some(figcraft_geom::transform_rect_bbox(world, local).inflate(m, m))
|
||||
Some(figcraft_geom::transform_rect_bbox(world, local))
|
||||
}
|
||||
|
||||
/// The local → page map of a layer drawn at `xf` (local → device): the view's scale taken out.
|
||||
|
||||
@@ -188,9 +188,9 @@ fn edits_under_and_beside_effects_match() {
|
||||
let beside = edit(&across, |d| d.get_mut(s.rect).unwrap().transform = Affine::translate((10.0, 110.0)));
|
||||
assert!(partial(check(&mut r, &beside, s.page, &v)));
|
||||
// A child of a group with a drop shadow: the shadow moves too, past the group's box with the
|
||||
// child (a view large enough that this stays a part of it).
|
||||
// child.
|
||||
let g1 = s.doc.find_by_name("G1", None)[0];
|
||||
let v = View { origin: (260.0, 0.0), scale: 1.0, width: 400, height: 300 };
|
||||
let v = View { origin: (260.0, 0.0), scale: 1.0, width: 300, height: 220 };
|
||||
check(&mut r, &beside, s.page, &v);
|
||||
let shadowed = edit(&beside, |d| d.get_mut(g1).unwrap().transform = Affine::translate((30.0, 20.0)));
|
||||
assert!(partial(check(&mut r, &shadowed, s.page, &v)));
|
||||
@@ -448,6 +448,36 @@ fn effect_margins_too_large_to_add_stay_large() {
|
||||
assert_eq!(m, 2.0 * crate::draw::MAX_REACH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_moved_layer_renders_where_its_effects_paint_and_no_further() {
|
||||
fonts();
|
||||
let shadow = |dy: f64, r: f64| Effect {
|
||||
kind: EffectKind::DropShadow(Shadow { color: Color::BLACK, offset: (0.0, dy), radius: r, ..Shadow::default() }),
|
||||
..Effect::drop_shadow()
|
||||
};
|
||||
let blur = Effect { kind: EffectKind::LayerBlur(figcraft_doc::Blur::uniform(30.0)), ..Effect::layer_blur() };
|
||||
for (why, effects) in [("a shadow falling 40", vec![shadow(40.0, 8.0)]), ("a blur of 30", vec![blur])] {
|
||||
let mut d = Document::new("moved");
|
||||
let p = d.first_page().unwrap();
|
||||
let id = d.create(p, NodeKind::Rectangle, "R", 300.0, 200.0, 120.0, 120.0).unwrap();
|
||||
solid(d.node_mut(id).unwrap(), "3366FF");
|
||||
d.node_mut(id).unwrap().effects = effects;
|
||||
let before = Arc::new(d);
|
||||
let after = edit(&before, |d| d.get_mut(id).unwrap().transform = Affine::translate((315.0, 210.0)));
|
||||
let v = View { origin: (0.0, 0.0), scale: 1.0, width: 1000, height: 800 };
|
||||
let mut r = Retained::default();
|
||||
check(&mut r, &before, p, &v);
|
||||
// Where it painted and where it paints now, a pixel round each for rounding out; a quarter
|
||||
// more, as layers grow by a shadow's reach on every side, not only towards its offset.
|
||||
let area = |doc: &Document| doc.world_render_bounds(id).map_or(0.0, |b| (b.width() + 2.0) * (b.height() + 2.0));
|
||||
let most = (area(&before) + area(&after)) * 1.25;
|
||||
match check(&mut r, &after, p, &v) {
|
||||
Work::Partial { pixels } => assert!(pixels as f64 <= most, "{why}: {pixels} pixels rendered, where it paints is {most}"),
|
||||
w => panic!("{why}: {w:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Every channel of `a` within `tol` of the same channel of `b` from row `rows_down` on.
|
||||
fn assert_within(a: &Pixmap, b: &Pixmap, rows_down: u32, tol: u8, what: &str) {
|
||||
assert_eq!(a.width(), b.width(), "{what}: widths");
|
||||
|
||||
Reference in new issue
Block a user