`Folder` folds text for case- and accent-insensitive search (Turkish and
Azerbaijani i by locale, ß, final sigma, ligatures, full-width forms) and
maps matches back to the original text for highlighting. `Collator`
(feature `collate`) sorts lists in the locale's order with digits compared
by value, on ICU4X with collation data for the shipped locales only.
The Turkish i and sigma handling come from PdfCraft's `fold_case`.
Part of #198.
Co-authored-by: snipeTR <31975916+snipeTR@users.noreply.github.com>
Co-authored-by: nevicia2010-hub <nevicia2010@gmail.com>
* media: add craft-media with bitstream and isobmff from FilmCraft
Moves filmcraft-bitstream and filmcraft-isobmff (storytold/filmcraft@6c3948a)
into one crate with a feature per module. The public API matches FilmCraft's so
its crates can become re-exports. Tests, oracle tests and fuzzing come along;
the ffmpeg discovery helpers replace filmcraft-testkit.
Out-of-contract inputs no longer panic: bit widths above 32, a zero NAL length
prefix width, and PCM frame sizes that overflow u32. Adds
BitReader::read_ue_plus from DeckCraft's copy.
* media: public ISO BMFF box reader (isobmff::boxes)
Make the demuxer's box iterator and big-endian reader public as
isobmff::boxes::{BoxIter, BoxRef, BoxHeader, Reader}, for walkers of
boxes the demuxer does not model (CR3 uuid boxes, HEIF meta items,
JPEG 2000). BoxIter::within keeps offsets relative to the outer slice,
and allow_truncated yields a cut last box. The fuzz test walks every
box of each mutated file.
* media: matroska feature from FilmCraft's filmcraft-matroska
Port storytold/filmcraft@6c3948a crates/matroska as craft_media::matroska
behind the opt-in feature matroska, with the same public API so FilmCraft
can make filmcraft-matroska a re-export. Its unit and ffprobe oracle tests
come with it, on craft-media's test helpers.
From DeckCraft's copy: cluster and block timestamps no longer overflow;
they saturate at i64::MAX. MuxingApp and the default WritingApp name
craft-media. New tests: block additions and mutation fuzzing. The oracle
skips the duration of a track's last packet when ffmpeg 8 shortened it.
* media: MOV PCM uses lpcm v2 above 16.16 rates and for unsigned 16-bit; signed 8-bit as twos
Version 0 sound descriptions store the rate as 16.16 fixed point, so 88.2 kHz
and higher were written as 0 Hz. 8-bit signed PCM was labelled raw (unsigned)
and 16-bit unsigned as twos/sowt (signed). The reader also took raw under a
sound handler for uncompressed video.
* media: stop the top-level box scan at a box that runs past the end of the file
A 64-bit box size near u64::MAX saturated the scan offset, and the next
offset + 8 overflowed.
* media: one sample budget for the whole ISO BMFF file
The sample cap and the file-length bound on samples without table entries
(constant-size stsz, trun without per-sample fields) applied per track or
per trun, so repeating a small trak or trun multiplied the allocation.
Both are now shared by all tracks and fragments.
* media: set_sample_entry rejects entries that change the track's media type or PCM frame size
The handler, stsz constant size and PCM timescale check are fixed at add_track;
a replacement that changed them produced a corrupt file. A bad track index
returns NoSuchTrack like the other writer methods.
* media: saturate the sample end in MkvFile::duration_ns
Cluster timestamps saturate at i64::MAX, so pts + duration could overflow
for files without Info/Duration.
* media: checked add for the Matroska cue cluster position
CueClusterPosition comes from the file; an add past u64::MAX panicked in
debug builds and wrapped in release. Such a cue now falls back to the index.
* media: cap the Matroska TimestampScale at 2^32 and saturate tick conversions
A scale near 2^64 overflowed u128/i128 in the per-lace split and in
Track::ticks_to_ns. A BlockDuration near u64::MAX also overflowed the tick
difference at the default scale. Larger scales are ignored like a zero scale,
and tick and nanosecond values outside i64 saturate.
* media: Matroska fixture generation no longer truncates the shared subtitle inputs
Parallel tests generating subs.mkv or webvtt.webm could read in.srt or in.vtt
while another thread rewrote it, and cache a fixture with missing packets.
* media: rustfmt parse_moof signature
* ci: add craft-media workflow covering feature sets, WASM and ffmpeg oracles
The lint job runs fmt, clippy for each feature set (none, bitstream,
isobmff, matroska, all) and a wasm32 check. The test job runs the
all-features tests with Ubuntu's ffmpeg and CRAFT_MEDIA_REQUIRE_ORACLES=1,
installing ffmpeg while the tests compile.
* media: Matroska lacing keeps timestamp gaps
A laced frame's timestamp is implied by the block's and the track's
DefaultDuration, so lacing collapsed gaps in the input. A frame now joins
a lace only when that implied tick equals its own, and tracks without a
DefaultDuration do not lace. The laced remux oracle compares timestamps.
* media: required oracles fail on fixture generator and ffprobe failures
Every path that gave up on an oracle check (missing tool, failed fixture
generator, failed ffprobe run) goes through one helper that prints
SKIPPED, or fails the test with CRAFT_MEDIA_REQUIRE_ORACLES=1. Fixture
generators of both containers share run_generator, which takes the
required flag explicitly so tests can exercise it without changing the
process environment.
* media: use US spelling
* media: a failed ffprobe probe skips the optional oracle check
* media: the Matroska oracle compares the last subtitle cue's duration
Consent expiry is now per kind of data: renewing text no longer renews an expired image permission. A connection edit keeps models found by a test at the new address, and drops only the ones saved for the old one.
Add opt-in shared PDF authoring with bounded font preparation, caller-owned metadata and settings, guarded serialization, and a backend that rejects poisoned drawing state.
Preserve the existing writer commits so immutable dependency pins remain reachable from main. Reader and application migrations remain separate.
PR #105.
Add shared config.toml storage while keeping settings types, defaults and UI policy in each app.
Includes isolated in-memory operation, configurable portable paths, atomic saves with private backups, damaged-file preservation, schema migrations, and documented best-effort handling of external edits.
Validation: native macOS formatting, strict workspace clippy, 172 workspace tests and the craft-settings WASM check. Independent backup-permission and failed external-migration repros fail before the fixes and pass afterward.
Hosted CI: all seven UI and printing jobs pass across macOS, Linux, Windows and UI WASM.
Refs #12
winit's default app menu sends Quit (Cmd+Q) straight to
-[NSApplication terminate:] and winit doesn't implement
applicationShouldTerminate:, so a Craft app quits without its
unsaved-changes prompt. The new opt-in `menu` feature adds
`install_app_menu(ctx, app_name)`, which replaces that menu with a
muda-built copy whose Quit sends ViewportCommand::Close. The app's own
close handling then runs, as for the close button, and
on_close_request quits.
muda is a macOS-only, optional dependency; no unsafe code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
craft-print's Windows backend ran an embedded PowerShell script for the printer list and every
job. Under App Control for Business or AppLocker script enforcement that script runs in
Constrained Language Mode and every job fails (storytold/pdfcraft#1107). The backend now runs
in this process and starts no program:
- Printers come from EnumPrinters and the default from GetDefaultPrinter; Printer::two_sided
from each driver's PrintCapabilities. The list is sorted, each name once.
- A job is drawn as vectors by the in-box Windows.Data.Pdf with Direct2D into the XPS print
API (winprint). Copies, collation, duplex (left out for duplex: None), colour, orientation
and the driver's own paper option go in a PrintTicket the driver validates; a ticket the
driver changed (paper, orientation, scaling) is refused before anything is sent. The driver
paper named like the standard size is preferred (pdfcraft#599).
- A job has one ticket, so one paper shape. A small lenient reader (sheets.rs) reads the
print-ready PDF's sheets and, when needed, appends an incremental update: /Rotate for sheets
of the other orientation, and for Scaling::ShrinkToFit a reframe onto the driver's matching
or default paper (shrunk inside its widest hardware margin, never enlarged, centred).
Exact size refuses mixed paper sizes and paper the driver lacks.
- command_preview describes the in-process job on Windows ("xps-print", key=value options).
- windows_print.ps1 and the PowerShell helpers are gone. open_printer_preferences (rundll32)
and the CUPS path are unchanged, as is the public API.
The end-to-end test puts a paused Generic / Text Only printer on LPT1: (no port to remove
afterwards; a paused FILE: queue never takes the job) and checks a mixed-orientation exact job
and a shrink-to-fit job each land as one job with all sheets. The reader is tested on every
platform with classic and compressed cross-references and thousands of truncated and corrupted
files. Windows-only dependencies: winprint =0.2.1 (default features off), winsafe 0.0.29,
roxmltree 0.20, miniz_oxide 0.8.
Ported from PdfCraft's native printing branch (pdfcraft#1132), which carries #599's approach.
Co-authored-by: durtyrobbin <76844303+durtyrobbin@users.noreply.github.com>
Co-authored-by: Dimitar Klaturov <7221384+bulgariamitko@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closing an eframe window on macOS can crash in AppKit's Touch Bar finder
after eframe drops the window while the run loop is still running (#3).
craft-quit routes a window close through -[NSApplication terminate:],
the path Cmd+Q already takes, so the process ends before another display
cycle runs.
- quit(): schedules terminate: on the main queue on macOS, no-op elsewhere
- on_close_request() (feature "egui"): cancels the root window's close
and quits through the platform path instead
Also commits Cargo.lock and ignores .idea/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>