diff --git a/apps/vectorcraft/src/printing.rs b/apps/vectorcraft/src/printing.rs index c9e6539a2..5464bb959 100644 --- a/apps/vectorcraft/src/printing.rs +++ b/apps/vectorcraft/src/printing.rs @@ -38,7 +38,7 @@ impl PrintService for SystemPrint { #[cfg(not(all(windows, any(feature = "windows7", target_vendor = "win7"))))] mod system { - use super::*; + use super::{Command, PrintJob, Printer}; pub fn printers() -> Vec { craft_print::printers().into_iter().map(|p| Printer { name: p.name, default: p.default }).collect() } diff --git a/crates/engine/src/cmd/fileinfo.rs b/crates/engine/src/cmd/fileinfo.rs index 549d0982c..36ccd7cdb 100644 --- a/crates/engine/src/cmd/fileinfo.rs +++ b/crates/engine/src/cmd/fileinfo.rs @@ -7,7 +7,7 @@ use serde_json::{Map, Value, json}; use vectorcraft_doc::metadata::{MAX_RATING, iso8601}; use vectorcraft_doc::{ColorMode, CopyrightStatus, DocMetadata, Document}; -use super::*; +use super::{Result, Session, bad}; const C: &str = "file.info"; /// Longest text field, in characters. diff --git a/crates/engine/src/cmd/fileio.rs b/crates/engine/src/cmd/fileio.rs index 6e5c9402e..6893c6f84 100644 --- a/crates/engine/src/cmd/fileio.rs +++ b/crates/engine/src/cmd/fileio.rs @@ -92,7 +92,7 @@ pub use svg::options_map as svg_options; #[cfg(not(target_arch = "wasm32"))] pub use vectorcraft_format::write_atomic; -use super::*; +use super::{CommandSpec, Result, Session, always, bad, cmd, has_doc, has_selection}; use crate::EngineError; mod access; diff --git a/crates/engine/src/cmd/fileio/access.rs b/crates/engine/src/cmd/fileio/access.rs index 8dfbead2d..ffe34acfd 100644 --- a/crates/engine/src/cmd/fileio/access.rs +++ b/crates/engine/src/cmd/fileio/access.rs @@ -1,4 +1,6 @@ -use super::*; +#[cfg(not(target_arch = "wasm32"))] +use super::write_atomic; +use super::{EngineError, Result, Session, Value, bad, json}; // ---------- the file system (none on the web, where commands take and return bytes) ---------- // diff --git a/crates/engine/src/cmd/fileio/action_batch.rs b/crates/engine/src/cmd/fileio/action_batch.rs index 90856aaa4..d1db60302 100644 --- a/crates/engine/src/cmd/fileio/action_batch.rs +++ b/crates/engine/src/cmd/fileio/action_batch.rs @@ -9,7 +9,9 @@ use serde_json::Value; #[cfg(not(target_arch = "wasm32"))] use serde_json::json; -use super::super::*; +use super::super::{Result, Session, bad}; +#[cfg(not(target_arch = "wasm32"))] +use super::super::{bool_or, find_command, str_param}; #[cfg(target_arch = "wasm32")] pub(super) fn action_batch(_: &mut Session, _: &Value) -> Result { diff --git a/crates/engine/src/cmd/fileio/affinity/document.rs b/crates/engine/src/cmd/fileio/affinity/document.rs index 0d74d1d81..e87e9ac0f 100644 --- a/crates/engine/src/cmd/fileio/affinity/document.rs +++ b/crates/engine/src/cmd/fileio/affinity/document.rs @@ -1,7 +1,7 @@ use super::layout::{master_instances, master_prefix, page_masters}; use super::master_copies::{CopyCost, MAX_MASTER_COPIES, MasterPart, copy_cost}; use super::nodes::rect_of; -use super::*; +use super::{Affine, Arc, Artboard, Blend, Builder, Document, Kind, Node, NodeKind, Result, af, err}; impl Builder { pub(super) fn new(k: f64) -> Self { diff --git a/crates/engine/src/cmd/fileio/affinity/import.rs b/crates/engine/src/cmd/fileio/affinity/import.rs index 625df1e3b..0b0d587d8 100644 --- a/crates/engine/src/cmd/fileio/affinity/import.rs +++ b/crates/engine/src/cmd/fileio/affinity/import.rs @@ -1,4 +1,4 @@ -use super::*; +use super::{Builder, Cursor, Document, Result, err, raster_doc}; /// What an Affinity file opened as. pub(in super::super) struct Imported { diff --git a/crates/engine/src/cmd/fileio/affinity/layout.rs b/crates/engine/src/cmd/fileio/affinity/layout.rs index 157a38836..8b6d4c4a8 100644 --- a/crates/engine/src/cmd/fileio/affinity/layout.rs +++ b/crates/engine/src/cmd/fileio/affinity/layout.rs @@ -1,5 +1,5 @@ use super::nodes::MAX_DEPTH; -use super::*; +use super::{AfAlign, CharStyle, Cursor, Justify, Kind, Rect, TextKind, TextObject, VerticalAlign, af, shapes}; /// The master page instances among `nodes` (also inside layers and groups): (master, first page, /// first master page, page count). diff --git a/crates/engine/src/cmd/fileio/affinity/master_copies.rs b/crates/engine/src/cmd/fileio/affinity/master_copies.rs index bc55dbc25..91b0ce53c 100644 --- a/crates/engine/src/cmd/fileio/affinity/master_copies.rs +++ b/crates/engine/src/cmd/fileio/affinity/master_copies.rs @@ -1,5 +1,5 @@ use super::nodes::MAX_DEPTH; -use super::*; +use super::{Kind, af}; /// What copying a subtree takes: its nodes, characters and table cells (`work`), and its pixels. #[derive(Clone, Copy, Debug, Default)] diff --git a/crates/engine/src/cmd/fileio/affinity/nodes.rs b/crates/engine/src/cmd/fileio/affinity/nodes.rs index a3867d0bd..0375ff39e 100644 --- a/crates/engine/src/cmd/fileio/affinity/nodes.rs +++ b/crates/engine/src/cmd/fileio/affinity/nodes.rs @@ -1,4 +1,4 @@ -use super::*; +use super::{Affine, Arc, Blend, BlendMode, Builder, FillRule, Kind, LayerColor, Node, NodeKind, OpacityMask, Rect, af}; /// Deepest node tree mapped (the reader bounds trees well below this). pub(super) const MAX_DEPTH: usize = 160; diff --git a/crates/engine/src/cmd/fileio/affinity/paint.rs b/crates/engine/src/cmd/fileio/affinity/paint.rs index a60911e0d..ce798dcfb 100644 --- a/crates/engine/src/cmd/fileio/affinity/paint.rs +++ b/crates/engine/src/cmd/fileio/affinity/paint.rs @@ -1,7 +1,11 @@ use super::layout::png; use super::nodes::affine; use super::text::Placement; -use super::*; +use super::{ + AfKind, Affine, Appearance, AppearanceItem, Arc, BezPath, Builder, Cap, Color, Dash, Effect, FillLayer, Gradient, GradientGeom, GradientKind, + GradientPaint, GradientStop, ImageObject, Join, LineCap, LineJoin, NodeKind, Paint, PathData, Pixels, Point, StrokeAlign, StrokeLayer, + TextObject, Vec2, af, ap, json, +}; impl Builder { /// Drop shadows, inner shadows and outer glows as VectorCraft's Stylize effects. Affinity's diff --git a/crates/engine/src/cmd/fileio/affinity/text.rs b/crates/engine/src/cmd/fileio/affinity/text.rs index cae76dc7b..beaaac541 100644 --- a/crates/engine/src/cmd/fileio/affinity/text.rs +++ b/crates/engine/src/cmd/fileio/affinity/text.rs @@ -1,6 +1,9 @@ use super::layout::{align_lines, fit_lines, font_style, justify, line_gap, place_cell}; use super::nodes::affine; -use super::*; +use super::{ + Affine, Appearance, AppearanceItem, Arc, BezPath, Builder, CharStyle, FillRule, FirstBaseline, Node, NodeKind, Paint, PathData, Point, Rect, + TextKind, TextObject, TextRun, Vec2, VerticalAlign, af, ap, shapes, +}; /// Where text goes: a rigid placement (translation and rotation) and the scale that maps node /// space into it (applied to the frame's geometry, not the type), plus the type's own scale. diff --git a/crates/engine/src/cmd/fileio/batch.rs b/crates/engine/src/cmd/fileio/batch.rs index ff8b8aece..d5aa6d144 100644 --- a/crates/engine/src/cmd/fileio/batch.rs +++ b/crates/engine/src/cmd/fileio/batch.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use serde_json::{Value, json}; use vectorcraft_doc::Document; -use super::super::*; +use super::super::{Result, Session, bad, str_param}; use crate::{DocState, EngineError}; pub(super) fn batch(s: &mut Session, p: &Value) -> Result { diff --git a/crates/engine/src/cmd/fileio/commands.rs b/crates/engine/src/cmd/fileio/commands.rs index 0a0a8549f..4be6d8ccb 100644 --- a/crates/engine/src/cmd/fileio/commands.rs +++ b/crates/engine/src/cmd/fileio/commands.rs @@ -1,6 +1,6 @@ use super::access::file_list; use super::formats::formats; -use super::*; +use super::{CommandSpec, action_batch, always, batch, cmd, export, has_doc, has_selection, load, pdfimport, save, screens}; pub fn specs() -> Vec { vec![ diff --git a/crates/engine/src/cmd/fileio/dxf.rs b/crates/engine/src/cmd/fileio/dxf.rs index f0bb1f400..a569f1b4c 100644 --- a/crates/engine/src/cmd/fileio/dxf.rs +++ b/crates/engine/src/cmd/fileio/dxf.rs @@ -10,7 +10,7 @@ use vectorcraft_cad::{ColorDepth, DxfOptions, DxfVersion, Preserve, RasterFormat use vectorcraft_doc::{Document, Unit}; use vectorcraft_geom::Rect; -use super::super::*; +use super::super::{CommandSpec, Result, Session, bad, cmd, has_doc}; use super::{ArtboardPick, Encoded, FormatOption}; const C: &str = "document.export"; diff --git a/crates/engine/src/cmd/fileio/dxfimport.rs b/crates/engine/src/cmd/fileio/dxfimport.rs index 3d2b66640..96fb71510 100644 --- a/crates/engine/src/cmd/fileio/dxfimport.rs +++ b/crates/engine/src/cmd/fileio/dxfimport.rs @@ -7,7 +7,7 @@ use serde_json::{Value, json}; use vectorcraft_cad::ImportOptions; use vectorcraft_doc::{Document, Unit}; -use super::super::*; +use super::super::{CommandSpec, Result, Session, always, bad, cmd}; use super::{err, source}; pub fn specs() -> Vec { diff --git a/crates/engine/src/cmd/fileio/encode.rs b/crates/engine/src/cmd/fileio/encode.rs index fbc18b422..30f9729ad 100644 --- a/crates/engine/src/cmd/fileio/encode.rs +++ b/crates/engine/src/cmd/fileio/encode.rs @@ -14,7 +14,7 @@ use vectorcraft_render::encode::quantize::{Dither, PaletteOptions, Reduction}; use vectorcraft_render::encode::tiff::{ByteOrder, TiffOptions}; use vectorcraft_render::encode::{RasterExportOptions, RasterFormat, bmp, psd, tga}; -use super::super::*; +use super::super::{EngineError, Result, bad, color_value, parse_range}; use super::Format; use super::imagemap::{self, MapKind}; diff --git a/crates/engine/src/cmd/fileio/eps.rs b/crates/engine/src/cmd/fileio/eps.rs index d33037715..dd6bbb7fe 100644 --- a/crates/engine/src/cmd/fileio/eps.rs +++ b/crates/engine/src/cmd/fileio/eps.rs @@ -13,7 +13,7 @@ use vectorcraft_eps::{EpsOptions, Level, Overprint, Preview, Raster}; use vectorcraft_geom::{Point, Rect}; use super::super::flatten::{FlattenOptions, flatten_document}; -use super::super::*; +use super::super::{CommandSpec, EngineError, Result, Session, bad, cmd, has_doc, str_param}; use super::{ArtboardPick, Encoded, FormatOption}; const C: &str = "document.export"; diff --git a/crates/engine/src/cmd/fileio/export.rs b/crates/engine/src/cmd/fileio/export.rs index dd7307e84..2a3ff0e78 100644 --- a/crates/engine/src/cmd/fileio/export.rs +++ b/crates/engine/src/cmd/fileio/export.rs @@ -9,7 +9,7 @@ use vectorcraft_doc::{Document, Node, NodeId, NodeKind, SymbolBoxes}; use crate::DocState; -use super::super::*; +use super::super::{Result, Session, bad, bool_or, edit, f64_or, str_param}; use super::encode::single_artboard; use super::{ ARTBOARD_PARAMS, Format, default_name, encode_all, encode_with_warnings, merge, with_black_output, writable, write_encoded, write_or_return, diff --git a/crates/engine/src/cmd/fileio/export_names.rs b/crates/engine/src/cmd/fileio/export_names.rs index c512c4c4c..66bd6d395 100644 --- a/crates/engine/src/cmd/fileio/export_names.rs +++ b/crates/engine/src/cmd/fileio/export_names.rs @@ -1,5 +1,5 @@ use super::access::write_file; -use super::*; +use super::{Encoded, EngineError, Result, Session, Value, json}; /// File-name parts for artboards `boards` of `doc`: the artboard's name with unsafe characters as /// `-`, `Artboard-N` when unnamed, and `-2`, `-3`… after a name already used (compared without diff --git a/crates/engine/src/cmd/fileio/formats.rs b/crates/engine/src/cmd/fileio/formats.rs index a9d6f88ac..da62d3e20 100644 --- a/crates/engine/src/cmd/fileio/formats.rs +++ b/crates/engine/src/cmd/fileio/formats.rs @@ -1,4 +1,4 @@ -use super::*; +use super::{Result, Session, TEMPLATE_FORMATS, UNSUPPORTED, Unsupported, Value, bad, dxf, eps, json, metafile, native, pdf, svg, text, unsupported}; /// One option a format's encoder reads from the export params. #[derive(Clone, Copy, Debug)] diff --git a/crates/engine/src/cmd/fileio/legacy_ai.rs b/crates/engine/src/cmd/fileio/legacy_ai.rs index 36b65d29e..c7c467dc8 100644 --- a/crates/engine/src/cmd/fileio/legacy_ai.rs +++ b/crates/engine/src/cmd/fileio/legacy_ai.rs @@ -37,7 +37,7 @@ use vectorcraft_color::BlendMode; use vectorcraft_doc::{Document, ImageBlob, ImageObject, Node, NodeKind}; use vectorcraft_geom::{Anchor, FillRule, PathData, Point, Rect, SubPath}; -use super::super::*; +use super::super::{Affine, EngineError, NodeId, Result, bad}; use super::{ArtboardPick, Encoded, Format}; /// Does `p` ask a save in `f` for a legacy `.ai` file of version 7 (`aiVersion: "7"`)? An unknown diff --git a/crates/engine/src/cmd/fileio/load.rs b/crates/engine/src/cmd/fileio/load.rs index 56f5aa0d7..59e784073 100644 --- a/crates/engine/src/cmd/fileio/load.rs +++ b/crates/engine/src/cmd/fileio/load.rs @@ -7,7 +7,7 @@ use vectorcraft_doc::{Document, ImageBlob, ImageObject, Node, NodeKind}; use vectorcraft_geom::Affine; use vectorcraft_render::effects::pixel::LoadedTexture; -use super::super::*; +use super::super::{Result, Session, bad, bool_or, clipboard, parse_range, str_param}; use super::pdfimport::LoadOptions; use super::{Format, SAVE_FORMATS, absolute_path, file_stamp, format, format_for_name, psdread, read_file}; use crate::cmd::links::Resolved; diff --git a/crates/engine/src/cmd/fileio/metafile.rs b/crates/engine/src/cmd/fileio/metafile.rs index 2c54d72e4..6bc658a4a 100644 --- a/crates/engine/src/cmd/fileio/metafile.rs +++ b/crates/engine/src/cmd/fileio/metafile.rs @@ -7,7 +7,7 @@ use serde_json::Value; use vectorcraft_doc::Document; use vectorcraft_metafile::Kind; -use super::super::*; +use super::super::{Result, bad}; use super::{ArtboardPick, Encoded, FormatOption}; const C: &str = "document.export"; diff --git a/crates/engine/src/cmd/fileio/native.rs b/crates/engine/src/cmd/fileio/native.rs index bcca24c34..d7dbbe5a6 100644 --- a/crates/engine/src/cmd/fileio/native.rs +++ b/crates/engine/src/cmd/fileio/native.rs @@ -12,7 +12,7 @@ use vectorcraft_color::cms; use vectorcraft_doc::Document; use vectorcraft_format::{PREVIEW_MAX, SaveOptions}; -use super::super::*; +use super::super::{EngineError, Result, bad}; use super::{Format, FormatOption}; /// The options `document.save` and the native encoder read. diff --git a/crates/engine/src/cmd/fileio/pdf.rs b/crates/engine/src/cmd/fileio/pdf.rs index df512f629..7902a0fed 100644 --- a/crates/engine/src/cmd/fileio/pdf.rs +++ b/crates/engine/src/cmd/fileio/pdf.rs @@ -11,7 +11,7 @@ use vectorcraft_doc::{Document, Node, NodeKind}; use vectorcraft_pdf::{Overprint, PdfError, PdfOptions, PdfPreset, PdfSettings, Standard, THUMBNAIL_SIZE, Thumbnail}; use super::super::flatten::{FlattenOptions, flatten_document, see_through_images}; -use super::super::*; +use super::super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, has_doc, str_param}; use super::{ArtboardPick, FormatOption, write_or_return}; use crate::EngineError; diff --git a/crates/engine/src/cmd/fileio/pdfimport.rs b/crates/engine/src/cmd/fileio/pdfimport.rs index e747be71f..80575c23f 100644 --- a/crates/engine/src/cmd/fileio/pdfimport.rs +++ b/crates/engine/src/cmd/fileio/pdfimport.rs @@ -7,7 +7,7 @@ use vectorcraft_doc::{ColorMode, Document}; use vectorcraft_pdf::{Choice, CropTo, ImportOptions, PdfError, TextAs}; use super::super::colormgmt::Grays; -use super::super::*; +use super::super::{Result, Session, bad, f64_or, parse_range, str_param}; use super::{err, source}; /// The `document.open` options besides the file. The PDF ones (pages, box, password, text, diff --git a/crates/engine/src/cmd/fileio/save.rs b/crates/engine/src/cmd/fileio/save.rs index 486777a24..7bd605b70 100644 --- a/crates/engine/src/cmd/fileio/save.rs +++ b/crates/engine/src/cmd/fileio/save.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use serde_json::{Map, Value, json}; use vectorcraft_doc::Document; -use super::super::*; +use super::super::{CommandSpec, Result, Session, always, bad, bool_or, clock_date, cmd, date_param, has_doc, str_param}; use super::{ ARTBOARD_PARAMS, ArtboardPick, Encoded, Format, Loaded, encode_all, file_stem, format, format_for_name, load, read_file, with_compression_pref, write_encoded, diff --git a/crates/engine/src/cmd/fileio/screens.rs b/crates/engine/src/cmd/fileio/screens.rs index ab8a0c432..328b1ca05 100644 --- a/crates/engine/src/cmd/fileio/screens.rs +++ b/crates/engine/src/cmd/fileio/screens.rs @@ -16,7 +16,7 @@ use serde_json::{Map, Value, json}; use vectorcraft_doc::Document; use vectorcraft_geom::Rect; -use super::super::*; +use super::super::{NodeId, Result, Session, bad, str_param}; use super::encode::single_artboard; use super::export::{export_crop, isolated, selected_artwork, without_artboards}; use super::naming::{self, NameParts}; diff --git a/crates/engine/src/cmd/fileio/tests.rs b/crates/engine/src/cmd/fileio/tests.rs index 2cbfdd9b7..f2b770682 100644 --- a/crates/engine/src/cmd/fileio/tests.rs +++ b/crates/engine/src/cmd/fileio/tests.rs @@ -386,8 +386,8 @@ fn open_exts_cover_every_readable_format() { #[test] fn library_open_filters_list_library_formats_first() { - let filters: Vec<_> = library_open_filters("Swatch libraries", super::swatchlib::LIBRARY_EXTS).collect(); - assert_eq!(filters[0], ("Swatch libraries", super::swatchlib::LIBRARY_EXTS)); + let filters: Vec<_> = library_open_filters("Swatch libraries", crate::cmd::swatchlib::LIBRARY_EXTS).collect(); + assert_eq!(filters[0], ("Swatch libraries", crate::cmd::swatchlib::LIBRARY_EXTS)); assert!(filters[0].1.contains(&"ase")); assert_eq!(filters[1], ("All readable files", OPEN_EXTS)); } diff --git a/crates/engine/src/cmd/fileio/tests_metafile.rs b/crates/engine/src/cmd/fileio/tests_metafile.rs index 80c15ace3..b02d16508 100644 --- a/crates/engine/src/cmd/fileio/tests_metafile.rs +++ b/crates/engine/src/cmd/fileio/tests_metafile.rs @@ -140,7 +140,7 @@ fn metafiles_open_and_place() { let placed = st.doc.layers[0].children().unwrap().last().unwrap().clone(); assert_eq!(placed.name.as_deref(), Some("pic.emf")); assert!(matches!(placed.kind, NodeKind::Group { clip: true, .. })); - let ext = fileio::PLACE_EXTS; + let ext = crate::cmd::fileio::PLACE_EXTS; assert!(ext.contains(&"emf") && ext.contains(&"wmf") && OPEN_EXTS.contains(&"emf") && OPEN_EXTS.contains(&"wmf")); } diff --git a/crates/engine/src/cmd/fileio/text.rs b/crates/engine/src/cmd/fileio/text.rs index 7e01a775a..85246456b 100644 --- a/crates/engine/src/cmd/fileio/text.rs +++ b/crates/engine/src/cmd/fileio/text.rs @@ -8,7 +8,7 @@ use serde::Deserialize; use serde_json::Value; use vectorcraft_doc::{Document, Node, NodeId, NodeKind}; -use super::super::*; +use super::super::{Result, bad}; use super::FormatOption; const C: &str = "document.export"; diff --git a/crates/engine/src/cmd/pdfcmds.rs b/crates/engine/src/cmd/pdfcmds.rs index faa986795..c9c94d808 100644 --- a/crates/engine/src/cmd/pdfcmds.rs +++ b/crates/engine/src/cmd/pdfcmds.rs @@ -8,7 +8,7 @@ use serde_json::{Value, json}; use vectorcraft_pdf::{PdfPreset, builtin_preset, builtin_presets}; use super::fileio::pdf::{find_preset, resolve}; -use super::*; +use super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, str_param, unique_name}; /// The `format` of a PDF presets file, also its extension. pub const PRESET_FORMAT: &str = "vcpdfpresets"; diff --git a/crates/engine/src/cmd/place.rs b/crates/engine/src/cmd/place.rs index 7089c2feb..ed4d0aba4 100644 --- a/crates/engine/src/cmd/place.rs +++ b/crates/engine/src/cmd/place.rs @@ -44,7 +44,7 @@ use vectorcraft_geom::{Affine, Point, Rect, shapes}; use vectorcraft_pdf::CropTo; use super::fileio::{self, Format, RasterImage}; -use super::*; +use super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, finite_numbers, has_doc, id_param, str_param, unique_name}; use crate::{EngineError, MAX_COORD}; const PLACE: &str = "file.place"; diff --git a/crates/engine/src/cmd/place/document.rs b/crates/engine/src/cmd/place/document.rs index 650ff9992..25dcd1538 100644 --- a/crates/engine/src/cmd/place/document.rs +++ b/crates/engine/src/cmd/place/document.rs @@ -25,7 +25,7 @@ use vectorcraft_geom::{Affine, Rect}; use vectorcraft_pdf::CropTo; use super::super::fileio; -use super::super::*; +use super::super::{EngineError, NodeId, Result, bad}; /// The largest file placed (bytes). pub(crate) const MAX_FILE: usize = 256 << 20; diff --git a/crates/engine/src/cmd/place/docx.rs b/crates/engine/src/cmd/place/docx.rs index c67c77ca4..063444442 100644 --- a/crates/engine/src/cmd/place/docx.rs +++ b/crates/engine/src/cmd/place/docx.rs @@ -43,7 +43,7 @@ use vectorcraft_doc::text::Kashida; use vectorcraft_doc::{CharPosition, CharStyle, Justify, ParaDirection, ParaStyle, ScriptMetrics, TextRun}; use super::text::{self, Story}; -use super::*; +use super::{EngineError, Paint, Result, bad, fileio}; use crate::cmd::fileio::zip::{self, Archive, ReadError}; /// Word documents as `file.place` reports them (not a format `document.open` reads). diff --git a/crates/engine/src/cmd/place/rtf.rs b/crates/engine/src/cmd/place/rtf.rs index 9bfeb67f7..b28797061 100644 --- a/crates/engine/src/cmd/place/rtf.rs +++ b/crates/engine/src/cmd/place/rtf.rs @@ -31,7 +31,7 @@ use std::collections::HashMap; use vectorcraft_doc::{CharPosition, CharStyle, Justify, ParaDirection, ParaStyle, ScriptMetrics, TextRun}; use super::text::{self, Story}; -use super::*; +use super::{Paint, Result, bad, fileio}; /// RTF files as `file.place` reports them (not a format `document.open` reads). pub(super) const FORMAT: fileio::Format = fileio::Format { diff --git a/crates/engine/src/cmd/place/text.rs b/crates/engine/src/cmd/place/text.rs index 78302890c..15c5f2575 100644 --- a/crates/engine/src/cmd/place/text.rs +++ b/crates/engine/src/cmd/place/text.rs @@ -3,7 +3,7 @@ use serde_json::Value; -use super::*; +use super::{Point, Rect, Result, bad, bool_or, fileio, shapes, str_param}; /// Text files as `file.place` reports them (not a format `document.open` reads). pub(super) const FORMAT: fileio::Format = fileio::Format { diff --git a/crates/engine/src/cmd/webexport.rs b/crates/engine/src/cmd/webexport.rs index a2e854ac9..c67d9428f 100644 --- a/crates/engine/src/cmd/webexport.rs +++ b/crates/engine/src/cmd/webexport.rs @@ -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::*; +use super::{CommandSpec, Result, Session, always, bad, bool_or, cmd, f64_or, has_doc, str_param, unique_name}; const C: &str = "document.exportForWeb"; diff --git a/crates/pdf/src/tests/webview.rs b/crates/pdf/src/tests/webview.rs index 680845722..9a4659ddc 100644 --- a/crates/pdf/src/tests/webview.rs +++ b/crates/pdf/src/tests/webview.rs @@ -135,6 +135,16 @@ struct Linearised { encrypted: bool, } +/// The main cross-reference table at `main`, covering the objects before the first page's `first`. +fn check_main_table(pdf: &[u8], lin: &Indirect, main: usize, first: u32) { + // /T: the white space before the main table's first entry. + let entries = main + format!("xref\n0 {first}\n").len(); + assert!(pdf[main..].starts_with(format!("xref\n0 {first}\n").as_bytes()), "the main table covers 0..{first}"); + assert_eq!(int(&lin.value, b"T"), entries - 1); + let main_trailer = Lexer::at(pdf, crate::lab_spot::find(pdf, b"trailer", main).unwrap() + 7).object(0).unwrap(); + assert_eq!(int(&main_trailer, b"Size") as u32, first); +} + /// Check `pdf` is linearised as ISO 32000-1 Annex F says, as a linearisation checker does: the /// linearization dictionary, both cross-reference tables and their trailers, and (unless the file /// is encrypted) the hint tables against where every page's objects are and what each page uses. @@ -160,12 +170,7 @@ fn check_linearised(pdf: &[u8]) -> Linearised { assert_eq!(all.len() as u32, size - 1, "the tables cover every object"); let first = lin.num; assert!(first_part.iter().all(|n| (first..size).contains(n)) && first_part.len() as u32 == size - first); - // /T: the white space before the main table's first entry. - let entries = main + format!("xref\n0 {first}\n").len(); - assert!(pdf[main..].starts_with(format!("xref\n0 {first}\n").as_bytes()), "the main table covers 0..{first}"); - assert_eq!(int(&lin.value, b"T"), entries - 1); - let main_trailer = Lexer::at(pdf, crate::lab_spot::find(pdf, b"trailer", main).unwrap() + 7).object(0).unwrap(); - assert_eq!(int(&main_trailer, b"Size") as u32, first); + check_main_table(pdf, &lin, main, first); // Every object where its table says, read as the file's objects. let objects: HashMap = all.iter().map(|(n, off)| (*n, indirect(pdf, *off).unwrap())).collect(); @@ -205,7 +210,41 @@ fn check_linearised(pdf: &[u8]) -> Linearised { let data = &pdf[data_at..data_at + int(&hint.value, b"Length")]; let mut r = BitReader { data, at: 0 }; - // The page offset hint table. + let (counts, ids) = check_page_hints(&mut r, &pages, &adjusted, &span, first_page_objects); + + // The shared object hint table. + let s = int(&hint.value, b"S"); + let mut r = BitReader { data, at: 8 * s }; + let (first_shared, first_shared_at, nfirst, ntotal) = read_shared_header(&mut r); + let shared_object = |id: u64| if id < nfirst { pages[0] + id as u32 } else { first_shared + (id - nfirst) as u32 }; + if ntotal > nfirst { + assert_eq!(first_shared_at, adjusted(first_shared), "the shared objects' location"); + } + check_shared_hints(&mut r, ntotal, nfirst, first_page_objects, &shared_object, &span); + + // What each page uses lies in its own objects, the first part or its shared objects. + let page_set: HashSet = pages.iter().copied().collect(); + let references = PageReferenceHints { + pages: &pages, + page_set: &page_set, + first_part: &first_part, + objects: &objects, + nodes: &nodes, + shared_object: &shared_object, + }; + for (i, &page) in pages.iter().enumerate() { + check_page_references(&references, i, page, counts[i], &ids[i]); + } + Linearised { pages, first_part, encrypted } +} + +fn check_page_hints( + r: &mut BitReader<'_>, + pages: &[u32], + adjusted: &impl Fn(u32) -> usize, + span: &impl Fn(u32) -> usize, + first_page_objects: u32, +) -> (Vec, Vec>) { let (min_objects, first_page_at, objects_bits) = (r.get(32), r.get(32) as usize, r.get(16)); let (min_len, len_bits) = (r.get(32), r.get(16)); let (_content_at, content_at_bits, _content_len, content_len_bits) = (r.get(32), r.get(16), r.get(32), r.get(16)); @@ -230,42 +269,58 @@ fn check_linearised(pdf: &[u8]) -> Linearised { assert_eq!(len as u64, lengths[i], "page {i}'s length"); at += len; } + (counts, ids) +} - // The shared object hint table. - let s = int(&hint.value, b"S"); - let mut r = BitReader { data, at: 8 * s }; - let (first_shared, first_shared_at, nfirst, ntotal) = (r.get(32) as u32, r.get(32) as usize, r.get(32), r.get(32)); - let (group_bits, min_group, group_len_bits) = (r.get(16), r.get(32), r.get(16)); +fn read_shared_header(r: &mut BitReader<'_>) -> (u32, usize, u64, u64) { + let first_shared = r.get(32) as u32; + let first_shared_at = r.get(32) as usize; + let nfirst = r.get(32); + let ntotal = r.get(32); + let group_bits = r.get(16); assert_eq!(group_bits, 0, "one object a group"); + (first_shared, first_shared_at, nfirst, ntotal) +} + +fn check_shared_hints( + r: &mut BitReader<'_>, + ntotal: u64, + nfirst: u64, + first_page_objects: u32, + shared_object: &impl Fn(u64) -> u32, + span: &impl Fn(u32) -> usize, +) { assert_eq!(nfirst as u32, first_page_objects); - let shared_object = |id: u64| if id < nfirst { pages[0] + id as u32 } else { first_shared + (id - nfirst) as u32 }; - if ntotal > nfirst { - assert_eq!(first_shared_at, adjusted(first_shared), "the shared objects' location"); - } - let groups = r.column(ntotal as usize, group_len_bits); - for (id, g) in groups.iter().enumerate() { + let (min_group, group_len_bits) = (r.get(32), r.get(16)); + for (id, g) in r.column(ntotal as usize, group_len_bits).iter().enumerate() { assert_eq!((g + min_group) as usize, span(shared_object(id as u64)), "shared object {id}'s length"); } assert!(r.column(ntotal as usize, 1).iter().all(|s| *s == 0), "no signatures"); +} - // What each page uses lies in its own objects, the first part or its shared objects. - let page_set: HashSet = pages.iter().copied().collect(); - for (i, &page) in pages.iter().enumerate() { - let own: HashSet = (page..page + counts[i] as u32).collect(); - let listed: HashSet = ids[i].iter().map(|id| shared_object(*id)).collect(); - let (mut seen, mut queue) = (HashSet::from([page]), vec![page]); - while let Some(o) = queue.pop() { - assert!( - own.contains(&o) || first_part.contains(&o) && (i == 0 || o < pages[0] || listed.contains(&o)) || listed.contains(&o), - "page {i} uses object {o}, which isn't among its objects or listed" - ); - let mut links = vec![]; - objects[&o].value.refs(&[b"Parent", b"Thumb"], &mut links); - queue.extend(links.into_iter().filter(|m| !page_set.contains(m) && !nodes.contains(m) && seen.insert(*m))); - } - assert!(listed.iter().all(|o| seen.contains(o)), "page {i} lists only objects it uses"); +struct PageReferenceHints<'a> { + pages: &'a [u32], + page_set: &'a HashSet, + first_part: &'a HashSet, + objects: &'a HashMap>, + nodes: &'a HashSet, + shared_object: &'a dyn Fn(u64) -> u32, +} + +fn check_page_references(hints: &PageReferenceHints<'_>, i: usize, page: u32, count: u64, ids: &[u64]) { + let own: HashSet = (page..page + count as u32).collect(); + let listed: HashSet = ids.iter().map(|id| (hints.shared_object)(*id)).collect(); + let (mut seen, mut queue) = (HashSet::from([page]), vec![page]); + while let Some(o) = queue.pop() { + assert!( + own.contains(&o) || hints.first_part.contains(&o) && (i == 0 || o < hints.pages[0] || listed.contains(&o)) || listed.contains(&o), + "page {i} uses object {o}, which isn't among its objects or listed" + ); + let mut links = vec![]; + hints.objects[&o].value.refs(&[&b"Parent"[..], &b"Thumb"[..]], &mut links); + queue.extend(links.into_iter().filter(|m| !hints.page_set.contains(m) && !hints.nodes.contains(m) && seen.insert(*m))); } - Linearised { pages, first_part, encrypted } + assert!(listed.iter().all(|o| seen.contains(o)), "page {i} lists only objects it uses"); } #[test]