mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 20:27:05 -06:00
Edits refuse to leave anything beyond MAX_COORD (doc_sane checks the artboards, the guides, the ruler origin and the objects an edit touches), but the native loader didn't check them. A file with one object, artboard, guide or ruler origin out there opened without a warning, and then every move failed with "result would exceed the canvas", in-range objects included; saving kept it that way. Document::drop_beyond_canvas removes objects whose geometric bounds aren't finite or reach past MAX_COORD (a layer or non-clipping group keeps its children within it), artboards with their artboard guides, and guides out there, and puts the ruler origin back at the origin. load_file runs it after the depth limit and reports what it did with the other load notes; a file whose artboards all lie beyond the canvas is refused.
70 lines
3.7 KiB
Rust
70 lines
3.7 KiB
Rust
//! #3575: a native file holding an object, artboard, guide or ruler origin beyond the canvas
|
|
//! (`MAX_COORD`) opened, but every move then failed with "result would exceed the canvas": edits
|
|
//! check those. Opening it now removes them (or resets the ruler origin) and says so.
|
|
|
|
use serde_json::{Value, json};
|
|
use vectorcraft_engine::Session;
|
|
|
|
/// A saved two-rectangle document as JSON, with its first rectangle 1e17 pt down when `far_object`.
|
|
fn document(far_object: bool) -> Value {
|
|
let mut s = Session::new();
|
|
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
|
s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 50, "height": 30})).unwrap();
|
|
s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 20, "height": 20})).unwrap();
|
|
let mut v: Value = serde_json::from_slice(&vectorcraft_format::save(&s.doc().unwrap().doc, false)).unwrap();
|
|
if far_object {
|
|
let far = &mut v["document"]["layers"][0]["kind"]["children"][0]["kind"];
|
|
far["path"]["subpaths"][0]["anchors"].as_array_mut().unwrap().iter_mut().for_each(|a| a["p"][1] = json!(a["p"][1].as_f64().unwrap() + 1e17));
|
|
far["live"]["xf"][5] = json!(far["live"]["xf"][5].as_f64().unwrap() + 1e17);
|
|
}
|
|
v
|
|
}
|
|
|
|
/// Open `v` from a file, select everything and move it: → the open reply's warnings.
|
|
fn open_and_move(v: &Value, tag: &str) -> (Session, Value) {
|
|
let path = std::env::temp_dir().join(format!("vectorcraft-beyond-canvas-{tag}-{}.vectorcraft", std::process::id()));
|
|
std::fs::write(&path, serde_json::to_vec(v).unwrap()).unwrap();
|
|
let mut s = Session::new();
|
|
let opened = s.execute("document.open", &json!({"path": path}));
|
|
let _ = std::fs::remove_file(&path);
|
|
let opened = opened.unwrap();
|
|
s.execute("select.all", &json!({})).unwrap();
|
|
s.execute("object.move", &json!({"dx": 5, "dy": 5})).expect("everything left can be moved");
|
|
(s, opened["warnings"].clone())
|
|
}
|
|
|
|
#[test]
|
|
fn an_object_beyond_the_canvas_is_removed_on_open() {
|
|
let (s, warnings) = open_and_move(&document(true), "object");
|
|
assert_eq!(s.doc().unwrap().doc.layers[0].children().unwrap().len(), 1, "the far rectangle is gone, the other stays");
|
|
assert!(warnings.to_string().contains("1 object beyond the canvas"), "{warnings}");
|
|
}
|
|
|
|
#[test]
|
|
fn an_artboard_a_guide_or_a_ruler_origin_beyond_the_canvas_no_longer_blocks_edits() {
|
|
let mut v = document(false);
|
|
let mut far = v["document"]["artboards"][0].clone();
|
|
far["id"] = json!(9);
|
|
far["rect"] = json!({"x0": 0.0, "y0": 1e17, "x1": 100.0, "y1": 1e17 + 100.0});
|
|
v["document"]["artboards"].as_array_mut().unwrap().push(far);
|
|
v["document"]["guides"] = json!([{"vertical": false, "pos": 1e17}, {"vertical": true, "pos": 50.0}]);
|
|
v["document"]["ruler_origin"] = json!([1e17, 0.0]);
|
|
let (s, warnings) = open_and_move(&v, "setup");
|
|
let d = &s.doc().unwrap().doc;
|
|
assert_eq!((d.artboards.len(), d.guides.len(), d.ruler_origin.x), (1, 1, 0.0));
|
|
assert!(warnings.to_string().contains("1 artboard, 1 guide beyond the canvas"), "{warnings}");
|
|
assert!(warnings.to_string().contains("ruler origin"), "{warnings}");
|
|
}
|
|
|
|
#[test]
|
|
fn a_file_whose_artboards_all_lie_beyond_the_canvas_is_refused() {
|
|
let mut v = document(false);
|
|
v["document"]["artboards"][0]["rect"] = json!({"x0": 0.0, "y0": 1e17, "x1": 100.0, "y1": 1e17 + 100.0});
|
|
let path = std::env::temp_dir().join(format!("vectorcraft-beyond-canvas-pages-{}.vectorcraft", std::process::id()));
|
|
std::fs::write(&path, serde_json::to_vec(&v).unwrap()).unwrap();
|
|
let r = Session::new().execute("document.open", &json!({"path": path}));
|
|
let _ = std::fs::remove_file(&path);
|
|
let e = r.unwrap_err().to_string();
|
|
assert!(e.contains("artboards all lie beyond the canvas"), "{e}");
|
|
}
|