mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 05:46:46 -06:00
fix: 粘贴图片的内容哈希键被占用时改用空闲键
This commit is contained in:
@@ -391,8 +391,19 @@ pub(super) fn paint_paste(s: &mut Session, p: &Value, fills: bool) -> Result<Val
|
||||
if let Some(d) = s.clipboard.paint_images.get(&copied).cloned() {
|
||||
let doc = s.doc_mut()?;
|
||||
// The destination may already use that key for different data (other layers keep
|
||||
// that image): the pasted paint takes the copied data's content hash instead.
|
||||
let key = if doc.images.get(&copied).is_some_and(|existing| existing != &d) { figcraft_format::image_hash(&d.bytes) } else { copied };
|
||||
// that image): the pasted paint takes the copied data's content hash instead. That key
|
||||
// can be taken too — images are usually keyed by their hash, so the copied key often
|
||||
// is that hash — and then a numbered variant of it.
|
||||
let base = if doc.images.get(&copied).is_some_and(|existing| existing != &d) { figcraft_format::image_hash(&d.bytes) } else { copied };
|
||||
let mut key = base.clone();
|
||||
let mut n = 0u32;
|
||||
while doc.images.get(&key).is_some_and(|existing| existing != &d) {
|
||||
n = n.saturating_add(1);
|
||||
if n > 999 {
|
||||
return Err(bad(cmd, "no free image key for the copied image"));
|
||||
}
|
||||
key = format!("{base}-{n}");
|
||||
}
|
||||
doc.images.entry(key.clone()).or_insert(d);
|
||||
img.image = key;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,30 @@ fn a_copied_image_key_taken_in_another_file_gets_the_copied_data() {
|
||||
assert_eq!(doc.images.get("img-key"), Some(&taken), "the destination's image stays");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_copied_image_whose_hash_key_is_also_taken_gets_a_free_key() {
|
||||
let mut s = Session::new();
|
||||
let a = rect(&mut s);
|
||||
let bytes = vec![1, 2, 3];
|
||||
let copied = figcraft_doc::ImageData { bytes: std::sync::Arc::new(bytes.clone()), width: 2, height: 2 };
|
||||
let taken = figcraft_doc::ImageData { bytes: std::sync::Arc::new(vec![9, 9, 9]), width: 3, height: 3 };
|
||||
// Images are usually keyed by their content hash: here the copied key is that hash, and the
|
||||
// other file already uses it for other data, so the replacement key is taken as well.
|
||||
let hash = figcraft_format::image_hash(&bytes);
|
||||
ex(&mut s, "fill.add", json!({"ids": [a], "paint": {"type": "image", "image": hash}}));
|
||||
s.doc_mut().unwrap().images.insert(hash.clone(), copied.clone());
|
||||
ex(&mut s, "fill.copy", json!({"id": a, "index": 1}));
|
||||
ex(&mut s, "file.new", json!({}));
|
||||
let b = rect(&mut s);
|
||||
s.doc_mut().unwrap().images.insert(hash.clone(), taken.clone());
|
||||
ex(&mut s, "fill.paste", json!({"ids": [b], "index": 0}));
|
||||
let doc = s.doc().unwrap();
|
||||
let figcraft_color::PaintKind::Image(img) = &doc.node(b).unwrap().fills[0].kind else { panic!("the pasted fill is an image") };
|
||||
assert_ne!(img.image, hash, "the taken hash is not reused");
|
||||
assert_eq!(doc.images.get(&img.image), Some(&copied), "the pasted paint points at the copied data");
|
||||
assert_eq!(doc.images.get(&hash), Some(&taken), "the destination's image stays");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_copied_pattern_does_not_paste_into_another_file() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user