mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 10:01:58 +00:00
many_tiling_patterns_and_spot_inks_read_in_linear_time checked that a program setting 200,000 different tiling patterns and 200,001 spot inks reads within 20 s of wall-clock time. It reads in about 4 s alone; while the crate's full test suite ran in parallel it took more than 20 s and failed. In test builds, the tiling pattern lookup now counts on its thread how many patterns it compared with the one it looked for (tilings_compared, gated with cfg(test) like SELECTOR_TESTS in the SVG reader's CSS). The test, renamed many_tiling_patterns_are_found_again_through_a_hash, reads through import on a thread of its own and asserts that its 200,000 lookups compared at most 200,000 patterns in all. When every pattern hashes alike, as when each lookup went through every pattern made so far, the lookups compare 19,999,900,000 and the test fails. The test still reads the 200,001 spot inks and checks their swatches, but it does not count or time their lookups. The other tests that read through read_soon wait 300 s instead of 20 s, as a guard against a read that never ends; their budgets and limits decide what they check. work_on_the_longest_dash_pattern_ends_soon (4.5 s alone) now also checks that the states gsave, grestore, gstate, currentgstate and setgstate save, make or set hold the one 65,535-entry dash pattern, so a copy of the pattern in any of them fails it.
76 lines
3.8 KiB
Rust
76 lines
3.8 KiB
Rust
//! The graphics state and the operators that draw: coordinates, paths, colours, painting,
|
|
//! clipping and shadings. Painted paths become document objects as they are drawn ([`Out`]).
|
|
|
|
use std::collections::{HashMap, HashSet};
|
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
|
use std::rc::Rc;
|
|
use std::sync::Arc;
|
|
|
|
use kurbo::{PathEl, Shape};
|
|
use vectorcraft_color::swatch::REGISTRATION;
|
|
use vectorcraft_color::{Color, Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop, Paint};
|
|
use vectorcraft_doc::clipnest::{Clip, Drawn, MAX_NEST, deep_clips};
|
|
use vectorcraft_doc::pattern::PatternDef;
|
|
use vectorcraft_doc::{Appearance, AppearanceItem, Dash, Document, FillLayer, LineCap, LineJoin, Node, NodeId, NodeKind, StrokeLayer};
|
|
use vectorcraft_geom::{Affine, BezPath, FillRule, PathData, Point, Rect, Vec2};
|
|
|
|
use super::interp::{Interp, MAX_GSAVE, matrix_obj};
|
|
use super::obj::{DictRef, Key, Obj, Op, PsError, Res, Shared, clamp_between, ps_err};
|
|
|
|
mod ops;
|
|
mod paint;
|
|
mod path;
|
|
mod state;
|
|
mod strips;
|
|
|
|
pub(crate) use paint::collapse;
|
|
#[cfg(test)]
|
|
pub(crate) use paint::tilings_compared;
|
|
pub(crate) use state::{GState, Out, Space, process};
|
|
pub(crate) use strips::merge_strips;
|
|
|
|
/// Most objects one file makes.
|
|
const MAX_NODES: usize = 1 << 20;
|
|
/// Objects reaching further than this from the page (points) come from damaged coordinates and
|
|
/// are left out.
|
|
const LIMIT: f64 = 1e6;
|
|
/// Width of a zero-width line (the thinnest a device draws), points.
|
|
pub(super) const HAIRLINE: f64 = 0.25;
|
|
/// Most inks a `DeviceN` space has (PostScript's own limit).
|
|
const MAX_INKS: usize = 32;
|
|
/// Most dashes `strokepath` makes of a path (more and it outlines the path undashed).
|
|
const MAX_DASHES: f64 = 1e5;
|
|
/// Most entries a dash pattern has: the most elements an array has in a typical PostScript
|
|
/// implementation (PLRM 3rd ed., Table B.1).
|
|
const MAX_DASH_ENTRIES: usize = 65_535;
|
|
/// Most entries an indexed colour space's table has.
|
|
const MAX_HIVAL: usize = 4095;
|
|
/// Most elements the current path may have.
|
|
pub(crate) const MAX_PATH: usize = 1 << 20;
|
|
/// Most path elements drawn in all (each object's clips and groups counting as elements too).
|
|
const MAX_DRAWN: usize = 1 << 24;
|
|
/// Samples taken of a shading function that isn't a plain interpolation.
|
|
const SHADING_SAMPLES: usize = 32;
|
|
/// Most bounds of a stitched linear function that become a gradient's stops (two where the pieces
|
|
/// don't meet): past it, the function is sampled like any other (each stop evaluates the whole
|
|
/// function).
|
|
const MAX_STITCH_STOPS: usize = 1024;
|
|
/// Most functions one evaluation of a shading's function visits: the function itself, each entry
|
|
/// of an array of functions and, in each stitching function, the piece that applies to the input.
|
|
/// For every shading type, the `Function` entry is one function dictionary or an array of one for
|
|
/// each color component (PLRM 3rd ed., Tables 4.12 to 4.17; a type 7 shading has the entries of
|
|
/// type 6). The reader allows at most [`MAX_INKS`] components, and the depth limit allows each
|
|
/// entry a chain of at most 8 functions.
|
|
const MAX_FUNCTION_VISITS: usize = 1 + MAX_INKS * 8;
|
|
/// Work one function costs against the operation budget each time it is evaluated: about as much
|
|
/// as 8 operations (measured).
|
|
const FUNCTION_OPS: u64 = 8;
|
|
|
|
pub(super) const FAR_AWAY: &str = "objects far outside the page were left out";
|
|
pub(super) const TOO_MUCH: &str = "the file draws more than VectorCraft reads: the rest was left out";
|
|
const NESTED_PATTERNS: &str = "patterns nested too deeply are filled with mid-grey";
|
|
/// Deepest patterns and glyph procedures drawn inside each other's art.
|
|
pub(crate) const MAX_APART: u32 = 8;
|
|
const UNKNOWN_FUNCTIONS: &str = "shadings whose functions are of an unknown type are filled with their middle colour";
|
|
const UNKNOWN_SHADINGS: &str = "shadings of an unknown type were left out";
|