engine, plugins: cap radar dimensions, resume slice-name suffixes, weigh cache keys

This commit is contained in:
Dylan M. Taylor
2026-11-04 11:45:15 +07:00
committed by bflatastic
parent 64b1fa5ab2
commit 0cdcf3039b
3 changed files with 17 additions and 7 deletions
+3 -2
View File
@@ -244,7 +244,8 @@ impl<'a> Plot<'a> {
if marker_cost(g, &designs) > MARKER_BUDGET {
designs.clear();
}
let nser = g.rows.iter().map(Vec::len).max().unwrap_or(0).max(1);
// The same dimensions `GraphSpec::cells` reads: raw rows can be longer than the grid they are read through.
let nser = g.rows.iter().map(Vec::len).max().unwrap_or(0).clamp(1, vectorcraft_doc::MAX_GRAPH_SERIES);
let kinds: Vec<GraphKind> = (0..nser).map(|s| g.series_kind(s)).collect();
Plot {
g,
@@ -253,7 +254,7 @@ impl<'a> Plot<'a> {
designs,
r: g.rect,
nser,
ncat: g.rows.len().max(1),
ncat: g.rows.len().clamp(1, vectorcraft_doc::MAX_GRAPH_CATEGORIES),
vs: label_size(&g.label_styles, Role::Value),
cs: label_size(&g.label_styles, Role::Category),
ls: label_size(&g.label_styles, Role::Legend),
+4 -2
View File
@@ -21,7 +21,7 @@ use vectorcraft_render::encode::quantize::{self, Dither, Indexed, PaletteOptions
use vectorcraft_render::encode::web::{self, ColorSort};
use vectorcraft_render::encode::{gif, jpeg, png};
use super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, f64_or, has_doc, str_param, unique_name};
use super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, f64_or, has_doc, str_param, unique_name_from};
const C: &str = "document.exportForWeb";
@@ -866,6 +866,8 @@ pub fn export_files(doc: &Document, selected: &[NodeId], s: &WebSettings, stem:
placed.push((None, Some(name)));
} else {
let mut taken = HashSet::new();
// Per base, where the suffix search resumes, so many slices of one name don't each count up from 2.
let mut next = std::collections::HashMap::new();
for c in &cells {
let kind = c.area.id.and_then(|id| doc.slice_options(id)).map(|o| o.kind).unwrap_or_default();
if kind != SliceKind::Image {
@@ -875,7 +877,7 @@ pub fn export_files(doc: &Document, selected: &[NodeId], s: &WebSettings, stem:
let base: String = doc.slice_name(c.area).chars().map(|ch| if ch.is_alphanumeric() || "-_.".contains(ch) { ch } else { '-' }).collect();
// A slice named after a Windows device (`aux`, `NUL`…) gets a `-` after the device name.
let file = |base: &str| super::fileio::safe_file_name(&format!("{base}.{ext}"));
let base = unique_name(&base, |n| taken.contains(&file(n).to_lowercase()));
let base = unique_name_from(&base, &mut next, |n| taken.contains(&file(n).to_lowercase()));
taken.insert(file(&base).to_lowercase());
let name = format!("{IMAGES}/{}", file(&base));
let [x0, y0, x1, y1] = c.px;
+10 -3
View File
@@ -120,8 +120,15 @@ struct Cache {
static CACHE: Mutex<Option<Cache>> = Mutex::new(None);
/// Cache units a path takes: its anchors, and one for each subpath's own allocation.
fn anchors(p: &PathData) -> usize {
p.subpaths.iter().map(|sp| sp.anchors.len()).sum()
p.subpaths.iter().map(|sp| sp.anchors.len() + 1).sum()
}
/// Cache units an entry takes: its input and result paths, and the serialized parameters and
/// paints its key owns (one unit per [`CACHE_ANCHORS`]'s 50 bytes an anchor stands for).
fn weight(key: &Key, out: Option<&PathData>) -> usize {
anchors(&key.path) + out.map_or(0, anchors) + (key.params.len() + key.paints.len()) / 50 + 1
}
static ERRORS: Mutex<Option<HashMap<String, String>>> = Mutex::new(None);
@@ -168,7 +175,7 @@ pub fn apply(id: &str, params: &Value, path: &PathData, bounds: Rect, rule: Fill
}
note(id, &r);
let out = r.ok();
let size = anchors(&key.path) + out.as_ref().map_or(0, anchors);
let size = weight(&key, out.as_ref());
if size > CACHE_ANCHORS / 4 {
return out;
}
@@ -178,7 +185,7 @@ pub fn apply(id: &str, params: &Value, path: &PathData, bounds: Rect, rule: Fill
*cache = Cache::default();
}
if let Some((old, old_out)) = cache.entries.insert(h, (key, out.clone())) {
cache.anchors = cache.anchors.saturating_sub(anchors(&old.path) + old_out.as_ref().map_or(0, anchors));
cache.anchors = cache.anchors.saturating_sub(weight(&old, old_out.as_ref()));
}
cache.anchors += size;
out