Merge pull request #1086 from vangel76/fix-1070-stale-footage-cache

This commit is contained in:
Brandon Thomas committed 2026-10-13 04:28:27 -04:00
commit 2a1a98006c
3 files changed
+41

No files matched your search

+5
View File
@@ -445,6 +445,11 @@ fn add_footage(s: &mut Session, pending: PendingImport, probed: Vec<std::result:
let mut asked: Vec<u64> = vec![];
let made: Vec<ItemId> = comps.iter().map(|c| ItemId(*c)).collect();
if !found.is_empty() {
// The file may have been overwritten since an earlier import or project decoded it (the
// media layer keys frames by path): a fresh import reads it again (#1070).
for f in &found {
s.forget_decoded(&f.footage);
}
s.edit("Import", None, |proj, st| {
let mut selection = made;
for f in found {
+17
View File
@@ -1016,6 +1016,15 @@ impl Session {
Ok((img.width, img.height, img.to_rgba8()))
}
/// Make the media layer and the layer cache let go of what they decoded from `footage`'s
/// files (it keys frames by path, so an overwritten file would keep showing its old pixels).
pub(crate) fn forget_decoded(&self, footage: &effectcraft_project::Footage) {
for p in std::iter::once(&footage.path).chain(&footage.sequence) {
self.footage.forget(p);
}
self.layer_cache.clear();
}
/// Replace the whole project (open/new), resetting history and state.
pub fn replace_project(&mut self, mut p: Project, path: Option<String>) {
if self.stop_render()
@@ -1042,6 +1051,14 @@ impl Session {
self.script_ui.project_epoch = self.script_ui.project_epoch.wrapping_add(1);
p.fix_next_id();
upgrade_effects(&mut p);
// The media layer keys decoded frames by path: files of the new project may have changed
// since an earlier project decoded them (#1070).
for it in p.items.values() {
if let effectcraft_project::ItemKind::Footage(f) = &it.kind {
self.forget_decoded(f);
}
}
self.layer_cache.clear();
self.project = Arc::new(p);
self.history = History::default();
self.state = EditorState { snapping: true, view_layout: 1, ..Default::default() };
+19
View File
@@ -194,3 +194,22 @@ fn image_sequences_reload_by_themselves_only_with_all_footage() {
png(&b, 128);
assert_eq!(s.execute_checked("footage.reloadChanged", json!({})).unwrap()["files"], json!(1));
}
/// #1070: a file decoded in one project and overwritten with one of the same size is read again
/// when a new project imports it (neither File ▸ Reload Footage nor the change watcher knows it).
#[test]
fn a_new_project_importing_an_overwritten_file_shows_the_new_pixels() {
let path = tmp("overwritten.psd");
std::fs::write(&path, flat(RED, false)).unwrap();
let (mut s, _item, cid) = flat_in_comp(&path);
assert!(near(pixel(&s, cid, 32, 24), RED));
// Another app overwrites the file with the same number of bytes.
save(&path, &flat(BLUE, false));
s.execute_checked("file.newProject", json!({})).unwrap();
let r = s.execute_checked("file.import", json!({"paths": [path.clone()]})).unwrap();
let item = r["items"][0].as_u64().unwrap();
s.execute_checked("comp.new", json!({"name": "C", "width": 64, "height": 48, "frameRate": 30, "duration": 1})).unwrap();
s.execute_checked("layer.addItem", json!({"item": item})).unwrap();
let cid = s.active_comp_id().unwrap();
assert!(near(pixel(&s, cid, 32, 24), BLUE), "stale pixels from the earlier project: {:?}", pixel(&s, cid, 32, 24));
}