* feat(materialx): add bounded document reader and OpenPBR writer
* proof, video, latex, cms: satisfy the clippy lints that ship with Rust 1.100
The newer clippy flags needless bool guards and range loops whose index
only indexes one slice; express both with the equivalent iterators so
the workspace lint stays green on every platform.
* cms: index the ink loops instead of a range loop, which newer clippy rejects
* feat(materialx): resolve shader graphs and write OpenPBR materials
* feat(materialx): resolve shader graphs and write OpenPBR materials
* plotter: add TB54 registration-mark offset command with py_silhouette citation
The full Silhouette registration sequence (TB99 through TB55, plus
TB123/TB124 for search and TB23 for manual positioning) is documented
in the community driver py_silhouette (zero_on_registration_mark()),
which reverse-engineered the protocol from public behaviour — not from
any proprietary binary.
TB54,0,0 sets the registration-mark offset to zero (mark at expected
position). Without it the machine may use a non-zero default offset.
* workspace: allow unused_workspace_dependencies lint
The root Cargo.toml declares many workspace dependencies that are not
referenced by any crate's Cargo.toml (e.g. craft-aep, craft-ai-core,
craft-cms, etc.). This is intentional — they are available for apps to
use. Suppress the clippy warning so CI passes.
* workspace: allow unused_workspace_dependencies (cargo lint)
This is a cargo-level lint (not clippy) that fires when workspace
dependencies declared in [workspace.dependencies] are not referenced
by any crate's Cargo.toml. Many entries are intentionally available
for apps to use.
* cms, prepress, proof: allow unused_workspace_dependencies lint
These crates are built individually by CI (cargo clippy -p <crate>)
which does not inherit workspace lints. Add per-crate suppression.
* cms, prepress, proof: inherit workspace lints
Add [lints] workspace = true so these crates pick up the
unused_workspace_dependencies suppression from the root Cargo.toml.
* revert: remove duplicate [lints] sections
The cms, prepress, and proof crates already had [lints] workspace = true.
My previous commits accidentally added duplicate sections.
* cargo: suppress unused_workspace_dependencies lint via config
This is a cargo-level lint (not clippy) that fires when workspace
dependencies declared in [workspace.dependencies] are not referenced
by any crate's Cargo.toml. Many entries are intentionally available
for apps to use.
---------
Co-authored-by: Dylan Taylor <dylanmtaylor@gmail.com>
outlines_match_the_string_dispatch failed on macOS for curvedRightArrow
while Linux and Windows passed. The digest prints each coordinate with
{:.3}, which writes a residue such as -1.4e-14 from the sine or cosine of
a right angle as "-0.000". The sign of that residue depends on the
platform's libm, so the digest did too.
digest_coord now maps every coordinate that prints as zero to 0.0 before
it is printed. The digests of pieWedge, curvedRightArrow and
curvedDownArrow, the only names whose outlines held such residues, are
taken again; no outline changes.
craft-metadata #1042 keeps the first text-bearing value of a repeated
property so a blank repeat cannot hide a location, but craft-crs's doc
comment and test still claimed the last repeat wins. The workspace-wide
test job has been red since it landed because of that assertion.
* prepress: separate a page in bands, past the 4 MP plate cap
`plates_in_bands` finds a page's inks once, then separates it in row
bands of at most MAX_PLATE_PIXELS each, rendering every band through
craft-pdf raster's size/offset viewport. A page can now be separated at
print resolution with bounded memory: only the renderer's 8192-pixel
side limit and a 256 MP per-plate total (MAX_BANDED_PIXELS) lower the
resolution. `plates` is unchanged in behaviour: it is the one-band case
of the same code.
Tests: bands of 7 rows join byte for byte into the whole-page render of
an anti-aliased disc under an overprinting spot (fails when the band
offset is dropped), and a 40 pt page at 3700 dpi separates at full
resolution in bands under the cap (fails when banding uses the plate
cap's scale).
Refs #838.
* prepress: bands pass the renderer's whole-page limits
The page's pixel size came from `raster::dimensions` on the whole page,
which enforces the renderer's 64 MP and 8192-pixel side limits, so a
Letter page past about 830 dpi failed with OutputLimit instead of
banding. The size is now computed as the renderer floors it, and only
each band's viewport reaches the renderer. Bands are also capped at
MAX_SIDE rows, and ink discovery renders within the renderer's limits.
A Letter page at 900 dpi now separates in 19 bands at full resolution;
across the page the side limit still lowers it, near 960 dpi.
Test: a 10 x 2000 pt strip at 600 dpi (16 666 rows) separates in three
bands with its black square on the right rows. It fails with either the
whole-page dimensions call or the uncapped band height restored.
* prepress: check the page before discovery; say what the banded cap bounds
The page-size check now runs before ink discovery renders anything.
MAX_BANDED_PIXELS bounds pixels, not the number of bands; the doc
comment and the README caps table say so.
* prepress: count a sub-pixel side as one pixel in the banded cap
A side scaled under one pixel still renders one, so a very thin, tall
page could pass MAX_BANDED_PIXELS by far. banded_scale now fits the
other side alone in that case, and separate() refuses any floored size
over the cap before it renders a band.
* prepress: keep the banded area scale under the cap after rounding
The area scale came from the exact cap, so f32 rounding could floor a
page one row past it (17 x 15 058 824 pt at 72 dpi), which then failed
with OutputLimit. The same 0.1% margin as the one-pixel branches now
applies to the area scale too, with a test on that page.
---------
Co-authored-by: KenM76 <KenM76>
* craft-cms: run the CMS suite in CI; say when system-profile checks are skipped
* craft-cms: satisfy clippy's chunks_exact_to_as_chunks lint in the total-ink test
---------
Co-authored-by: aiongg <aiongtaigi@gmail.com>
* PDF interpret: a glyph shown in a clipping mode clips even with no outline
A glyph shown in a clipping render mode (`4 Tr` to `7 Tr`) adds its outline to
the clipping path, and that clip applies to everything painted after `ET` until
the enclosing `Q`. When the glyphs shown have no outline -- a space, say -- the
clip they contribute is empty, and an empty clip admits nothing.
`interpret_window` applied a clip only once a glyph had contributed an outline,
so such a text object applied *no* clip and what followed painted unmasked.
A text object that shows no glyph at all is a different case and is left alone:
the clipping path is unchanged there, as readers leave it, and a glyph whose
outline is unavailable (Type 3) leaves the real clip unknown, so both stay
unclipped. pdf.js draws the same line in `endText`: it builds the clip from the
glyphs shown, empty outlines and all, and applies none when none were shown.
Measured on a page filled red behind the text object, Preview (CoreGraphics)
and Firefox (pdf.js) agreeing on the case this changes:
a space shown in 7 Tr before: the fill paints after: nothing paints
no glyph shown in 7 Tr unchanged: the fill paints
Companion to storytold/pdfcraft#3451.
The first push of this branch also carried 803 build-artifact files from
`crates/pdf/read-only-contract/target/`, which `.gitignore` did not cover: its
`/target` is anchored to the repository root, so a sub-crate's own build
directory is not ignored. Recommitted without them, and `target/` added so the
next one cannot slip in either (#185 review).
* pdf: test visible glyphs in a clipping mode, and what each clip leaves on the page
---------
Co-authored-by: Hamza <mail.hamzanaveed@gmail.com>
* Share shape gallery choices and procedural previews
* Clip shape previews to their supplied rectangles
* Discard texture updates explicitly in headless rendering tests
* Honor fill colors across complete star and heart contours
* Make heart contour collection type explicit
* Use fixed-size triangle chunks in fill regression
---------
Co-authored-by: Fluorine <joseph.anglada92@gmail.com>
Co-authored-by: Joseph Anglada Muñiz <janglada@nd-soft.com>
* craft-window: frame policy v2: integrated title bar by default, desktop and backend detection
Add the policy module: Backend, Desktop::detect, TitleBarPref, Os, Frame
{Native, Inset, Integrated}, pure decide, decide_for and apply. Caption
layouts come from GNOME gsettings, kwinrc and GTK settings.ini parsers.
Choice::probe, the root Frame and decorate keep their behaviour.
* craft-window: review fixes for the frame policy
Desktop gains icon_theme, Decision gains desktop, Backend::from_env,
GNOME layout falls back to settings.ini, compositor socket variables mark
tiling, GTK_THEME wins over settings.ini, layout is read only for an
integrated frame, Layout::mirrored.
* craft-window: CRAFT_TITLEBAR applies when the app's own variable is unset
---------
Co-authored-by: aiongg <aiongtaigi@gmail.com>
* platform: GNOME's light setting reads as light, and Watcher::wait_first for the first frame
GNOME 42-46 writes color-scheme 'default' for Settings > Appearance > Light and the portal
reports 0. Both now decode as Light on GNOME (XDG_CURRENT_DESKTOP, read once at start);
0 stays no preference on other desktops.
Watcher::wait_first(timeout) blocks until the first answer, a known-absent portal with an
empty fallback, a no-preference answer, worker exit or drop, or the timeout.
* platform: GNOME's 'default' is light only on a GNOME desktop
---------
Co-authored-by: aiongg <aiongtaigi@gmail.com>
In "Vado. ‘poi’ torno." the capital-letter check skipped poi, because ends_sentence didn't count ‘ among the characters that may open the next sentence. This is the last part of storytold/wordcraft#3675; the rest came with #484.
---------
Co-authored-by: VoiceLessQ <t12kaem@gmail.com>
* krilla: TrueType subsets keep the font's OS/2 table (embedding permissions)
The subsetter writes only the tables it subsets, so a FontFile2 program
had no OS/2 table and the font's embedding permissions (OS/2.fsType)
never reached the PDF: a Preview & Print or Restricted font looked
unrestricted to anything reading the file later (designcraft#1781).
Patch 18 adds the source font's OS/2 table, byte for byte, to a
TrueType subset that lacks one, rewriting the table directory with its
checksums and head.checkSumAdjustment. CFF programs are still embedded
bare. Ledger, patch file and SOURCE.json updated; craft-pdf's new
font_tables test checks the table, its fsType and the font's checksums.
* krilla: the OS/2 test checks the embedded program is a subset
Its sfnt and re-read checks also pass for the source font embedded whole. A subset has fewer glyphs than the fixture's 11, and a shorter glyf.
---------
Co-authored-by: Hamza <mail.hamzanaveed@gmail.com>
* update: offer Save and Update in the prompt when the app can save (#586)
With unsaved work the prompt only said to save or close first. An app can now pass can_save to show_with_save: the button then reads Save and Update, a click asks the app to save through take_save_request, and the install starts once nothing is unsaved. save_stopped reports a save that did not get there. show and show_if are unchanged, so other apps see no difference.
* update: test that a second click during the save leaves the prompt open
The saving prompt test only read the painted text. This one clicks where Save and Update was, where a Dismiss would catch the second click of a double click.
* update: Save and Update follows the ready update (#586)
A ready update whose close was canceled now offers Save and Update in place of Restart to Update while the app can save. Once the save ends with nothing unsaved, the app is asked to close in that same frame, once. Tests cover both prompts and the close order.
---------
Co-authored-by: Marc <184940552+marcwgls@users.noreply.github.com>
Drop the residual_ prefix from four tests in language_packs/tests.rs.
The two cleanup tests become committed_cleanup_*, matching the
committed removal receipts they exercise. Test bodies are unchanged.
---------
Co-authored-by: dotCooCoo <RobertLeeLW@gmail.com>
* prepress: one wide curve no longer slows region cleanup for every other curve
The flattener's region cleanup looks up the input curves whose bounds hold
both ends of an output piece. The lookup searched back from a point by the
width of the widest input curve, so one curve as wide as the page made every
lookup scan nearly every input curve, and the cleanup grew quadratically with
the number of curves.
The curves are now grouped by bounds width, each group within a factor of two,
and each group is searched within its own widest bounds. The lookup returns
the same curves in the same order as before, so the regions are unchanged.
* prepress: region cleanup keeps a curve held just inside its right edge
Far from the origin, `x - width` can round above the left edge of a curve
whose bounds hold `x`, and the width-group search then skipped that curve.
The search's left edge is now rounded outward.
---------
Co-authored-by: dotCooCoo <RobertLeeLW@gmail.com>
macOS returns EILSEQ when a file name is not UTF-8, so the test panicked while creating its checkout. The test now ends at that step on macOS for that error. Any other error, and the same error on another platform, still fails the test.
---------
Co-authored-by: dotCooCoo <RobertLeeLW@gmail.com>
* web-api: refuse calls beyond an in-flight limit, and say who can call window.<app>
At most 64 calls (PageApi::with_max_in_flight) may wait for the app at once. A call made while that many wait rejects at once with a busy error and never reaches the app, so a page script that calls in a loop without awaiting cannot grow the app queue without bound, as the desktop control server already answers busy when its queue is full. The README also says the API is a property of the page global with no key: any script in the page origin has the same command control as the desktop control server.
* web-api: turn a busy call away before converting its params, and say a same-origin parent or opener can call window.<app>
A call over the in-flight limit used to stringify and convert its params before the busy check, so a large payload still cost the work it was being refused for. The params are now built by a closure the call runs only once it holds a slot.
The README said a parent, a child or an opener cannot reach window.<app>. That holds across origins only: a same-origin parent, child or opener with a window reference calls it directly, and the craft-web-host origin and source checks do not apply to that call.
---------
Co-authored-by: Helen Kwok <107752876+helenkwok@users.noreply.github.com>
Plates::composite converts through sRGB, which clips the press gamut
before a print profile sees it. Output converts press CMYK straight into
a gray, RGB or CMYK output profile (CMYK -> PCS -> output) at a chosen
intent and black point compensation, and Plates::composite_to combines
spot inks in that space: a multiply in gray or RGB, a multiply of the
complements in CMYK. CmsConversion::profile exposes the press profile.
The spot ramps move into shared helpers, used by composite and output;
the Lab encoding moves into one used by cms and output.
Part of #838 (item 2). The printer-leg semantics are adapted from pdfcer
(MIT, same author), crates/pdfcer-print/src/icc_proof.rs at 0a249a73;
the code is new, on craft-cms.
---------
Co-authored-by: KenM76 <KenM76>