This commit is contained in:
bflatastic
2026-10-13 11:02:36 +07:00
3 changed files with 51 additions and 0 deletions
+2
View File
@@ -350,6 +350,8 @@ fn request_window(app: &mut LightcraftApp, v: &TileView) -> Option<crate::region
// refused: what the window reads (a spot's source, an Auto Mask stroke) is too far for one
// render; the pane keeps its whole-frame render
let job = app.session.region_job(v.id, fw, fh, win, true)?;
// keyed as the renderer keys the texture (a display profile changes the key)
let job = app.renderer.job_for(Slot::CompareRegion(v.pane), job);
let look = job.settings.hash64();
let view = crate::region::RegionView { photo: v.id, before: false, key: job.key, full: (fw, fh), window: win, settings: look };
// windows of other photos, looks and zooms of this pane can't be drawn any more
+2
View File
@@ -331,6 +331,8 @@ fn request_window(app: &mut LightcraftApp, c: &WindowCtx, v: &WindowView) -> Opt
let overlay = if v.before { lightcraft_pipeline::Overlay::None } else { c.overlay };
let job = if v.before { job } else { job.with_hidden_grading(app.ui.grading_hidden_for(c.id)) };
let job = job.with_overlay(overlay);
// keyed as the renderer keys the texture (a display profile changes the key)
let job = app.renderer.job_for(v.slot, job);
// The overlay is part of the tile's identity too, so changing mask view/colour never leaves a
// stale region tile on screen while its replacement renders.
let look = job.settings.hash64() ^ overlay.key().rotate_left(17);
+47
View File
@@ -763,6 +763,53 @@ mod in_the_loupe {
assert!(held(&h) > before / 3, "and they are still there");
}
/// Load a Display P3 monitor profile (`app.displayProfile`), as Settings ▸ Display does.
fn use_display_profile(h: &mut Headless) {
let dir = std::env::temp_dir().join(format!("lightcraft-zoom-display-{}-{:?}", std::process::id(), std::thread::current().id()));
std::fs::create_dir_all(&dir).expect("temp dir");
let path = dir.join("p3.icc");
std::fs::write(&path, lightcraft_codecs::icc::write_named(lightcraft_codecs::NamedSpace::DisplayP3)).expect("profile written");
let r = h.request("engine.execute", json!({"command": "app.displayProfile", "params": {"path": path.to_string_lossy()}}), T);
assert_eq!(r["ok"], true, "{r}");
assert!(h.app.renderer.display_id().is_some());
}
// Given a monitor profile, when I zoom to 1:1, then the sharp window is painted over the
// whole-frame render, as without one (a display profile changes the texture's render key, and
// the window used to be looked up by the key it had before: never found, so only the
// whole-frame render, magnified and blurred, was shown)
#[test]
fn a_display_profile_keeps_the_sharp_window_at_one_to_one() {
let (mut h, native) = detail();
use_display_profile(&mut h);
h.request("engine.execute", json!({"command": "view.zoom100"}), T);
h.settle(SETTLE);
assert!(rendered_long_edge(&h) < native, "the whole frame is smaller than the photo");
let view = h.app.region_view.expect("a window render");
assert_eq!(view.full.0.max(view.full.1), native);
let (whole, window) = (drawn(&h, Slot::Main), drawn(&h, Slot::Region));
assert!(!whole.is_empty(), "the whole-frame render is painted");
assert!(!window.is_empty(), "the window is painted");
assert!(window[0].0 > whole[0].0, "over the whole-frame render");
}
// …and in Compare, each pane's window too
#[test]
fn a_display_profile_keeps_the_compare_windows_at_one_to_one() {
let (mut h, _) = detail();
use_display_profile(&mut h);
let r = h.request("engine.execute", json!({"command": "view.compare"}), T);
assert_eq!(r["ok"], true, "{r}");
h.app.ui.zoom = crate::state::Zoom::Percent(100.0);
h.settle(SETTLE);
for i in 0..2u8 {
assert!(h.app.compare_windows[i as usize].is_some(), "pane {i} asked for a window");
let (whole, window) = (drawn(&h, Slot::Compare(i)), drawn(&h, Slot::CompareRegion(i)));
assert!(!whole.is_empty() && !window.is_empty(), "pane {i}: both are painted");
assert!(window[0].0 > whole[0].0, "pane {i}: the window is painted over the whole-frame render");
}
}
/// Compare view of the demo library at `zoom`, settled.
fn compare_at(zoom: crate::state::Zoom) -> Headless {
let (mut h, _) = detail();