mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Cap path elements in DXF import across the whole file
Squashed from #3800 onto main.
This commit is contained in:
@@ -25,12 +25,15 @@ const THINNEST: f64 = 0.25;
|
||||
const MAX_NODES: usize = 2_000_000;
|
||||
/// The most block visits (one per insert copy) an import makes, whatever they produce.
|
||||
const MAX_VISITS: usize = 10_000_000;
|
||||
/// The most path elements an import makes (blocks drawn as art are copied for every placement).
|
||||
const MAX_ELEMENTS: usize = if cfg!(test) { 1_000_000 } else { 4_000_000 };
|
||||
/// How far from the origin art may lie (points): the canvas.
|
||||
pub(crate) const MAX_EXTENT: f64 = 4.0e6;
|
||||
|
||||
const NESTED: &str = "blocks nested more than 8 deep, or inside themselves, are left out";
|
||||
const XREFS: &str = "blocks referencing other drawings (external references) are left out";
|
||||
const TOO_MANY: &str = "the drawing has more than 2,000,000 objects: the rest are left out";
|
||||
const TOO_MANY_POINTS: &str = "the drawing has more than 4,000,000 path points: the rest are left out";
|
||||
|
||||
/// What a block's art takes from the insert that places it: its colour, lineweight, linetype
|
||||
/// and opacity where the art says "by block", and its layer for art on layer 0.
|
||||
@@ -66,6 +69,8 @@ pub(crate) struct Build<'d, 'a> {
|
||||
lw_scale: f64,
|
||||
nodes: usize,
|
||||
visits: usize,
|
||||
/// Path elements made so far.
|
||||
elements: usize,
|
||||
warnings: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -122,6 +127,7 @@ impl<'d, 'a> Build<'d, 'a> {
|
||||
lw_scale: 1.0,
|
||||
nodes: 0,
|
||||
visits: 0,
|
||||
elements: 0,
|
||||
warnings: vec![],
|
||||
}
|
||||
}
|
||||
@@ -451,6 +457,12 @@ impl<'d, 'a> Build<'d, 'a> {
|
||||
}
|
||||
|
||||
fn path(&mut self, bp: &BezPath, fill: bool, width: f64, p: &Props, map: Affine, inh: &Inherit) -> Option<Node> {
|
||||
let n = bp.elements().len();
|
||||
if self.elements.saturating_add(n) > MAX_ELEMENTS {
|
||||
self.warn(TOO_MANY_POINTS);
|
||||
return None;
|
||||
}
|
||||
self.elements += n;
|
||||
let mut bp = bp.clone();
|
||||
bp.apply_affine(map);
|
||||
super::curve::bounds(&bp)?;
|
||||
|
||||
@@ -817,6 +817,30 @@ fn nested_array_inserts_of_nothing_stop_at_the_work_budget() {
|
||||
assert!(r.warnings.iter().any(|w| w.contains("more than")), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_array_of_a_large_anonymous_block_stops_at_the_path_element_budget() {
|
||||
// A 2,000-vertex polyline in *U1, placed in a 100 × 10 array: 2,000,000 path elements when
|
||||
// every cell is copied, twice the budget tests import with.
|
||||
let mut owned: Vec<(i32, String)> = vec![(0, "BLOCK".into()), (2, "*U1".into()), (70, "1".into()), (10, "0".into()), (20, "0".into())];
|
||||
owned.extend([(0, "LWPOLYLINE".into()), (90, "2000".into()), (70, "0".into())]);
|
||||
for i in 0..2000 {
|
||||
owned.extend([(10, i.to_string()), (20, (i % 2).to_string())]);
|
||||
}
|
||||
owned.push((0, "ENDBLK".into()));
|
||||
let blocks: Vec<(i32, &str)> = owned.iter().map(|(c, v)| (*c, v.as_str())).collect();
|
||||
let inserts = [(0, "INSERT"), (2, "*U1"), (10, "0"), (20, "0"), (70, "100"), (71, "10"), (44, "2000"), (45, "2")];
|
||||
let r = open(&drawing(&[], &[], &blocks, &inserts), &points());
|
||||
let mut elements = 0;
|
||||
r.document.walk(|n| {
|
||||
if let NodeKind::Path { path, .. } = &n.kind {
|
||||
elements += path.to_bezpath().elements().len();
|
||||
}
|
||||
});
|
||||
assert!(elements > 0);
|
||||
assert!(elements <= 1_000_000, "{elements} path elements");
|
||||
assert!(r.warnings.iter().any(|w| w.contains("path points")), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocks_inside_themselves_are_left_out_without_hanging() {
|
||||
let blocks = [
|
||||
|
||||
Reference in New Issue
Block a user