diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 0000000000..2408084cf9
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
+reviews:
+ auto_review:
+ # Dependabot bumps are checked by CI; skip CodeRabbit reviews on them.
+ ignore_usernames:
+ - "dependabot[bot]"
diff --git a/.config/nextest.toml b/.config/nextest.toml
new file mode 100644
index 0000000000..2a4cd2cb93
--- /dev/null
+++ b/.config/nextest.toml
@@ -0,0 +1,3 @@
+# Minimum cargo-nextest for this repository: GHSA-vc25-qg58-w57c is fixed in 0.9.150 and CI
+# installs exactly that version, so an older nextest refuses to run (exit 92 REQUIRED_VERSION_NOT_MET).
+nextest-version = "0.9.150"
diff --git a/.github/assets/badges/rust.svg b/.github/assets/badges/rust.svg
index 11aeaaf4bd..fc33e3e188 100644
--- a/.github/assets/badges/rust.svg
+++ b/.github/assets/badges/rust.svg
@@ -1 +1 @@
-
+
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 0000000000..93b6522991
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,12 @@
+# Tests hold known passwords and crypto vectors on purpose. Vendored crates are patched copies of
+# third-party code, whose PDF encryption code flags the formats' own constants. Excluding them keeps
+# real findings in the app's code visible, but CodeQL no longer looks for bugs in these folders.
+paths-ignore:
+ - "vendor/**"
+ - "xtask/**"
+ - "**/tests/**"
+ - "**/tests.rs"
+ - "**/*_tests.rs"
+ - "**/benches/**"
+ - "**/examples/**"
+ - "**/fuzz/**"
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..1910ea4bd3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,32 @@
+version: 2
+updates:
+ # Maintain Rust / Cargo dependencies
+ - package-ecosystem: "cargo"
+ directories:
+ - "/"
+ - "/crates/filters/fuzz"
+ schedule:
+ interval: "daily"
+ time: "06:00"
+ timezone: "America/New_York"
+ # Consolidate updates into a single PR rather than one PR per crate
+ groups:
+ cargo-dependencies:
+ patterns:
+ - "*"
+ commit-message:
+ prefix: "chore(deps)"
+
+ # Maintain GitHub Actions workflows
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ time: "06:00"
+ timezone: "America/New_York"
+ groups:
+ actions:
+ patterns:
+ - "*"
+ commit-message:
+ prefix: "ci(deps)"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..50ff3e96c4
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,76 @@
+
+
+## What this changes
+
+
+
+## How you verified it
+
+
+
+- [ ] `cargo fmt --check`
+- [ ] clippy with `-D warnings` on the crates I changed
+- [ ] tests pass on the crates I changed
+- [ ] `cargo xtask layers` and `cargo xtask assets` (if you touched crate boundaries or any asset)
+
+**Tests.** New behaviour needs a test at the right scale — a property test, a unit test, a
+crate integration test or an end-to-end one. For a bug fix, **please check that the test
+fails before your fix** by reverting the fix and watching it go red. A test nobody has seen
+fail is not evidence that it pins anything.
+
+## Never-crash
+
+Every PDF, script, MCP call, settings file and keystroke is untrusted input (`AGENTS.md` §4).
+
+- [ ] No new `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` outside tests, unless it is
+ provably infallible with a comment saying why
+- [ ] No indexing or slicing with input-derived positions (`get`, and strings only at char
+ boundaries); checked or saturating arithmetic; allocations sized by input are capped;
+ recursion is bounded
+- [ ] No `unsafe`
+- [ ] Any crash this fixes has a small synthetic regression test
+
+## Provenance
+
+This is the part that cannot be undone after a merge, and the part a new contributor is
+least likely to know about. Please read `AGENTS.md` §1 before adding any asset.
+
+- [ ] No asset from an Adobe product, and no Adobe icon recreated, traced or imitated
+- [ ] No font files committed here (they live in
+ [storytold/craft-fonts](https://github.com/storytold/craft-fonts))
+- [ ] No GPL/AGPL code copied in — MuPDF, Ghostscript, Poppler, veraPDF and DSS may only be
+ run as external oracle processes
+- [ ] Behaviour comes from the specification or black-box observation, **not** from reading
+ another implementation's source
+- [ ] Every new asset has an `ATTRIBUTION.toml` entry and `cargo xtask assets` passes
+
+## Security
+
+- [ ] `--root` confinement still holds on every path, including ones reached by nested
+ tool dispatch
+- [ ] MCP and the UI control channel stay opt-in, loopback-only and token-authenticated
+- [ ] No new outbound network access (that decision is the owner's)
+
+## Parity and reach
+
+- [ ] `parity/acrobat-features.toml` updated in this PR, with `notes` saying what is *still*
+ missing — `shipped` means "exists and tested", not "as good as Acrobat"
+- [ ] Reachable headlessly through an `automation` tool where that applies (`AGENTS.md` §3),
+ so agents can drive it and not just the UI
+- [ ] Docs updated if this changes a documented behaviour (`docs/`, crate README)
+
+## Anything a reviewer should look at first
+
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e0c0596447..087f26bceb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,133 +1,92 @@
name: CI
+# Quality gates for every push to main and every pull request (`cargo xtask ci`), through the
+# suite's shared gate workflow in craft-common-actions. Nightly fuzzing is in fuzz.yml.
on:
push:
branches: [main]
pull_request:
+ # `labeled` so that adding `full-ci` to an open PR starts a run with Windows in it.
+ types: [opened, synchronize, reopened, labeled]
workflow_dispatch:
- schedule:
- - cron: "17 3 * * *" # nightly fuzzing
-env:
- CARGO_TERM_COLOR: always
- RUST_BACKTRACE: 1
+# The token is only used to check out the code: no job writes to the repository.
+permissions:
+ contents: read
+# A newer push to a PR branch cancels its older run; every push to main runs to the end. Adding
+# any label but `full-ci` gets a group of its own, so it neither runs the gate nor cancels a run.
concurrency:
- group: ci-${{ github.ref }}
- cancel-in-progress: true
+ group: ci-${{ github.event_name == 'pull_request' && (github.event.action != 'labeled' || github.event.label.name == 'full-ci') && github.ref || github.run_id }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
- test:
- name: test (${{ matrix.os }})
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- # No macOS on PRs, main or nightly: the org's 5 macOS slots are kept for release builds,
- # and release.yml builds macOS (a failing release is fixed and rebuilt).
- os: [ubuntu-latest, windows-latest]
- steps:
- - uses: actions/checkout@v4
-
- # The optional craft-fonts build input (Japanese fonts), so the Japanese font tests run on
- # Linux; Windows tests the build without it. See craftrules standards/fonts.md.
- - name: Check out craft-fonts (Linux)
- if: runner.os == 'Linux'
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
-
- - name: Install Linux system dependencies (egui/winit/rfd)
- if: runner.os == 'Linux'
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends \
- libxkbcommon-dev libwayland-dev libx11-dev libxrandr-dev libxi-dev \
- libgl1-mesa-dev libgtk-3-dev
-
- - uses: dtolnay/rust-toolchain@stable
- with:
- components: clippy, rustfmt
-
- - name: Require Windows executable resources
- if: runner.os == 'Windows'
- run: Add-Content -Path $env:GITHUB_ENV -Value 'PDFCRAFT_REQUIRE_WINRES=1'
- shell: pwsh
-
- - uses: Swatinem/rust-cache@v2
-
- - name: Format
- if: runner.os == 'Linux'
- run: cargo fmt --all -- --check
-
- - name: Clippy
- run: cargo clippy --workspace --all-targets -- -D warnings
-
- - name: Test
- if: runner.os != 'Linux'
- run: cargo test --workspace
-
- - name: Test (with craft-fonts)
- if: runner.os == 'Linux'
- env:
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- run: cargo test --workspace
-
- - name: Layering
- run: cargo xtask layers
-
- - name: Assets (licences and attribution)
- if: runner.os == 'Linux'
- run: cargo xtask assets
-
- - name: CLI without the MCP server still builds
- if: runner.os == 'Linux'
- run: cargo check -p pdfcraft-cli --no-default-features
-
- wasm:
- name: wasm32 check
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: wasm32-unknown-unknown
- - uses: Swatinem/rust-cache@v2
- with:
- key: wasm32
- - name: Check library crates for wasm32
- run: cargo xtask wasm
-
- deny:
- name: dependency licences and advisories
+ # The shared gate doesn't check where git dependencies come from; release.yml runs the same job.
+ git-sources:
+ if: github.event.action != 'labeled' || github.event.label.name == 'full-ci'
+ name: Git dependencies come from storytold
runs-on: ubuntu-latest
+ permissions:
+ contents: read
steps:
- - uses: actions/checkout@v4
- - uses: EmbarkStudios/cargo-deny-action@v2
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
- command: check
-
- fuzz:
- name: fuzz (mutation, 15 min)
- if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: dtolnay/rust-toolchain@stable
- - uses: Swatinem/rust-cache@v2
- with:
- key: fuzz
- - name: Fetch the pdf.js corpus (seeds)
- run: cargo xtask corpus
- - name: Fuzz
- run: cargo xtask fuzz --time 900 --seed ${{ github.run_number }}
- - name: Upload findings
- if: always()
- uses: actions/upload-artifact@v4
- with:
- name: fuzz-findings
- path: fuzz-out/findings
- if-no-files-found: ignore
+ persist-credentials: false
+ - name: Windows font notice regressions
+ shell: pwsh
+ run: ./packaging/windows/test-font-notices.ps1
+ - name: Git dependencies come from storytold
+ run: |
+ set -euo pipefail
+ test -f Cargo.lock || { echo "Cargo.lock is missing"; exit 1; }
+ # Source replacement, patches and path overrides in cargo config never show up
+ # in Cargo.lock. Parsed rather than grepped: TOML has many spellings of one key.
+ # Cargo still reads the legacy .cargo/config.
+ python3 - <<'PY'
+ import os, sys, tomllib
+ for path in (".cargo/config", ".cargo/config.toml"):
+ if not os.path.exists(path):
+ continue
+ config = tomllib.load(open(path, "rb"))
+ replaced = [name for name, source in config.get("source", {}).items()
+ if isinstance(source, dict) and "replace-with" in source]
+ if replaced or "patch" in config or "paths" in config:
+ print(f"{path} replaces, patches or overrides a source")
+ sys.exit(1)
+ PY
+ # Fails when Cargo.lock is out of date with the manifests.
+ cargo metadata --locked --format-version 1 > /dev/null
+ python3 - <<'PY'
+ import sys, tomllib
+ lock = tomllib.load(open("Cargo.lock", "rb"))
+ bad = sorted({p["source"] for p in lock.get("package", [])
+ if p.get("source", "").startswith("git+")
+ and not p["source"].startswith("git+https://github.com/storytold/")})
+ if bad:
+ print("Git dependencies outside github.com/storytold:", *bad, sep="\n")
+ sys.exit(1)
+ PY
+
+ gate:
+ if: github.event.action != 'labeled' || github.event.label.name == 'full-ci'
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/gate.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+ with:
+ # Windows on main, manual runs and pull requests labelled `full-ci`. No macOS on PRs or main:
+ # the org's 5 macOS slots are kept for release builds, and release.yml builds macOS.
+ os: ${{ (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'full-ci')) && '["ubuntu-24.04","windows-latest"]' || '["ubuntu-24.04"]' }}
+ # Same craft-fonts commit as release.yml and freebsd.yml.
+ craft-fonts-ref: b076417b5880bd4154bd22f00695b1d28c6bea83
+ # egui/winit/rfd, and the independent oracles (crates/oracle).
+ packages: >-
+ libxkbcommon-dev libwayland-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev
+ libgtk-3-dev qpdf poppler-utils
+ # cargo-deny for the deny step of `cargo xtask ci`, which requires it under CI.
+ tools: cargo-nextest@0.9.150,cargo-deny@0.20.2
+ # A missing oracle fails the job instead of printing a skip notice that reads as a pass.
+ linux-env: PDFCRAFT_ORACLES_REQUIRED=1
+ windows-env: PDFCRAFT_REQUIRE_WINRES=1
+ # Windows checks what differs by platform: the build (with resources) and the tests.
+ windows-command: |
+ cargo clippy --workspace --all-targets --locked -- -D warnings
+ cargo test --workspace --locked
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 9348c2cdf6..4f30a827af 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -39,6 +39,7 @@ jobs:
with:
languages: ${{ matrix.language }}
build-mode: none
+ config-file: ./.github/codeql/codeql-config.yml
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4
diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml
index e409d1e99e..53e3046d30 100644
--- a/.github/workflows/freebsd.yml
+++ b/.github/workflows/freebsd.yml
@@ -23,30 +23,7 @@ permissions:
jobs:
freebsd:
- name: FreeBSD 14 (build + test)
- runs-on: ubuntu-latest
- timeout-minutes: 300
- steps:
- - uses: actions/checkout@v4
- - name: Build and test in a FreeBSD VM
- uses: vmactions/freebsd-vm@c46abacb49f09938ca4e1702d15d836285d694cc # v1
- with:
- release: "14.3"
- usesh: true
- cpu: 4
- mem: 12288
- # Nothing to bring back; copying the target dir out of the VM fails on large builds.
- copyback: false
- prepare: |
- pkg install -y bash git curl pkgconf cmake python3 libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader gtk3 fontconfig freetype2 alsa-lib
- curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal
- run: |
- . "$HOME/.cargo/env"
- # The checkout is synced in under another owner; let tests that call git read it.
- git config --global --add safe.directory "*"
- rustc --version
- CARGO_PROFILE_DEV_DEBUG=0 cargo build --workspace --all-targets --locked
- CARGO_PROFILE_DEV_DEBUG=0 cargo test --workspace --locked
- # The release packaging, end to end (a quicker release profile than the real release).
- CARGO_PROFILE_RELEASE_LTO=false CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 packaging/freebsd/package.sh
- tar -tzf dist/release/pdfcraft-*-freebsd-*.tar.gz | grep -E '/bin/pdfcraft$|/bin/pdfcraft-cli$|applications/|/share/pdfcraft/models/.+\.onnx$'
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/freebsd.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+ with:
+ craft-fonts-ref: b076417b5880bd4154bd22f00695b1d28c6bea83
diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml
new file mode 100644
index 0000000000..b7b1d409c8
--- /dev/null
+++ b/.github/workflows/fuzz.yml
@@ -0,0 +1,46 @@
+name: Fuzz
+
+# Mutation fuzzing of open/render/edit/save (`cargo xtask fuzz`), nightly and on demand. Findings
+# are uploaded as an artifact; each real one becomes a synthetic regression test.
+on:
+ schedule:
+ - cron: "17 3 * * *"
+ workflow_dispatch:
+
+# The token is only used to check out the code: no job writes to the repository.
+permissions:
+ contents: read
+
+env:
+ CARGO_TERM_COLOR: always
+ RUST_BACKTRACE: 1
+
+concurrency:
+ group: fuzz-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ fuzz:
+ name: fuzz (mutation, 15 min)
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable
+ with:
+ toolchain: stable
+ - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
+ with:
+ key: fuzz
+ - name: Fetch the pdf.js corpus (seeds)
+ run: cargo xtask corpus
+ - name: Fuzz
+ run: cargo xtask fuzz --time 900 --seed ${{ github.run_number }}
+ - name: Upload findings
+ if: always()
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+ with:
+ name: fuzz-findings
+ path: fuzz-out/findings
+ if-no-files-found: ignore
diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml
new file mode 100644
index 0000000000..86e12c9ef2
--- /dev/null
+++ b/.github/workflows/nix.yml
@@ -0,0 +1,23 @@
+# Evaluates the Nix flake (no build, about a minute): `nix build` / `nix develop` stop at evaluation
+# when Cargo.lock gains something nix/package.nix can't vendor, and nothing else would notice.
+name: Nix
+
+on:
+ push:
+ branches: [main]
+ paths: ["flake.nix", "flake.lock", "nix/**", "Cargo.lock", ".github/workflows/nix.yml"]
+ pull_request:
+ paths: ["flake.nix", "flake.lock", "nix/**", "Cargo.lock", ".github/workflows/nix.yml"]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: nix-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ nix:
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/nix.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
diff --git a/.github/workflows/packaging-lint.yml b/.github/workflows/packaging-lint.yml
index aed79a90ed..bc0248fd20 100644
--- a/.github/workflows/packaging-lint.yml
+++ b/.github/workflows/packaging-lint.yml
@@ -19,48 +19,29 @@ concurrency:
jobs:
lint:
- runs-on: ubuntu-latest
- env:
- ACTIONLINT_VERSION: 1.7.12
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/packaging-lint.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+
+ windows-install-policy:
+ timeout-minutes: 10
+ name: Windows installation policy (no app build)
+ runs-on: windows-latest
steps:
- - uses: actions/checkout@v4
- - name: Install tools
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends shellcheck desktop-file-utils appstream libxml2-utils python3-yaml
- curl -fsSL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
- | tar -xz -C "$RUNNER_TEMP" actionlint
- - name: actionlint
- run: |
- "$RUNNER_TEMP/actionlint" -color
- - name: shellcheck
- run: shellcheck packaging/*.sh packaging/*/*.sh
- - name: PowerShell
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Install the pinned packaging toolchain
shell: pwsh
run: |
- foreach ($f in Get-ChildItem packaging/windows/*.ps1) {
- $errors = $null
- [System.Management.Automation.Language.Parser]::ParseFile($f.FullName, [ref]$null, [ref]$errors) | Out-Null
- if ($errors) { $errors | ForEach-Object { Write-Output "::error file=$($f.Name)::$_" }; exit 1 }
- Write-Output "ok $($f.Name)"
+ $tools = Join-Path $env:RUNNER_TEMP 'craft-install-policy-wix'
+ dotnet tool install --tool-path $tools wix --version 5.0.2
+ if ($LASTEXITCODE -ne 0) { throw 'WiX installation failed.' }
+ $tools >> $env:GITHUB_PATH
+ $policy = Get-Content -Raw -LiteralPath packaging/windows/install-policy.json | ConvertFrom-Json
+ foreach ($extension in @($policy.extensions)) {
+ & (Join-Path $tools 'wix.exe') extension add -g "WixToolset.$extension.wixext/5.0.2"
+ if ($LASTEXITCODE -ne 0) { throw "WiX extension $extension installation failed." }
}
- - name: XML, desktop entry, AppStream, Flatpak manifest
- run: |
- xmllint --noout packaging/windows/*.wxs packaging/macos/*.plist* packaging/linux/*.xml*
- # Windows Installer needs Icon ids ending in .ico or .exe, or shortcuts show a blank icon (#57).
- if grep -oE '"$RUNNER_TEMP/ai.storyteller.pdfcraft.metainfo.xml"
- appstreamcli validate --no-net --explain "$RUNNER_TEMP/ai.storyteller.pdfcraft.metainfo.xml"
- python3 - <<'EOF'
- import yaml
- src = yaml.safe_load(open("packaging/linux/flatpak/ai.storyteller.pdfcraft.yml"))
- bundle = yaml.safe_load(open("packaging/linux/flatpak/ai.storyteller.pdfcraft.bundle.yml"))
- for m in (src, bundle):
- assert m["id"] == "ai.storyteller.pdfcraft" and m["command"] == "pdfcraft", m["id"]
- for key in ("runtime", "runtime-version", "sdk", "finish-args"):
- assert src[key] == bundle[key], f"Flatpak manifests disagree on {key}: {src[key]} vs {bundle[key]}"
- print("Flatpak manifests ok")
- EOF
+ - name: Build and check non-executable installer fixtures
+ shell: pwsh
+ run: ./packaging/windows/test-install-policy.ps1 -OutputDirectory (Join-Path $env:RUNNER_TEMP 'craft-install-policy-tests')
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index da4a9e02b6..573b9f69f3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,12 +1,3 @@
-# Release pipeline: every push to `release` builds signed installers for every platform and
-# creates or updates the draft GitHub Release "PdfCraft v". See docs/releasing.md.
-#
-# The jobs that sign (macOS, Windows) and the one that drafts the release run in the `release`
-# environment (restricted to the `release` branch), which holds the signing secrets. Every secret
-# is optional: missing ones produce unsigned artifacts and a warning, never a failed build. The
-# other jobs use no secrets and so no environment: a dispatch on another branch builds and checks
-# them (a dry run), while the signing jobs are refused there and the draft-release job, which
-# needs them, is skipped.
name: Release
on:
@@ -20,494 +11,33 @@ on:
default: ""
permissions:
- contents: read
+ contents: write
concurrency:
group: release-${{ github.ref }}
- # Never cancel a run mid-notarization or mid-upload; a newer push waits its turn.
cancel-in-progress: false
-env:
- CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: 1
- PDFCRAFT_BUILD_SHA: ${{ github.sha }}
- INPUT_VERSION: ${{ inputs.version }}
-
jobs:
- version:
- name: version
- runs-on: ubuntu-latest
- outputs:
- version: ${{ steps.v.outputs.version }}
- date: ${{ steps.v.outputs.date }}
- prerelease: ${{ steps.v.outputs.prerelease }}
- steps:
- - uses: actions/checkout@v4
- - id: v
- name: Resolve version
- run: |
- . packaging/env.sh
- v="${INPUT_VERSION#v}"
- v="${v:-$VERSION}"
- if ! printf '%s' "$v" | grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$'; then
- echo "::error::'$v' is not a version like 1.2.3 or 1.2.3-rc.1"
- exit 1
- fi
- case "$v" in *-*) pre=true ;; *) pre=false ;; esac
- {
- echo "version=$v"
- echo "date=$(date -u +%Y-%m-%d)"
- echo "prerelease=$pre"
- } >>"$GITHUB_OUTPUT"
- echo "### PdfCraft v$v (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY"
-
- macos:
- name: macOS universal
- needs: version
- runs-on: macos-15-xlarge # M2 Pro larger runner; use only in release.yml (actions_macos_xl budget caps spend)
- environment: release
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: aarch64-apple-darwin, x86_64-apple-darwin
- - uses: Swatinem/rust-cache@v2
- with:
- key: release-macos-universal
- - name: Apply version override
- if: inputs.version != ''
- run: cargo xtask version set "$PDFCRAFT_VERSION"
- - name: Import signing certificate
- env:
- APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
- APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- run: packaging/macos/import-cert.sh
- - name: Build, sign, notarize
- env:
- APPLE_ID: ${{ secrets.APPLE_ID }}
- APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- run: packaging/macos/package.sh --arch universal
- - uses: actions/upload-artifact@v4
- with:
- name: release-macos
- path: dist/release/*
- if-no-files-found: error
- - name: Remove temporary keychain
- if: always()
- run: |
- if [ -n "${MACOS_KEYCHAIN:-}" ]; then security delete-keychain "$MACOS_KEYCHAIN" || true; fi
-
- windows:
- name: Windows ${{ matrix.arch }}
- needs: version
- runs-on: windows-latest
- environment: release
- strategy:
- fail-fast: false
- matrix:
- include:
- - { arch: x64, target: x86_64-pc-windows-msvc }
- - { arch: x86, target: i686-pc-windows-msvc }
- # Windows on ARM (#61): cross-compiled on the x64 runner, so signing and WiX run as above.
- # .github/workflows/windows-arm64.yml installs and runs it on ARM64 hardware.
- - { arch: arm64, target: aarch64-pc-windows-msvc }
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: ${{ matrix.target }}
- - uses: Swatinem/rust-cache@v2
- with:
- key: release-windows-${{ matrix.arch }}
- - name: Apply version override
- if: inputs.version != ''
- shell: bash
- run: cargo xtask version set "$PDFCRAFT_VERSION"
- - name: Install WiX
- shell: pwsh
- run: dotnet tool install --global wix --version 5.0.2
- - name: Build, sign, package
- shell: pwsh
- env:
- WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
- WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
- AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
- AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
- AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- AZURE_SIGNING_ENDPOINT: ${{ secrets.AZURE_SIGNING_ENDPOINT }}
- AZURE_SIGNING_ACCOUNT: ${{ secrets.AZURE_SIGNING_ACCOUNT }}
- AZURE_CERT_PROFILE: ${{ secrets.AZURE_CERT_PROFILE }}
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- run: ./packaging/windows/package.ps1 -Arch ${{ matrix.arch }}
- - uses: actions/upload-artifact@v4
- with:
- name: release-windows-${{ matrix.arch }}
- path: dist/release/*
- if-no-files-found: error
-
- linux:
- name: Linux ${{ matrix.arch }}
- needs: version
- # The oldest GitHub-hosted image, so the binaries only need glibc >= 2.35 (Ubuntu 22.04+,
- # Debian 12+, Fedora 36+, RHEL 10). See docs/releasing.md.
- runs-on: ${{ matrix.runner }}
- # No `environment: release`: this job signs nothing, so it gets no release secrets.
- strategy:
- fail-fast: false
- matrix:
- include:
- - { arch: x86_64, runner: ubuntu-22.04, deb: amd64 }
- - { arch: aarch64, runner: ubuntu-22.04-arm, deb: arm64 }
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- NFPM_VERSION: 2.47.0
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - name: Install build and packaging tools
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends \
- libxkbcommon-dev libwayland-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev \
- desktop-file-utils appstream python3-yaml zsync
- curl -fsSL -o "$RUNNER_TEMP/nfpm.deb" \
- "https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_${{ matrix.deb }}.deb"
- sudo dpkg -i "$RUNNER_TEMP/nfpm.deb"
- - uses: dtolnay/rust-toolchain@stable
- - uses: Swatinem/rust-cache@v2
- with:
- key: release-linux-${{ matrix.arch }}
- - name: Apply version override
- if: inputs.version != ''
- run: cargo xtask version set "$PDFCRAFT_VERSION"
- - name: Build and package (AppImage, deb, rpm, tar.gz, CLI tar.gz)
- env:
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- run: packaging/linux/package.sh
- - name: Check the packages
- run: |
- dpkg-deb --info dist/release/*.deb
- dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/pdfcraft$|metainfo|applications'
- # The OCR models (#103), where the installed app looks: /../share/pdfcraft/models.
- dpkg-deb --contents dist/release/*.deb | grep -E 'usr/share/pdfcraft/models/.+\.onnx$'
- # Named exactly: dist/release also holds the CLI-only tar.gz, and `tar -tzf a b` reads b as a member.
- tar -tzf "dist/release/pdfcraft-$PDFCRAFT_VERSION-linux-${{ matrix.arch }}.tar.gz" | grep -E '/share/pdfcraft/models/.+\.onnx$'
- ldd target/release/pdfcraft
- # The CLI-only archive: the binary and its licences, and it runs.
- cli="dist/release/pdfcraft-cli-$PDFCRAFT_VERSION-linux-${{ matrix.arch }}.tar.gz"
- tar -tzf "$cli" | grep -E '/pdfcraft-cli$'
- tar -tzf "$cli" | grep -E '/LICENSE-APACHE$'
- mkdir -p "$RUNNER_TEMP/cli" && tar -xzf "$cli" -C "$RUNNER_TEMP/cli"
- "$RUNNER_TEMP/cli/pdfcraft-cli-$PDFCRAFT_VERSION-linux-${{ matrix.arch }}/pdfcraft-cli" --version
- python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.pdfcraft.yml')); assert m['id'] == 'ai.storyteller.pdfcraft'"
- for appimage in dist/release/*.AppImage; do
- chmod +x "$appimage"
- APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --version
- # Update information is embedded, and the .zsync for delta updates sits beside it.
- "$appimage" --appimage-updateinformation | grep -F 'gh-releases-zsync|'
- test -s "$appimage.zsync"
- done
- - uses: actions/upload-artifact@v4
- with:
- name: release-linux-${{ matrix.arch }}
- path: dist/release/*
- if-no-files-found: error
-
- linux-riscv64:
- name: Linux riscv64
- needs: version
- # Cross-compiled on x86_64 (no hosted RISC-V runners) against the runner's own Ubuntu release
- # from ports.ubuntu.com, so the binaries need that release's glibc (24.04: 2.39). 22.04's
- # riscv64 ports lag its amd64 updates, which breaks the multiarch install. tar.gz only (the
- # app tree and the CLI-only archive); the CLI is smoke-tested under QEMU.
- runs-on: ubuntu-24.04
- # No `environment: release`: this job signs nothing, so it gets no release secrets.
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: riscv64gc-unknown-linux-gnu
- - uses: Swatinem/rust-cache@v2
- with:
- key: release-linux-riscv64
- - name: Apply version override
- if: inputs.version != ''
- run: cargo xtask version set "$PDFCRAFT_VERSION"
- - name: Install cross-compilation dependencies
- run: |
- . /etc/os-release
- sudo dpkg --add-architecture riscv64
- # Pin the existing (archive.ubuntu.com) sources to amd64; riscv64 comes from ports.
- if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then
- sudo sed -i '/^Types: deb/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
- fi
- if [ -f /etc/apt/sources.list ]; then
- sudo sed -i 's/^deb /deb [arch=amd64] /g' /etc/apt/sources.list
- sudo sed -i 's/^deb-src /deb-src [arch=amd64] /g' /etc/apt/sources.list
- fi
- for suite in "$VERSION_CODENAME" "$VERSION_CODENAME-updates" "$VERSION_CODENAME-security"; do
- echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports $suite main universe restricted multiverse"
- done | sudo tee /etc/apt/sources.list.d/riscv64.list
- sudo apt-get update
- # The same -dev packages as the linux job, for riscv64; the C toolchain also builds
- # aws-lc-sys and ring (signing, TLS).
- sudo apt-get install -y --no-install-recommends \
- gcc-riscv64-linux-gnu g++-riscv64-linux-gnu binutils-riscv64-linux-gnu libc6-dev-riscv64-cross \
- libc6-dev:riscv64 qemu-user \
- libxkbcommon-dev:riscv64 libwayland-dev:riscv64 libx11-dev:riscv64 libxrandr-dev:riscv64 \
- libxi-dev:riscv64 libgl1-mesa-dev:riscv64
- - name: Build and package (tar.gz, CLI tar.gz)
- env:
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER: riscv64-linux-gnu-gcc
- CC_riscv64gc_unknown_linux_gnu: riscv64-linux-gnu-gcc
- CXX_riscv64gc_unknown_linux_gnu: riscv64-linux-gnu-g++
- AR_riscv64gc_unknown_linux_gnu: riscv64-linux-gnu-ar
- PKG_CONFIG_SYSROOT_DIR: /
- PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig:/usr/share/pkgconfig
- PKG_CONFIG_ALLOW_CROSS: "1"
- CROSS_ARCH: riscv64
- CROSS_TARGET: riscv64gc-unknown-linux-gnu
- CROSS_COMPILE: riscv64-linux-gnu-
- EMULATOR: qemu-riscv64
- QEMU_LD_PREFIX: /usr/riscv64-linux-gnu
- run: packaging/linux/package.sh --formats "tar cli"
- - name: Check the packages
- run: |
- tar -tzf "dist/release/pdfcraft-$PDFCRAFT_VERSION-linux-riscv64.tar.gz" | grep -E '/bin/pdfcraft$'
- # The OCR models (#103), where the installed app looks: /../share/pdfcraft/models.
- tar -tzf "dist/release/pdfcraft-$PDFCRAFT_VERSION-linux-riscv64.tar.gz" | grep -E '/share/pdfcraft/models/.+\.onnx$'
- cli="dist/release/pdfcraft-cli-$PDFCRAFT_VERSION-linux-riscv64.tar.gz"
- tar -tzf "$cli" | grep -E '/pdfcraft-cli$'
- tar -tzf "$cli" | grep -E '/LICENSE-APACHE$'
- file target/riscv64gc-unknown-linux-gnu/release/pdfcraft | grep -F 'RISC-V'
- - uses: actions/upload-artifact@v4
- with:
- name: release-linux-riscv64
- path: dist/release/*.tar.gz
- if-no-files-found: error
-
- flatpak:
- name: Flatpak ${{ matrix.arch }}
- needs: [version, linux]
- # Repackages the Linux job's tarball (the same binaries as the AppImage/deb/rpm); no Rust
- # build here. 24.04 for a newer flatpak-builder (1.4) than 22.04 ships.
- runs-on: ${{ matrix.runner }}
- # No `environment: release`: this job signs nothing, so it gets no release secrets.
- strategy:
- fail-fast: false
- matrix:
- include:
- - { arch: x86_64, runner: ubuntu-24.04 }
- - { arch: aarch64, runner: ubuntu-24.04-arm }
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- steps:
- - uses: actions/checkout@v4
- - uses: actions/download-artifact@v4
- with:
- name: release-linux-${{ matrix.arch }}
- path: dist/linux
- - name: Install flatpak-builder
- run: |
- sudo apt-get update
- # librsvg2-common: the SVG pixbuf loader. flatpak-builder runs the host's
- # `appstreamcli compose`, which renders the scalable icon and fails without it.
- sudo apt-get install -y --no-install-recommends flatpak flatpak-builder librsvg2-common
- # Ubuntu 24.04's AppArmor blocks the unprivileged user namespaces bubblewrap needs.
- sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- - name: Build the Flatpak bundle
- run: packaging/linux/flatpak-bundle.sh "dist/linux/pdfcraft-$PDFCRAFT_VERSION-linux-${{ matrix.arch }}.tar.gz"
- - uses: actions/upload-artifact@v4
- with:
- name: release-flatpak-${{ matrix.arch }}
- path: dist/release/*.flatpak
- if-no-files-found: error
-
- freebsd:
- name: FreeBSD x86_64
- needs: version
- # GitHub has no FreeBSD runners: build in a FreeBSD VM (see .github/workflows/freebsd.yml).
- runs-on: ubuntu-latest
- timeout-minutes: 180
- # No `environment: release`: this job signs nothing, so it gets no release secrets.
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- VERSION_OVERRIDE: ${{ inputs.version }}
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - name: Build and package in a FreeBSD VM (tar.gz)
- # vmactions/freebsd-vm v1.5.9, pinned by commit (it runs our build).
- uses: vmactions/freebsd-vm@c46abacb49f09938ca4e1702d15d836285d694cc
- with:
- release: "14.3"
- usesh: true
- cpu: 4
- mem: 12288
- envs: "PDFCRAFT_VERSION PDFCRAFT_BUILD_DATE VERSION_OVERRIDE"
- # The same packages as the FreeBSD CI workflow, plus bash for the packaging script.
- prepare: |
- pkg install -y bash git curl pkgconf cmake python3 libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader gtk3 fontconfig freetype2 alsa-lib
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
- run: |
- set -e
- . "$HOME/.cargo/env"
- git config --global --add safe.directory "$PWD"
- export CRAFT_FONTS_DIR="$PWD/craft-fonts" CRAFT_FONTS_REQUIRED=1
- if [ -n "$VERSION_OVERRIDE" ]; then cargo xtask version set "$PDFCRAFT_VERSION"; fi
- packaging/freebsd/package.sh
- # Only dist/ comes back out of the VM: copying the target dir back fails on large builds.
- rm -rf target
- - uses: actions/upload-artifact@v4
- with:
- name: release-freebsd-x86_64
- path: dist/release/*
- if-no-files-found: error
-
- web:
- name: Web (wasm)
- needs: version
- runs-on: ubuntu-latest
- # No `environment: release`: this job signs nothing, so it gets no release secrets.
- env:
- PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
- TRUNK_VERSION: 0.21.14
- steps:
- - uses: actions/checkout@v4
- # The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
- - name: Check out craft-fonts
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- with:
- repository: storytold/craft-fonts
- ref: 8dcdacd5153e64560d109541a47d806f26f048c0
- path: craft-fonts
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: wasm32-unknown-unknown
- - uses: Swatinem/rust-cache@v2
- with:
- key: release-web
- - name: Install trunk
- run: |
- curl -fsSL "https://github.com/trunk-rs/trunk/releases/download/v${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz" \
- | tar -xz -C "$HOME/.cargo/bin" trunk
- trunk --version
- - name: Apply version override
- if: inputs.version != ''
- run: cargo xtask version set "$PDFCRAFT_VERSION"
- - name: Build and zip
- env:
- CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
- CRAFT_FONTS_REQUIRED: "1"
- run: packaging/web/package.sh
- - uses: actions/upload-artifact@v4
- with:
- name: release-web
- path: dist/release/*
- if-no-files-found: error
-
release:
- name: Draft GitHub Release
- # Needs the signing jobs, which only run on `release`: a branch dry run never drafts a release.
- needs: [version, macos, windows, linux, linux-riscv64, flatpak, freebsd, web]
- runs-on: ubuntu-latest
- environment: release
- permissions:
- contents: write
- env:
- VERSION: ${{ needs.version.outputs.version }}
- PRERELEASE: ${{ needs.version.outputs.prerelease }}
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GH_REPO: ${{ github.repository }}
- steps:
- - uses: actions/download-artifact@v4
- with:
- pattern: release-*
- path: artifacts
- merge-multiple: true
- - name: Checksums
- working-directory: artifacts
- run: |
- sha256sum -- * | tee SHA256SUMS.txt
- - name: Create or update the draft release
- working-directory: artifacts
- run: |
- tag="v$VERSION"
- title="PdfCraft v$VERSION"
- pre=()
- if [ "$PRERELEASE" = true ]; then pre=(--prerelease); fi
- if draft="$(gh release view "$tag" --json isDraft --jq .isDraft 2>/dev/null)"; then
- if [ "$draft" != "true" ]; then
- echo "::error::Release $tag is already published. Bump the version (cargo xtask version set) before pushing to release."
- exit 1
- fi
- echo "Updating draft $tag: replacing its assets"
- gh release view "$tag" --json assets --jq '.assets[].name' | while read -r asset; do
- gh release delete-asset "$tag" "$asset" --yes
- done
- gh release edit "$tag" --draft --title "$title" --target "$GITHUB_SHA" --prerelease="$PRERELEASE"
- gh release upload "$tag" --clobber -- *
- else
- echo "Creating draft $tag"
- gh release create "$tag" --draft --title "$title" --target "$GITHUB_SHA" --generate-notes "${pre[@]}" -- *
- fi
- {
- echo "Draft release **$title** at \`${GITHUB_SHA::9}\`:"
- echo
- sed 's/^/ /' SHA256SUMS.txt
- } >>"$GITHUB_STEP_SUMMARY"
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/release.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+ with:
+ app-name: pdfcraft
+ app-title: PlutarchPages
+ craft-fonts-ref: b076417b5880bd4154bd22f00695b1d28c6bea83
+ version: ${{ inputs.version }}
+ secrets:
+ APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
+ APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
+ WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_SIGNING_ENDPOINT: ${{ secrets.AZURE_SIGNING_ENDPOINT }}
+ AZURE_SIGNING_ACCOUNT: ${{ secrets.AZURE_SIGNING_ACCOUNT }}
+ AZURE_CERT_PROFILE: ${{ secrets.AZURE_CERT_PROFILE }}
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
new file mode 100644
index 0000000000..6f99597f63
--- /dev/null
+++ b/.github/workflows/sonarcloud.yml
@@ -0,0 +1,21 @@
+name: SonarCloud
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: sonarcloud-${{ github.ref }}
+ # A push to main is the run that publishes coverage; superseded runs there would never finish.
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
+
+jobs:
+ sonarcloud:
+ uses: storytold/craft-common-actions/.github/workflows/sonarcloud.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+ secrets:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml
index 07d2861aa2..438231da2d 100644
--- a/.github/workflows/windows-arm64.yml
+++ b/.github/workflows/windows-arm64.yml
@@ -25,134 +25,12 @@ concurrency:
permissions:
contents: read
-env:
- CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: 1
-
jobs:
- package:
- name: package (cross-compiled on x64)
- runs-on: windows-latest
- timeout-minutes: 90
- steps:
- - uses: actions/checkout@v4
- - uses: dtolnay/rust-toolchain@stable
- with:
- targets: aarch64-pc-windows-msvc
- - uses: Swatinem/rust-cache@v2
- with:
- key: windows-arm64-package
- - name: Install WiX
- shell: pwsh
- run: dotnet tool install --global wix --version 5.0.2
- - name: Build and package (unsigned)
- shell: pwsh
- env:
- DIST: ${{ github.workspace }}\dist\arm64
- run: ./packaging/windows/package.ps1 -Arch arm64
- - uses: actions/upload-artifact@v4
- with:
- name: pdfcraft-windows-arm64
- path: dist/arm64/*
- if-no-files-found: error
- retention-days: 7
-
- install:
- name: install and run on ARM64
- needs: package
- runs-on: windows-11-arm
- timeout-minutes: 30
- steps:
- - uses: actions/download-artifact@v4
- with:
- name: pdfcraft-windows-arm64
- path: dist
- - name: Install the MSI, check it, run it, uninstall it, reinstall without the desktop shortcut
- shell: pwsh
- run: |
- $ErrorActionPreference = 'Stop'
- $msi = (Get-ChildItem dist/*.msi | Select-Object -First 1).FullName
- # A command-line override must not put files in a user profile while registering
- # their handlers machine-wide (#305). This runs on a disposable CI runner.
- $p = Start-Process msiexec.exe -WindowStyle Hidden -ArgumentList '/i', "`"$msi`"", '/qn', 'ALLUSERS=2', 'MSIINSTALLPERUSER=1', '/l*v', 'per-user.log' -Wait -PassThru
- if ($p.ExitCode -ne 1603) { Get-Content per-user.log -Tail 60; throw "per-user install should fail with 1603, got $($p.ExitCode)" }
- if (-not (Select-String -Path per-user.log -SimpleMatch 'PlutarchPages must be installed for all users.')) {
- Get-Content per-user.log -Tail 60; throw 'per-user install did not fail on the scope guard'
- }
- $p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', '/l*v', 'install.log' -Wait -PassThru
- if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 60; throw "msiexec /i exited $($p.ExitCode)" }
- $shortcuts = @(
- (Join-Path ([Environment]::GetFolderPath('CommonPrograms')) 'PlutarchPages.lnk'),
- (Join-Path ([Environment]::GetFolderPath('CommonDesktopDirectory')) 'PlutarchPages.lnk')
- )
- # Plain shortcuts to the program (#143), not advertised ones, so TargetPath is the exe.
- $exePath = Join-Path $env:ProgramFiles 'PlutarchPages\pdfcraft.exe'
- $wsh = New-Object -ComObject WScript.Shell
- foreach ($shortcut in $shortcuts) {
- if (-not (Test-Path -LiteralPath $shortcut)) { throw "installer did not create $shortcut" }
- $target = $wsh.CreateShortcut($shortcut).TargetPath
- if ($target -ne $exePath) { throw "$shortcut points to '$target', not $exePath" }
- Write-Output "ok $shortcut -> $target"
- }
- $dir = Join-Path $env:ProgramFiles 'PlutarchPages'
- foreach ($exe in 'pdfcraft.exe', 'pdfcraft-cli.exe') {
- $path = Join-Path $dir $exe
- if (-not (Test-Path $path)) { Get-ChildItem -Recurse $env:ProgramFiles -Filter $exe | Select-Object -First 3; throw "$exe not installed in $dir" }
- $bytes = [System.IO.File]::ReadAllBytes($path)
- $machine = [BitConverter]::ToUInt16($bytes, [BitConverter]::ToInt32($bytes, 0x3C) + 4)
- if ($machine -ne 0xAA64) { throw "$exe is for machine 0x$('{0:X}' -f $machine), not ARM64" }
- Write-Output "ok $path (ARM64)"
- }
- # The installed CLI runs natively: open, render and edit a small PDF through the engine.
- $cli = Join-Path $dir 'pdfcraft-cli.exe'
- & $cli tools | Out-Null
- if ($LASTEXITCODE -ne 0) { throw "pdfcraft-cli tools exited $LASTEXITCODE" }
- $body = 'BT /F1 24 Tf 20 150 Td (Hello ARM64) Tj ET'
- $objs = @('<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
- '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>',
- "<< /Length $($body.Length) >>`nstream`n$body`nendstream", '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>')
- $sb = [System.Text.StringBuilder]::new("%PDF-1.7`n"); $offsets = @()
- for ($i = 0; $i -lt $objs.Count; $i++) { $offsets += $sb.Length; [void]$sb.Append("$($i + 1) 0 obj`n$($objs[$i])`nendobj`n") }
- $xref = $sb.Length
- [void]$sb.Append("xref`n0 $($objs.Count + 1)`n0000000000 65535 f `n")
- foreach ($o in $offsets) { [void]$sb.Append(('{0:D10} 00000 n `n' -f $o)) }
- [void]$sb.Append("trailer`n<< /Size $($objs.Count + 1) /Root 1 0 R >>`nstartxref`n$xref`n%%EOF`n")
- New-Item -ItemType Directory -Force smoke | Out-Null
- [System.IO.File]::WriteAllText("$PWD\smoke\hello.pdf", $sb.ToString(), [System.Text.Encoding]::ASCII)
- $steps = '[{"tool":"doc_open","args":{"path":"hello.pdf"}},{"tool":"text_paragraphs","args":{"doc":1,"page":1}},{"tool":"text_edit","args":{"doc":1,"page":1,"paragraph":1,"text":"Edited on ARM64"}},{"tool":"page_render","args":{"doc":1,"page":1,"dpi":72},"out":"page.png"},{"tool":"doc_save","args":{"doc":1,"path":"out.pdf"}}]'
- [System.IO.File]::WriteAllText("$PWD\smoke\steps.json", $steps)
- $out = & $cli run --script smoke\steps.json --root smoke 2>&1 | Out-String
- if ($LASTEXITCODE -ne 0) { Write-Output $out; throw "pdfcraft-cli run exited $LASTEXITCODE" }
- if ($out -notmatch 'Hello ARM64') { Write-Output $out; throw 'text_paragraphs did not read the page' }
- foreach ($f in 'smoke\page.png', 'smoke\out.pdf') { if (-not (Test-Path $f) -or (Get-Item $f).Length -eq 0) { Write-Output $out; throw "$f was not written" } }
- Write-Output 'ok pdfcraft-cli: opened, read, edited, rendered and saved a PDF on ARM64'
- $p = Start-Process msiexec.exe -ArgumentList '/x', "`"$msi`"", '/qn' -Wait -PassThru
- if ($p.ExitCode -ne 0) { throw "msiexec /x exited $($p.ExitCode)" }
- if (Test-Path (Join-Path $dir 'pdfcraft.exe')) { throw 'uninstall left pdfcraft.exe behind' }
- foreach ($shortcut in $shortcuts) {
- if (Test-Path -LiteralPath $shortcut) { throw "uninstall left $shortcut behind" }
- }
- Write-Output 'ok uninstalled'
- # Unattended installs can opt out of the desktop shortcut (#143); the Start Menu one stays.
- $p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', 'INSTALLDESKTOPSHORTCUT=0', '/l*v', 'install-nodesktop.log' -Wait -PassThru
- if ($p.ExitCode -ne 0) { Get-Content install-nodesktop.log -Tail 60; throw "msiexec /i INSTALLDESKTOPSHORTCUT=0 exited $($p.ExitCode)" }
- if (-not (Test-Path -LiteralPath $shortcuts[0])) { throw "INSTALLDESKTOPSHORTCUT=0 also skipped $($shortcuts[0])" }
- if (Test-Path -LiteralPath $shortcuts[1]) { throw "INSTALLDESKTOPSHORTCUT=0 still created $($shortcuts[1])" }
- $p = Start-Process msiexec.exe -ArgumentList '/x', "`"$msi`"", '/qn' -Wait -PassThru
- if ($p.ExitCode -ne 0) { throw "msiexec /x exited $($p.ExitCode)" }
- if (Test-Path -LiteralPath $shortcuts[0]) { throw "uninstall left $($shortcuts[0]) behind" }
- Write-Output 'ok INSTALLDESKTOPSHORTCUT=0: Start Menu shortcut only'
-
- test:
- name: test (native ARM64)
- runs-on: windows-11-arm
- timeout-minutes: 120
- steps:
- - uses: actions/checkout@v4
- - uses: dtolnay/rust-toolchain@stable
- - uses: Swatinem/rust-cache@v2
- with:
- key: windows-arm64-test
- - name: Test
- run: cargo test --workspace --locked
+ windows-arm64:
+ # Pinned: a mutable reference to another repository can change what CI runs. Move it deliberately.
+ uses: storytold/craft-common-actions/.github/workflows/windows-arm64.yml@2b3fb9dc05036f73c77d18f753a3aa9da55fa386 # main, 31 October 2026
+ with:
+ app-name: pdfcraft
+ app-dir: PlutarchPages
+ install-relative-path: Programs/PlutarchPages
+ install-scope: perUser
diff --git a/AGENTS.md b/AGENTS.md
index 671d7a6ca3..fc3a75a673 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -20,12 +20,12 @@ An **asset** is any non-code material that the project includes, ships, embeds,
- **Never** use icons, images, artwork, logos, UI graphics, fonts, stamps, cursors, sample documents or any other asset taken from an Adobe product, installer, website, document or package.
- "Adobe product" includes Acrobat, Reader, Photoshop, Illustrator, Premiere, Lightroom and Creative Cloud, including the fonts they install (for example Minion, Myriad, Kozuka and the Adobe CJK families).
- - This holds even when Adobe publishes the material under an open licence, if it is **visual design**. For example, **do not** use Source Han, Source Serif or Source Sans, or Noto CJK, which is Source Han rebranded.
+ - Typefaces released under the SIL Open Font License are allowed like any other OFL font, with an `ATTRIBUTION.toml` entry, whoever designed them: for example Noto CJK and Source Han, taken from their open-source releases. The copies an Adobe product installs stay banned.
- **Never** recreate, trace, redraw or closely imitate an Adobe icon or graphic. Our icons come from Lucide, and our visual design is our own.
- Screenshots of Adobe software exist only as private, local observation notes under `plan/acrobat/`, which is gitignored. They must **never** be committed, published, linked, shown in docs, used as a design source to trace, or placed anywhere else in the repository or its outputs.
-- The only Adobe-authored material allowed is **non-visual technical data** that is openly licensed and required for PDF compatibility. Each item needs its own entry in `ATTRIBUTION.toml` with `adobe_data = true`, and the list below is closed:
+- Apart from those OFL typefaces, the only Adobe-authored material allowed is **non-visual technical data** that is openly licensed and required for PDF compatibility. Each item needs its own entry in `ATTRIBUTION.toml` with `adobe_data = true`, and the list below is closed:
- The CMap resources (BSD-3-Clause), bundled inside the `hayro-cmap` dependency.
- - The standard-14 font metrics and encoding tables in the PDF specification. They are data, not typefaces, and are embedded as code in hayro.
+ - The standard-14 font metrics and encoding tables in the PDF specification. They are data, not typefaces. They are embedded as code in hayro, and as our own generated table in `crates/fonts/src/std14_metrics.rs` (approved by the owner, 2026-10-08; that file holds the data alone, so the code reading it can change without re-attesting the table), which is what generated appearances measure with and what survives hayro being retired.
Adding anything to this list needs the user's explicit approval.
@@ -54,16 +54,17 @@ Anything else is forbidden, including assets whose licence you cannot prove from
- path or URL, title, author;
- source (URL, with version or commit);
- SPDX licence, and the licence file in the repo;
- - SHA-256;
+ - SHA-256, except for translation catalogs (see below);
- how it is used.
+- **Translation catalogs** (`crates/ui-egui/src/i18n/*.tsv`, `kind = "translation"`) are project files under the project licence. Their entries carry no `sha256`: git history records every change and who made it. Every other kind (fonts, images, data) is hashed.
- **`ATTRIBUTION.md`** is generated from it (`cargo xtask assets --write`). Never edit it by hand.
- **`NOTICE`** keeps the licence notices that the licences require.
- **`cargo xtask assets`** runs in `cargo xtask ci`. It fails if:
- an asset file in the repository has no entry;
- - an entry's hash does not match;
+ - an entry's hash is missing or does not match (translation catalogs carry none);
- a licence is not on the allowlist;
- a licence file is missing;
- - an image, icon or font names Adobe as author or source.
+ - an image, icon or font names Adobe as author or source, except a font licensed under OFL-1.1 alone.
- **`cargo xtask demo-pdf`** downloads its fonts only from `ATTRIBUTION.toml` entries, pinned by SHA-256. Afterwards it **fails if the PDF embeds any font not in its allowlist**, which catches the browser silently falling back to a system font.
### 1.4 Fonts live in craft-fonts
@@ -137,3 +138,8 @@ Follow `CLAUDE.md`. It covers quality gates, layering, commit rules and how to r
GitHub profiles). Never hand-edit `contributors.json`.
- Maintainers refresh the stats with `python3 ../../craftrules/scripts/contributors.py .` (it also
re-verifies who wrote each `people.toml` entry; `--check` only verifies).
+
+## CI workflows
+- Workflows in `.github/workflows/` call the shared workflows in [`storytold/craft-common-actions`](https://github.com/storytold/craft-common-actions) at `@main`, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here.
+- Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time.
+- Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it.
diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md
index 44435b23af..b8281a9c8a 100644
--- a/ATTRIBUTION.md
+++ b/ATTRIBUTION.md
@@ -2,28 +2,40 @@
-Every asset PdfCraft includes, bundles or uses to build its published material, with its author, source and licence. The policy is in [AGENTS.md](AGENTS.md) §1. The machine-readable list, with SHA-256 hashes, is [ATTRIBUTION.toml](ATTRIBUTION.toml). Licence texts are kept beside the assets and summarised in [NOTICE](NOTICE).
+Every asset PdfCraft includes, bundles or uses to build its published material, with its author, source and licence. The policy is in [AGENTS.md](AGENTS.md) §1. The machine-readable list, with the SHA-256 of every asset but the translation catalogs, is [ATTRIBUTION.toml](ATTRIBUTION.toml). Licence texts are kept beside the assets and summarised in [NOTICE](NOTICE).
-## In this repository (262)
+## In this repository (288)
| Asset | Title | Author | Licence | Source | Used for |
|---|---|---|---|---|---|
-| `crates/ui-egui/src/i18n/zh-hans.tsv` | Simplified Chinese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/zh-hant.tsv` | Traditional Chinese (Taiwan) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/cs.tsv` | Czech interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Czech UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/pt-br.tsv` | Brazilian Portuguese interface translation catalog | André Cardoso (andrecards), PdfCraft contributors | MIT OR Apache-2.0 | Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors | Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/es.tsv` | Spanish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Spanish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/fr.tsv` | French interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/de.tsv` | German interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/te.tsv` | Telugu interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Telugu UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/it.tsv` | Italian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/pl.tsv` | Polish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Polish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/ru.tsv` | Russian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/hu.tsv` | Hungarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/bg.tsv` | Bulgarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/ja.tsv` | Japanese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
-| `crates/ui-egui/src/i18n/ar.tsv` | Arabic interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources | Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs |
+| `crates/ui-egui/src/i18n/el.tsv` | Greek interface translation catalog | Camthalion77 and contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Greek UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/zh-hans.tsv` | Simplified Chinese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/zh-hant.tsv` | Traditional Chinese (Taiwan) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/cs.tsv` | Czech interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Czech UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/pt-br.tsv` | Brazilian Portuguese interface translation catalog | André Cardoso (andrecards), PdfCraft contributors | MIT OR Apache-2.0 | Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/es.tsv` | Spanish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Spanish UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/fr.tsv` | French interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | French UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/de.tsv` | German interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | German UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/lo.tsv` | Lao interface translation catalog | @bounkirdni-2025 | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Lao UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/te.tsv` | Telugu interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Telugu UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/it.tsv` | Italian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Italian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/pl.tsv` | Polish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Polish UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ru.tsv` | Russian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Russian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/hu.tsv` | Hungarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Hungarian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/bg.tsv` | Bulgarian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/kk.tsv` | Kazakh interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Kazakh UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ja.tsv` | Japanese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Japanese UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ar.tsv` | Arabic interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Arabic UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ckb.tsv` | Central Kurdish (Sorani) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Central Kurdish UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/fa.tsv` | Persian (Farsi) interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed | Persian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/tr.tsv` | Turkish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Turkish UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/lt.tsv` | Lithuanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/hi.tsv` | Hindi interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Hindi UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/id.tsv` | Indonesian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Indonesian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ko.tsv` | Korean interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Korean UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ro.tsv` | Romanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Romanian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/fi.tsv` | Finnish interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Finnish UI strings, compiled in by crates/ui-egui/src/i18n.rs |
| `assets/icons/accessibility.svg` | Lucide icon "accessibility" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/accessibility.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/align-left.svg` | Lucide icon "align-left" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/align-left.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/align-center.svg` | Lucide icon "align-center" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/align-center.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
@@ -199,7 +211,7 @@ Every asset PdfCraft includes, bundles or uses to build its published material,
| `assets/icons/x.svg` | Lucide icon "x" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/x.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/zoom-in.svg` | Lucide icon "zoom-in" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/zoom-in.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/zoom-out.svg` | Lucide icon "zoom-out" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/zoom-out.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
-| `assets/fonts/Inter-Regular.ttf` | Inter Regular | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/rsms/inter | UI font, embedded in the app; demo PDF labels |
+| `assets/fonts/Inter-Regular.ttf` | Inter Regular | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/rsms/inter | UI font, embedded in the app; demo PDF labels; slanted fallback glyphs in Fill & Sign typed signatures for characters Dancing Script lacks (Cyrillic, Greek), drawn as filled paths |
| `assets/fonts/Inter-Medium.ttf` | Inter Medium | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/rsms/inter | UI font, embedded in the app; demo PDF labels |
| `assets/fonts/Inter-SemiBold.ttf` | Inter SemiBold | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/rsms/inter | UI font, embedded in the app; demo PDF labels |
| `assets/fonts/JetBrainsMono-Regular.ttf` | JetBrains Mono Regular | The JetBrains Mono Project Authors | OFL-1.1 | https://github.com/JetBrains/JetBrainsMono | UI monospace font; demo PDF code |
@@ -218,7 +230,8 @@ Every asset PdfCraft includes, bundles or uses to build its published material,
| `vendor/hayro-interpret/assets/FoxitSerifItalic.pfb` | FoxitSerifItalic (standard-14 substitute font) | Foxit Software Inc. / PDFium Authors | BSD-3-Clause | https://pdfium.googlesource.com/pdfium (via hayro-interpret 0.7.0 assets/) | Renders non-embedded standard-14 fonts (vendored hayro-interpret) |
| `vendor/hayro-interpret/assets/FoxitSymbol.pfb` | FoxitSymbol (standard-14 substitute font) | Foxit Software Inc. / PDFium Authors | BSD-3-Clause | https://pdfium.googlesource.com/pdfium (via hayro-interpret 0.7.0 assets/) | Renders non-embedded standard-14 fonts (vendored hayro-interpret) |
| `vendor/hayro-interpret/assets/CGATS001Compat-v2-micro.icc` | CGATS001Compat v2 micro ICC profile | Clinton Ingram (saucecontrol/Compact-ICC-Profiles) | CC0-1.0 | https://github.com/saucecontrol/Compact-ICC-Profiles | Default CMYK colour conversion (vendored hayro-interpret) |
-| `vendor/hayro-interpret/assets/LAB.icc` | Lab abstract ICC profile | The Hayro Authors (generated with LittleCMS 2) | MIT OR Apache-2.0 | https://github.com/LaurenzV/hayro (hayro-interpret 0.7.0 assets/) | Lab colour space conversion (vendored hayro-interpret) |
+| `crates/fonts/src/std14_metrics.rs` | Standard-14 font advance widths and encodings (as Rust tables) | Adobe (Core14 AFM metrics, PDF specification encodings); tables generated by the PdfCraft contributors | MIT OR Apache-2.0 | ISO 32000-2 Annex D and the Adobe Core14 AFM metrics. Generated by joining the published WinAnsi, Symbol and ZapfDingbats encodings (code to glyph name) with the per-glyph advance widths, then spot-checked against the specification by hand in the tests of crates/fonts/src/std14.rs. Data only: the code that reads these tables lives in std14.rs, so that ordinary edits do not churn this file's hash. | Advance widths for the fourteen standard fonts, which a PDF may name without embedding. Non-visual data, not a typeface: the item AGENTS.md 1.1 permits, held first-party so generated appearance streams and the renderer agree. |
+| `vendor/hayro-cmap/assets/cmaps.brotli` | Adobe CMap resources (predefined CJK CMaps) | Adobe | BSD-3-Clause | https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap 0.1.0 assets/) | Character-code mapping tables required to read CJK PDFs. Non-visual data, allowed by AGENTS.md §1.1 |
| `assets/app-icon/pdfcraft.svg` | PdfCraft app icon (master vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Master artwork; every other app-icon file is rendered from it (packaging/icons.sh) |
| `assets/app-icon/pdfcraft-small.svg` | PdfCraft app icon (light vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | README header and assets/app-icon/README.md |
| `assets/app-icon/pdfcraft-1024.png` | PdfCraft app icon, 1024 px on Apple's icon grid | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs) |
@@ -242,18 +255,6 @@ Every asset PdfCraft includes, bundles or uses to build its published material,
| `.github/assets/badges/fork-of.svg` | PlutarchPages README badge: fork of PdfCraft | shields.io contributors (static badge template); badge text by EquityBot | Apache-2.0 | https://img.shields.io/badge/fork%20of-PdfCraft-66023C?labelColor=000000&style=flat&color=66023C (badges/shields) | README badge row; committed static SVG, text names the font family only, no embedded fonts |
| `.github/assets/badges/licence.svg` | PlutarchPages README badge: licence | shields.io contributors (static badge template); badge text by EquityBot | Apache-2.0 | https://img.shields.io/badge/licence-MIT%20OR%20Apache--2.0-66023C?labelColor=000000&style=flat&color=66023C (badges/shields) | README badge row; committed static SVG, text names the font family only, no embedded fonts |
| `.github/assets/badges/rust.svg` | PlutarchPages README badge: Rust version | shields.io contributors (static badge template); badge text by EquityBot | Apache-2.0 | https://img.shields.io/badge/rust-1.90%2B-66023C?labelColor=000000&style=flat&color=66023C (badges/shields) | README badge row; committed static SVG, text names the font family only, no embedded fonts |
-| `docs/images/pdfcraft-bookmarks.png` | PdfCraft screenshot: Bookmarks | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-dark.png` | PdfCraft screenshot: Dark theme | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-find.png` | PdfCraft screenshot: Find text | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-forms.png` | PdfCraft screenshot: Interactive form | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-layers.png` | PdfCraft screenshot: Layers | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-organize.png` | PdfCraft screenshot: Organize pages | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-palette.png` | PdfCraft screenshot: Command palette | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-properties.png` | PdfCraft screenshot: Document properties | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-scripts.png` | PdfCraft screenshot: Scripts of the world | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-split.png` | PdfCraft screenshot: Split dialog | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-twoup.png` | PdfCraft screenshot: Two-up reading | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/pdfcraft-viewer.png` | PdfCraft screenshot: Viewer with comments | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
| `assets/icons/pin.svg` | Lucide icon "pin" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pin.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/move-right.svg` | Lucide icon "move-right" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-right.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/reply.svg` | Lucide icon "reply" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/reply.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
@@ -261,25 +262,50 @@ Every asset PdfCraft includes, bundles or uses to build its published material,
| `assets/icons/thumbs-down.svg` | Lucide icon "thumbs-down" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-down.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/message-square-plus.svg` | Lucide icon "message-square-plus" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-plus.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/circle-x.svg` | Lucide icon "circle-x" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/circle-x.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
-| `crates/ui-egui/tests/data/form.pdf` | One-page AcroForm test fixture (text, check box, radio group, combo box) | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects, no third-party content | Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs) |
+| `crates/ui-egui/tests/data/form.pdf` | One-page AcroForm test fixture (text, check box, radio group, combo box) | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects, no third-party content | Form-filling UI tests (crates/ui-egui/tests/it/forms.rs, commands.rs) |
| `assets/icons/pentagon.svg` | Lucide icon "pentagon" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pentagon.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/message-square-quote.svg` | Lucide icon "message-square-quote" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-quote.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
-| `crates/sign/tests/data/openssl-signed.pdf` | One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make |
+| `crates/sign/tests/data/openssl-signed.pdf` | One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/it/pdf.rs): a signature PdfCraft did not make |
| `assets/icons/clipboard-paste.svg` | Lucide icon "clipboard-paste" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/clipboard-paste.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/fonts/DancingScript.ttf` | Dancing Script (variable) | The Dancing Script Project Authors (Pablo Impallari) | OFL-1.1 | https://github.com/google/fonts/blob/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/dancingscript/DancingScript%5Bwght%5D.ttf | Fill & Sign typed signatures and initials: the typed name's glyph outlines, drawn as filled paths (the font file itself is not embedded in PDFs) |
| `packaging/macos/dmg/background.svg` | PdfCraft macOS DMG window background | @XusBadia | MIT OR Apache-2.0 | Original work for this repository, derived from the PdfCraft app icon (assets/app-icon/pdfcraft.svg, referenced via an SVG image element, not copied); in this fork its title reads PlutarchPages, outlined from Inter SemiBold (assets/fonts/Inter-SemiBold.ttf) with usvg 0.48.1 | Finder window of the macOS DMG; rendered to background.tiff by packaging/macos/dmg/generate.py |
| `packaging/macos/dmg/background.tiff` | PdfCraft macOS DMG window background (rendered) | @XusBadia | MIT OR Apache-2.0 | Rendered from packaging/macos/dmg/background.svg by packaging/macos/dmg/generate.py | 1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile |
-| `crates/sign/tests/data/x509-rsa-sha1.pdf` | One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/pdf.rs): the legacy adbe.x509.rsa_sha1 format |
+| `crates/sign/tests/data/x509-rsa-sha1.pdf` | One-page PDF with a legacy adbe.x509.rsa_sha1 signature by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl dgst -sha1 -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/it/pdf.rs): the legacy adbe.x509.rsa_sha1 format |
+| `assets/icons/monitor.svg` | Lucide icon "monitor" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/monitor.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
+| `crates/ui-egui/src/i18n/vi.tsv` | Vietnamese interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/sl.tsv` | Slovene interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Slovene UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `vendor/vello_common/assets/probe.png` | vello_common probe reference image (rendered from probe.rgba) | Linebender vello contributors | MIT OR Apache-2.0 | vello_common 0.0.8 (crates.io), vendored in vendor/vello_common; regenerated by its vello_sparse_tests regenerate_probe_reference binary | Reference picture of the vendored vello_common probe module, for people only; the build reads probe.rgba, not this file |
+| `crates/ui-egui/src/i18n/nb.tsv` | Norwegian Bokmål interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Norwegian Bokmål UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `assets/icons/superscript.svg` | Lucide icon "superscript" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/superscript.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
+| `assets/icons/subscript.svg` | Lucide icon "subscript" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/subscript.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
+| `assets/icons/pilcrow.svg` | Lucide icon "pilcrow" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pilcrow.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
+| `assets/icons/move-horizontal.svg` | Lucide icon "move-horizontal" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-horizontal.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
+| `crates/ui-egui/src/i18n/sq.tsv` | Albanian interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Albanian UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/th.tsv` | Thai interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Thai UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `crates/ui-egui/src/i18n/ca.tsv` | Catalan interface translation catalog | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed | Catalan UI strings, compiled in by crates/ui-egui/src/i18n.rs |
+| `docs/images/pdfcraft-bookmarks.png` | PdfCraft screenshot: Bookmarks | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-dark.png` | PdfCraft screenshot: Dark theme | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-find.png` | PdfCraft screenshot: Find text | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-forms.png` | PdfCraft screenshot: Interactive form | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-layers.png` | PdfCraft screenshot: Layers | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-organize.png` | PdfCraft screenshot: Organize pages | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-palette.png` | PdfCraft screenshot: Command palette | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-properties.png` | PdfCraft screenshot: Document properties | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-scripts.png` | PdfCraft screenshot: Scripts of the world | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-split.png` | PdfCraft screenshot: Split dialog | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-tools.png` | PdfCraft screenshot: All tools | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tool catalogue. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-twoup.png` | PdfCraft screenshot: Two-up reading | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-viewer.png` | PdfCraft screenshot: Viewer with comments | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
## Compiled in through dependencies (6)
| Crate | File | Title | Author | Licence | Source | Used for |
|---|---|---|---|---|---|---|
-| `epaint_default_fonts` 0.36.2 | `fonts/Ubuntu-Light.ttf` | Ubuntu Light | Canonical Ltd. / Dalton Maag | Ubuntu-font-1.0 | https://design.ubuntu.com/font | egui fallback fonts (eframe feature default_fonts) |
-| `epaint_default_fonts` 0.36.2 | `fonts/Hack-Regular.ttf` | Hack Regular | Source Foundry Authors (derived from Bitstream Vera / DejaVu) | MIT AND Bitstream-Vera | https://github.com/source-foundry/Hack | egui fallback fonts (eframe feature default_fonts) |
-| `epaint_default_fonts` 0.36.2 | `fonts/NotoEmoji-Regular.ttf` | Noto Emoji (monochrome) | Google Inc. | OFL-1.1 | https://github.com/googlefonts/noto-emoji | egui fallback fonts (eframe feature default_fonts) |
-| `epaint_default_fonts` 0.36.2 | `fonts/emoji-icon-font.ttf` | emoji-icon-font | John Slegers | MIT | https://github.com/jslegers/emoji-icon-font | egui fallback fonts (eframe feature default_fonts) |
-| `hayro-cmap` 0.1.0 | `assets/cmaps.brotli` | Adobe CMap resources (predefined CJK CMaps) (non-visual data, AGENTS.md §1.1) | Adobe | BSD-3-Clause | https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap) | Character-code mapping tables required to read CJK PDFs. Non-visual data, allowed by AGENTS.md §1.1 |
+| `epaint_default_fonts` 0.37.0 | `fonts/Ubuntu-Light.ttf` | Ubuntu Light | Canonical Ltd. / Dalton Maag | Ubuntu-font-1.0 | https://design.ubuntu.com/font | egui fallback fonts (eframe feature default_fonts) |
+| `epaint_default_fonts` 0.37.0 | `fonts/Hack-Regular.ttf` | Hack Regular | Source Foundry Authors (derived from Bitstream Vera / DejaVu) | MIT AND Bitstream-Vera | https://github.com/source-foundry/Hack | egui fallback fonts (eframe feature default_fonts) |
+| `epaint_default_fonts` 0.37.0 | `fonts/NotoEmoji-Regular.ttf` | Noto Emoji (monochrome) | Google Inc. | OFL-1.1 | https://github.com/googlefonts/noto-emoji | egui monochrome fallback font (egui feature monochrome_emoji_fonts) |
+| `epaint_default_fonts` 0.37.0 | `fonts/emoji-icon-font.ttf` | emoji-icon-font | John Slegers | MIT | https://github.com/jslegers/emoji-icon-font | egui monochrome fallback font (egui feature monochrome_emoji_fonts) |
+| `epaint_default_fonts` 0.37.0 | `fonts/egui-icons.ttf` | egui icons (monochrome emoji-icon-font subset) | John Slegers | MIT | https://github.com/jslegers/emoji-icon-font | Small special-icon subset embedded by egui default_fonts; retained in FontDefinitions::default(). Provenance: https://github.com/storytold/egui/blob/6d518fc799681571963842f95b55a6b68431b15a/crates/epaint_default_fonts/fonts/egui-icons.txt; complete MIT copyright and permission text in NOTICE. |
| `hayro-interpret` 0.7.0 | `src/font/generated/metrics.rs` | Standard-14 font metrics and encodings (as Rust tables) (non-visual data, AGENTS.md §1.1) | Adobe (Core 14 AFM metrics, PDF specification encodings); tables by The Hayro Authors | MIT OR Apache-2.0 | ISO 32000-2 Annex D; Adobe Core14 AFM files (via vendored hayro-interpret) | Glyph widths and encodings for non-embedded standard fonts. Non-visual data, allowed by AGENTS.md §1.1 |
## Downloaded at build time (22)
@@ -308,8 +334,8 @@ Fonts are fetched by `cargo xtask demo-pdf` into `target/demo-fonts/`, OCR model
| `NotoColorEmoji-Regular.ttf` | Noto Color Emoji | Google Inc. | OFL-1.1 | https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/notocoloremoji | Showcase PDF (cargo xtask demo-pdf) |
| `Inter[opsz,wght].ttf` | Inter (variable) | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter | Showcase PDF (cargo xtask demo-pdf) |
| `Inter-Italic[opsz,wght].ttf` | Inter Italic (variable) | The Inter Project Authors (Rasmus Andersson) | OFL-1.1 | https://github.com/google/fonts/tree/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/inter | Showcase PDF (cargo xtask demo-pdf) |
-| `text-detection.onnx` | Ocrs text detection model | Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0) | CC-BY-SA-4.0 | https://github.com/robertknight/ocrs-models (the models ocrs downloads; model card: https://huggingface.co/robertknight/ocrs, cc-by-sa-4.0) | Scan & OCR: finds words on page images (cargo xtask models) |
-| `text-recognition.onnx` | Ocrs text recognition model | Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0) | CC-BY-SA-4.0 | https://github.com/robertknight/ocrs-models (the models ocrs downloads; model card: https://huggingface.co/robertknight/ocrs, cc-by-sa-4.0) | Scan & OCR: reads the words it finds (cargo xtask models) |
+| `text-detection.onnx` | Ocrs text detection model | Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0) | CC-BY-SA-4.0 | https://github.com/robertknight/ocrs/blob/0c826441362a701c55560fefc17bf356b6d1037e/ocrs/examples/download-models.sh (author-published ONNX models; model card: https://huggingface.co/robertknight/ocrs/blob/df0edd170279ab971b53e094c627255a87e1a503/README.md, cc-by-sa-4.0) | Scan & OCR: finds words on page images (cargo xtask models) |
+| `text-recognition.onnx` | Ocrs text recognition model | Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0) | CC-BY-SA-4.0 | https://github.com/robertknight/ocrs/blob/0c826441362a701c55560fefc17bf356b6d1037e/ocrs/examples/download-models.sh (author-published ONNX models; model card: https://huggingface.co/robertknight/ocrs/blob/df0edd170279ab971b53e094c627255a87e1a503/README.md, cc-by-sa-4.0) | Scan & OCR: reads the words it finds (cargo xtask models) |
## Optional build inputs (1)
@@ -317,4 +343,4 @@ Not in this repository and never downloaded by it: compiled in only when the bui
| Input | Option | Title | Author | Licence | Source | Attribution | Used for |
|---|---|---|---|---|---|---|---|
-| `craft-fonts` | `CRAFT_FONTS_DIR` | Japanese fonts: BIZ UDPGothic (Regular, Bold), Shippori Mincho, BIZ UDMincho; Arabic font: Noto Sans Arabic | The BIZ UDGothic and BIZ UDMincho Project Authors (Morisawa Inc.), The Shippori Mincho Project Authors (FONTDASU), The Noto Project Authors (Noto Sans Arabic) | OFL-1.1 | https://github.com/storytold/craft-fonts (pinned by commit in .github/workflows/release.yml) | https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md | Japanese fallback in the interface (BIZ UDPGothic first) and Japanese glyphs in edited PDF text (Shippori Mincho); Arabic interface text, file names and document titles (Noto Sans Arabic); the web build embeds only BIZ UDPGothic Regular and Noto Sans Arabic. The checkout also holds Noto Sans CJK SC, which crates/fonts/build.rs never embeds (AGENTS.md §1.1) |
+| `craft-fonts` | `CRAFT_FONTS_DIR` | Japanese fonts: BIZ UDPGothic (Regular, Bold), Shippori Mincho, BIZ UDMincho; native Simplified Chinese font: LXGW WenKai Lite; Arabic font: Noto Sans Arabic | The BIZ UDGothic and BIZ UDMincho Project Authors (Morisawa Inc.), The Shippori Mincho Project Authors (FONTDASU), LXGW and the original Klee Project Authors / Fontworks (LXGW WenKai Lite), The Noto Project Authors (Noto Sans Arabic) | OFL-1.1 | https://github.com/storytold/craft-fonts (pinned by commit in .github/workflows/release.yml and .github/workflows/ci.yml); LXGW WenKai Lite from https://github.com/lxgw/LxgwWenKai-Lite/releases/tag/v1.530 (commit b712c83d98acf977bacfb7fb010207802808bda9) | https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md | Japanese fallback in the interface (BIZ UDPGothic first) and Japanese glyphs in edited PDF text (Shippori Mincho); Simplified Chinese interface fallback on native builds only (LXGW WenKai Lite Regular, font SHA-256 f799a538a3355877e597a0ae04050e897932c9ae7689eb9227c2953c5dd549ea, OFL SHA-256 0333a85fe077b6849f8e417acc44e8bd879442ceb681e271acf93e2d57fd4e2e, read from fonts/simplified-chinese-manifest.txt and never embedded on wasm); Arabic interface text, file names and document titles (Noto Sans Arabic); the web build embeds BIZ UDPGothic Regular and the pinned small Arabic, Hebrew, Thai and Devanagari faces; the selected craft-fonts revision contains no Telugu face. Other non-Japanese CJK faces retain the general 4 MiB cap; the reviewed native-only LXGW fallback has a separate 16 MiB cap. Open-source OFL releases are permitted under current AGENTS.md §1.1 |
diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml
index 2ed16dbe7b..a735efea83 100644
--- a/ATTRIBUTION.toml
+++ b/ATTRIBUTION.toml
@@ -1,7 +1,19 @@
+[[asset]]
+path = "crates/ui-egui/src/i18n/el.tsv"
+title = "Greek interface translation catalog"
+author = "Camthalion77 and contributors"
+source = "Contributor-original: clean-room translations of PdfCraft English UI labels; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Greek UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
# ATTRIBUTION.toml: one entry per asset (AGENTS.md §1). The source of truth for provenance and licences.
# ATTRIBUTION.md is generated from this file: `cargo xtask assets --write`. Checked by `cargo xtask assets` (part of `xtask ci`).
#
# [[asset]] a file in this repository (committed or vendored); `sha256` must match the file.
+# Translation catalogs (kind = "translation", crates/ui-egui/src/i18n/*.tsv) are project files
+# under the project licence and carry no `sha256`: git history records their provenance.
# [[bundled]] a file compiled into PdfCraft by a Cargo dependency (its crate version must match Cargo.lock).
# [[fetched]] downloaded at build time by xtask (never committed), pinned by `sha256`.
# [[build_input]] an optional build input outside this repository (e.g. craft-fonts via CRAFT_FONTS_DIR);
@@ -14,177 +26,270 @@
path = "crates/ui-egui/src/i18n/zh-hans.tsv"
title = "Simplified Chinese interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "68e8ca7bdb19a321f6f70843abfb1bc08c2f2ea353177e51f0d724d323111768"
+usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/zh-hant.tsv"
title = "Traditional Chinese (Taiwan) interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "8da3d11470b9c4304c18fc56dd7c9fc88a97fd06cf82253d65cf722422290f8f"
+usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/cs.tsv"
title = "Czech interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check and standard-identification wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "8df881d04ba4016693b920d08dd6d8dd9ff53cf1e90252b1d1d1ea0f1abccfee"
+usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/pt-br.tsv"
title = "Brazilian Portuguese interface translation catalog"
author = "André Cardoso (andrecards), PdfCraft contributors"
-source = "Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors"
+source = "Clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources: the ~1,826-entry gist posted in issue #288 (https://gist.github.com/andrecards/ac388c25fba17312ce83207f8b7b467e), completed and reviewed by PdfCraft contributors; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table limit messages are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "2f423a95c84a9be90b00ecc0d75952d7b2ca373b01469f8bf9363a6a577ce0ac"
+usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/es.tsv"
title = "Spanish interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; the 2026-10-20 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "52b51c06916e208a455b55a244e19e04e9462e6096baa2d6017d593ed6608c60"
+usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/fr.tsv"
title = "French interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "b2feef88102b920102075be873a741b8958890cd92701c61719eace1d310c04d"
+usage = "French UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/de.tsv"
title = "German interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "90992a1f62beecfb952c677c9f9b15edf4d4444f3fa5b53df096f4e053f74013"
+usage = "German UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/lo.tsv"
+title = "Lao interface translation catalog"
+author = "@bounkirdni-2025"
+source = "Contributor-original: clean-room translations of PdfCraft English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Lao UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/te.tsv"
title = "Telugu interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "3fdcd98f48029f1c56cae4515dc13cb8f65675f0d366e79e1b13471b0602fa65"
+usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/it.tsv"
title = "Italian interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "0a103ed5869ac5882acfd3ea8b19e58ebed7b6f7913859373be93ce757e8f04b"
+usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/pl.tsv"
title = "Polish interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "a19bdd068d817575006aed9b51879abca63fa0852227f4cedafa3b5c08ab5766"
+usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/ru.tsv"
title = "Russian interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "51de90f7bb066acc9500f4eff5c7f2277d2ed81bd0d314d058241b2080f00292"
+usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/hu.tsv"
title = "Hungarian interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "f8087a0cdb58f16efaff2ffadfe3d49c49d90eecfd0da98352df46dad7037891"
+usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/bg.tsv"
title = "Bulgarian interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/kk.tsv"
+title = "Kazakh interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of the English UI labels into Kazakh, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "c43faa6092a8ca97ff12b246420d2b849f0b3642b3f45bce17bae9d334aa1c8f"
+usage = "Kazakh UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/ja.tsv"
title = "Japanese interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "4ebc0823d4573e428cfb0fe819351e0fc3b487f06bc4deb5268bc1f385be028d"
+usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/uk.tsv"
title = "Ukrainian interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "b35c5e81fe2cd114142f16413d7a9be00dea8b1c67253fb7ba7f67f379d66253"
+usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "crates/ui-egui/src/i18n/ar.tsv"
title = "Arabic interface translation catalog"
author = "PdfCraft contributors"
-source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "translation"
-usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
-sha256 = "6d2bd38132f411d439eb9ae1f54c3e512c4a6a67c322b243fab316043e3ac8bf"
+usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/ckb.tsv"
+title = "Central Kurdish (Sorani) interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Central Kurdish UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/fa.tsv"
+title = "Persian (Farsi) interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-25 initial catalog covering the current 2,776-entry key union, AI-assisted translations from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Persian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/tr.tsv"
+title = "Turkish interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Turkish UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/lt.tsv"
+title = "Lithuanian interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; original catalog reviewed by a native Lithuanian-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/hi.tsv"
+title = "Hindi interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Hindi UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+[[asset]]
+path = "crates/ui-egui/src/i18n/id.tsv"
+title = "Indonesian interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Indonesian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+[[asset]]
+path = "crates/ui-egui/src/i18n/ko.tsv"
+title = "Korean interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Korean UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/ro.tsv"
+title = "Romanian interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels and user-facing messages; AI-assisted and not yet reviewed line by line by a native Romanian speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Romanian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/fi.tsv"
+title = "Finnish interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: AI-assisted (Claude Code) clean-room translations of PdfCraft's English UI labels and user-facing messages; not yet proofread by a native Finnish speaker; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 calculation-order, text-format, print, thumbnail, layer, comment-reshape and signature labels (previously English placeholders) are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Finnish UI strings, compiled in by crates/ui-egui/src/i18n.rs"
[[asset]]
path = "assets/icons/accessibility.svg"
@@ -2119,7 +2224,7 @@ source = "https://github.com/rsms/inter"
licence = "OFL-1.1"
licence_file = "assets/fonts/OFL-Inter.txt"
kind = "font"
-usage = "UI font, embedded in the app; demo PDF labels"
+usage = "UI font, embedded in the app; demo PDF labels; slanted fallback glyphs in Fill & Sign typed signatures for characters Dancing Script lacks (Cyrillic, Greek), drawn as filled paths"
sha256 = "40d692fce188e4471e2b3cba937be967878f631ad3ebbbdcd587687c7ebe0c82"
[[asset]]
@@ -2321,19 +2426,20 @@ usage = "Default CMYK colour conversion (vendored hayro-interpret)"
sha256 = "73e1ba37d2bad5bab2a964f40a9eed96209666efc067c3322626214bbef234a0"
[[asset]]
-path = "vendor/hayro-interpret/assets/LAB.icc"
-title = "Lab abstract ICC profile"
-author = "The Hayro Authors (generated with LittleCMS 2)"
-source = "https://github.com/LaurenzV/hayro (hayro-interpret 0.7.0 assets/)"
+path = "crates/fonts/src/std14_metrics.rs"
+title = "Standard-14 font advance widths and encodings (as Rust tables)"
+author = "Adobe (Core14 AFM metrics, PDF specification encodings); tables generated by the PdfCraft contributors"
+source = "ISO 32000-2 Annex D and the Adobe Core14 AFM metrics. Generated by joining the published WinAnsi, Symbol and ZapfDingbats encodings (code to glyph name) with the per-glyph advance widths, then spot-checked against the specification by hand in the tests of crates/fonts/src/std14.rs. Data only: the code that reads these tables lives in std14.rs, so that ordinary edits do not churn this file's hash."
licence = "MIT OR Apache-2.0"
-licence_file = "vendor/hayro-interpret/LICENSE-MIT"
+licence_file = "LICENSE-MIT"
kind = "data"
-usage = "Lab colour space conversion (vendored hayro-interpret)"
-sha256 = "a6efc5c30ece826eba2a83ddf5aa7026289b0c5ffa90acb129bc59ab8d7f5c59"
+adobe_data = true
+usage = "Advance widths for the fourteen standard fonts, which a PDF may name without embedding. Non-visual data, not a typeface: the item AGENTS.md 1.1 permits, held first-party so generated appearance streams and the renderer agree."
+sha256 = "f225e0b044875b8fa6375b6b5ad935f0d99fcc1ad03ecf9f0baae2cedbfca4d2"
[[bundled]]
crate = "epaint_default_fonts"
-version = "0.36.2"
+version = "0.37.0"
path = "fonts/Ubuntu-Light.ttf"
title = "Ubuntu Light"
author = "Canonical Ltd. / Dalton Maag"
@@ -2345,7 +2451,7 @@ sha256 = "80307b8da7649aa4ee4d484b232140e3ce1ec0ca093073d3c53c8f5a5ced7a70"
[[bundled]]
crate = "epaint_default_fonts"
-version = "0.36.2"
+version = "0.37.0"
path = "fonts/Hack-Regular.ttf"
title = "Hack Regular"
author = "Source Foundry Authors (derived from Bitstream Vera / DejaVu)"
@@ -2357,36 +2463,47 @@ sha256 = "15f55cc0c85a2988d2b4b3a8cdb5d77fdfbaf319e1bb5309d725db9818fb7125"
[[bundled]]
crate = "epaint_default_fonts"
-version = "0.36.2"
+version = "0.37.0"
path = "fonts/NotoEmoji-Regular.ttf"
title = "Noto Emoji (monochrome)"
author = "Google Inc."
source = "https://github.com/googlefonts/noto-emoji"
licence = "OFL-1.1"
kind = "font"
-usage = "egui fallback fonts (eframe feature default_fonts)"
+usage = "egui monochrome fallback font (egui feature monochrome_emoji_fonts)"
sha256 = "415dc6290378574135b64c808dc640c1df7531973290c4970c51fdeb849cb0c5"
[[bundled]]
crate = "epaint_default_fonts"
-version = "0.36.2"
+version = "0.37.0"
path = "fonts/emoji-icon-font.ttf"
title = "emoji-icon-font"
author = "John Slegers"
source = "https://github.com/jslegers/emoji-icon-font"
licence = "MIT"
kind = "font"
-usage = "egui fallback fonts (eframe feature default_fonts)"
+usage = "egui monochrome fallback font (egui feature monochrome_emoji_fonts)"
sha256 = "f426bec371f484646d002717e2c555a95cd5145e635d83a48bbef83f3abf18ca"
[[bundled]]
-crate = "hayro-cmap"
-version = "0.1.0"
-path = "assets/cmaps.brotli"
+crate = "epaint_default_fonts"
+version = "0.37.0"
+path = "fonts/egui-icons.ttf"
+title = "egui icons (monochrome emoji-icon-font subset)"
+author = "John Slegers"
+source = "https://github.com/jslegers/emoji-icon-font"
+licence = "MIT"
+kind = "font"
+usage = "Small special-icon subset embedded by egui default_fonts; retained in FontDefinitions::default(). Provenance: https://github.com/storytold/egui/blob/6d518fc799681571963842f95b55a6b68431b15a/crates/epaint_default_fonts/fonts/egui-icons.txt; complete MIT copyright and permission text in NOTICE."
+sha256 = "122806555c73df7cef55aa1d945289ae27fbc4dbbd31abbb4204ee0cda829cc8"
+
+[[asset]]
+path = "vendor/hayro-cmap/assets/cmaps.brotli"
title = "Adobe CMap resources (predefined CJK CMaps)"
author = "Adobe"
-source = "https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap)"
+source = "https://github.com/adobe-type-tools/cmap-resources (via hayro-cmap 0.1.0 assets/)"
licence = "BSD-3-Clause"
+licence_file = "vendor/hayro-cmap/assets/LICENSE.txt"
kind = "data"
adobe_data = true
usage = "Character-code mapping tables required to read CJK PDFs. Non-visual data, allowed by AGENTS.md §1.1"
@@ -2674,7 +2791,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Master artwork; every other app-icon file is rendered from it (packaging/icons.sh)"
-sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d"
+sha256 = "ba79fea56c0e4b76f063c86594d6f447275b507c722fd56583db591515385c06"
[[asset]]
path = "assets/app-icon/pdfcraft-small.svg"
@@ -2685,7 +2802,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "README header and assets/app-icon/README.md"
-sha256 = "b036304c11ef5dcad36636d06ca0bf331b51e47650d25d3c916a0e1eabf544c7"
+sha256 = "ba4c15c0e34e597083cf89769b08e0db6fee53994f512f227c1c154a4a6ecef9"
[[asset]]
path = "assets/app-icon/pdfcraft-1024.png"
@@ -2696,7 +2813,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs)"
-sha256 = "da577d3f21fbcf5c739067787a9e683be2b064d76813b5d5fec9074a7a106538"
+sha256 = "15fc405f45d1e5958da48630ae1230d797555fbc8d47ea728ce087b522183c62"
[[asset]]
path = "assets/app-icon/pdfcraft.icns"
@@ -2707,7 +2824,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "macOS app bundle icon"
-sha256 = "2425148222873de241d267aba667a8b234ecdd0149f2ca8bb6e79443b743b1e8"
+sha256 = "9aaf5f2cf012cd376867102579445f92a70a3a41ffa83ad285609962d7cba0d2"
[[asset]]
path = "assets/app-icon/pdfcraft.ico"
@@ -2718,7 +2835,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab)"
-sha256 = "56daaaae9ae5389794909570885809adf5e1d9183bef2d9669ed2f9bba3ed6f5"
+sha256 = "4038fbd7c4a1a8fb16a82dbe4a93fafd4342cedcc353850e03c186c574fa0785"
[[asset]]
path = "assets/app-icon/pdfcraft-document.svg"
@@ -2729,7 +2846,7 @@ licence = "ISC AND (MIT OR Apache-2.0)"
licence_file = "assets/app-icon/LICENSE-document.txt"
kind = "icon"
usage = "Master artwork for the Windows PDF file type icon; rendered by packaging/icons.sh, without fonts or external images"
-sha256 = "8da8278c2b89362be0a960879d453ff879d7544d6d58e47d5389574e8dfff77b"
+sha256 = "dc99b273428705256129319d526f474e107bcdd2325c923d43d9e7c6717a137f"
[[asset]]
path = "assets/app-icon/pdfcraft-document.ico"
@@ -2740,7 +2857,7 @@ licence = "ISC AND (MIT OR Apache-2.0)"
licence_file = "assets/app-icon/LICENSE-document.txt"
kind = "icon"
usage = "Embedded in pdfcraft.exe as resource 2; the Windows installer uses it for PdfCraft.Document and Applications/pdfcraft.exe PDF file associations"
-sha256 = "ba3f9128b368fc6d17d376cf62dbdbc22455451c5c8c4779210d7a2a7409b9e6"
+sha256 = "614a86c0cedbc663c15150c2e14ce1d4d5ee0b37952ebbbe5c8b8dbb1b6781a5"
[[asset]]
path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png"
@@ -2751,7 +2868,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "9b77095cbe75dcba6b74a1fdcd4064812850efaf7a12edebefc9ded5eabb49da"
+sha256 = "1b4b38909b2deac20bb37e86f9df35e843e3e56fdacb8d7663f37ef6aa47cf1d"
[[asset]]
path = "assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png"
@@ -2762,7 +2879,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "a4cd466687f6c5cb59eef3fc564bdba1c8f0d9e324754eeebab82f18823efae7"
+sha256 = "4ed2a977e7643769ec7c144fe5146d4656ef4461f915c62c6292ca6ae48552d8"
[[asset]]
path = "assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png"
@@ -2773,7 +2890,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "e22279013a5ed5c02571e1e4e9bc4cef9aa0847fcb733a285b2916fabd16bf78"
+sha256 = "cbcec71077b4541c2cb263a4d8baf6046fe81e9f29a8a36d3539d0bc3f264bb7"
[[asset]]
path = "assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png"
@@ -2784,7 +2901,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "55daf2d5575f6c4e4c4975c9f1c74231178f1801963a8b19f68dfa9bc50cb22f"
+sha256 = "a17bfe4958a5bfc25ca7d76c8f054ce1b1ff0c3088ece97537a87105ed5b3b4a"
[[asset]]
path = "assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png"
@@ -2795,7 +2912,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "2975c200f341e247b5fa18f568fb27d390e3fa01e9b2ad37acb48d0e1cc8a124"
+sha256 = "50b11c39ccdba334dfd4962eb77b403a48abfd30b6acbf9b58ce3ec2fb67e57e"
[[asset]]
path = "assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png"
@@ -2806,7 +2923,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "6ef927ca252b40bc9b5d8843d84137334362f8aa1acbb1bf8c15a02affd25b2b"
+sha256 = "980dff6bbd2312a3adb8f5e0bd466ba6ef734bd9401f68040bfb39bbcdd41e47"
[[asset]]
path = "assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png"
@@ -2817,7 +2934,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs)"
-sha256 = "cde7ee8c5ee38f9fc40a429fd9e6d99a035bcd321701fce331bb13bac126614d"
+sha256 = "cdc0db0b1cbba5353f2b0743bff4086b7d059ee3c8719a8618a8c42a3146af0e"
[[asset]]
path = "assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png"
@@ -2828,7 +2945,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "5ede733e93b96f4eb8d94299232cf2f9605fa19b0d913f95fe9828c316a2d066"
+sha256 = "5f227f3f36ec43d9b58aaf2b90af211ebfa734ce976ab4d93307fe597b39e116"
[[asset]]
path = "assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg"
@@ -2839,7 +2956,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
-sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d"
+sha256 = "ba79fea56c0e4b76f063c86594d6f447275b507c722fd56583db591515385c06"
[[asset]]
path = ".github/assets/banner-light.svg"
@@ -2916,139 +3033,7 @@ licence = "Apache-2.0"
licence_file = "LICENSE-APACHE"
kind = "image"
usage = "README badge row; committed static SVG, text names the font family only, no embedded fonts"
-sha256 = "4ad8c783ef128abc2398825c4248b840938e04f86503f83b4de4452673d0bd57"
-
-[[asset]]
-path = "docs/images/pdfcraft-bookmarks.png"
-title = "PdfCraft screenshot: Bookmarks"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "6daf2dceda8737da0c5f9e7895e5c4cc24cc845938ffca478713c2230573240d"
-
-[[asset]]
-path = "docs/images/pdfcraft-dark.png"
-title = "PdfCraft screenshot: Dark theme"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "18fbd4931b2a8d01a88aef0d5d0837e3cdc12aa35f8529bedbb4a930565d47e5"
-
-[[asset]]
-path = "docs/images/pdfcraft-find.png"
-title = "PdfCraft screenshot: Find text"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "b52771502be4c03e2dabf107c77d5183fad7f39655146d59761dda855c2d4b52"
-
-[[asset]]
-path = "docs/images/pdfcraft-forms.png"
-title = "PdfCraft screenshot: Interactive form"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "f8eb7705056d32e9c8e4d3b8b197c3e500faae08672e4622d6327d2799b536e7"
-
-[[asset]]
-path = "docs/images/pdfcraft-layers.png"
-title = "PdfCraft screenshot: Layers"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "20ff9e1c6ecc74d000a7514b82fe9e39f82c8ef5e7c1a52e9060c5ca349020d6"
-
-[[asset]]
-path = "docs/images/pdfcraft-organize.png"
-title = "PdfCraft screenshot: Organize pages"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "0a309ba73bcfccbe0106824b55fc347cc0b32293d1db68149d5eccec9c087ba1"
-
-[[asset]]
-path = "docs/images/pdfcraft-palette.png"
-title = "PdfCraft screenshot: Command palette"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "74867793e506c03255459e838eef0b08e485c13b7ea8a6b8de3ec16870067eda"
-
-[[asset]]
-path = "docs/images/pdfcraft-properties.png"
-title = "PdfCraft screenshot: Document properties"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "86f293543b299fa1665db999a68978138f8d61a4082d7c5b5025498e188da459"
-
-[[asset]]
-path = "docs/images/pdfcraft-scripts.png"
-title = "PdfCraft screenshot: Scripts of the world"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "0dde8ed5a14dee7396379963adff517bd249c7dd0fe494c389b612e643584b15"
-
-[[asset]]
-path = "docs/images/pdfcraft-split.png"
-title = "PdfCraft screenshot: Split dialog"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "bf31e13b563ead564af968c5fae8d1c07b91ee38867d0cf1aae9e0582efc2fe5"
-
-[[asset]]
-path = "docs/images/pdfcraft-twoup.png"
-title = "PdfCraft screenshot: Two-up reading"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "a72ed1b84c827e3aa1dd3282d857b4742f02d8ff23fc39b62115c840ebad14b4"
-
-[[asset]]
-path = "docs/images/pdfcraft-viewer.png"
-title = "PdfCraft screenshot: Viewer with comments"
-author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
-source = "this repository"
-licence = "MIT OR Apache-2.0"
-licence_file = "LICENSE-MIT"
-kind = "image"
-usage = "README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
-sha256 = "ecd261028d8837f7f7c013dd796d81ca7e89643bcfcbad3ab9fbfbe87ded04e3"
+sha256 = "d60e88a8c56df37dda916263fa5cea446da6d3f8ab886bcb877252c9e2555115"
[[asset]]
path = "assets/icons/pin.svg"
@@ -3135,7 +3120,7 @@ source = "Contributor-original: hand-written PDF objects, no third-party content
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "document"
-usage = "Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs)"
+usage = "Form-filling UI tests (crates/ui-egui/tests/it/forms.rs, commands.rs)"
sha256 = "c6f8b656e225101129aa36bd5467adc8dba16730915f19caca17f6a546d0b040"
[[asset]]
@@ -3168,7 +3153,7 @@ source = "Contributor-original: hand-written PDF objects; signature made with `o
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "document"
-usage = "Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make"
+usage = "Signature validation tests (crates/sign/tests/it/pdf.rs): a signature PdfCraft did not make"
sha256 = "8b91c3b4e39c4a31717a0dd0685bd7d0468671df32aee5b9818d44dc72c2bc3c"
[[asset]]
@@ -3202,7 +3187,7 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "image"
usage = "Finder window of the macOS DMG; rendered to background.tiff by packaging/macos/dmg/generate.py"
-sha256 = "f208091c702350d39096be33ab2ac1ed521ce7cbc93d44789911c5ddd7a5b799"
+sha256 = "769e2a49eb96283ae48d1109bdb0ee159b1b17b9f407f440e092c6818eaad904"
[[asset]]
@@ -3214,14 +3199,14 @@ licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "image"
usage = "1x + 2x HiDPI 16-colour palette TIFF copied into the macOS DMG by packaging/macos/package.sh; includes the app icon and the free LittleCMS built-in sRGB profile"
-sha256 = "e6ab168dad3e125196590375a41da1eb6638c74ebe68004508c44d72374eb916"
+sha256 = "5b8c3b1395805311d3c43fde2682e0a73dbb900d52faee60845f8655fab38b48"
[[fetched]]
file = "text-detection.onnx"
url = "https://ocrs-models.s3-accelerate.amazonaws.com/text-detection.onnx"
title = "Ocrs text detection model"
author = "Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0)"
-source = "https://github.com/robertknight/ocrs-models (the models ocrs downloads; model card: https://huggingface.co/robertknight/ocrs, cc-by-sa-4.0)"
+source = "https://github.com/robertknight/ocrs/blob/0c826441362a701c55560fefc17bf356b6d1037e/ocrs/examples/download-models.sh (author-published ONNX models; model card: https://huggingface.co/robertknight/ocrs/blob/df0edd170279ab971b53e094c627255a87e1a503/README.md, cc-by-sa-4.0)"
licence = "CC-BY-SA-4.0"
licence_url = "https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt"
licence_sha256 = "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5"
@@ -3234,7 +3219,7 @@ file = "text-recognition.onnx"
url = "https://ocrs-models.s3-accelerate.amazonaws.com/text-recognition.onnx"
title = "Ocrs text recognition model"
author = "Robert Knight (ocrs-models; trained on HierText, CC-BY-SA-4.0)"
-source = "https://github.com/robertknight/ocrs-models (the models ocrs downloads; model card: https://huggingface.co/robertknight/ocrs, cc-by-sa-4.0)"
+source = "https://github.com/robertknight/ocrs/blob/0c826441362a701c55560fefc17bf356b6d1037e/ocrs/examples/download-models.sh (author-published ONNX models; model card: https://huggingface.co/robertknight/ocrs/blob/df0edd170279ab971b53e094c627255a87e1a503/README.md, cc-by-sa-4.0)"
licence = "CC-BY-SA-4.0"
licence_url = "https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt"
licence_sha256 = "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5"
@@ -3245,13 +3230,13 @@ sha256 = "86c145c2edb96c8caed5b1ebb8f44d706408922211451c309c625157dd6061c5"
[[build_input]]
name = "craft-fonts"
option = "CRAFT_FONTS_DIR"
-title = "Japanese fonts: BIZ UDPGothic (Regular, Bold), Shippori Mincho, BIZ UDMincho; Arabic font: Noto Sans Arabic"
-author = "The BIZ UDGothic and BIZ UDMincho Project Authors (Morisawa Inc.), The Shippori Mincho Project Authors (FONTDASU), The Noto Project Authors (Noto Sans Arabic)"
-source = "https://github.com/storytold/craft-fonts (pinned by commit in .github/workflows/release.yml)"
+title = "Japanese fonts: BIZ UDPGothic (Regular, Bold), Shippori Mincho, BIZ UDMincho; native Simplified Chinese font: LXGW WenKai Lite; Arabic font: Noto Sans Arabic"
+author = "The BIZ UDGothic and BIZ UDMincho Project Authors (Morisawa Inc.), The Shippori Mincho Project Authors (FONTDASU), LXGW and the original Klee Project Authors / Fontworks (LXGW WenKai Lite), The Noto Project Authors (Noto Sans Arabic)"
+source = "https://github.com/storytold/craft-fonts (pinned by commit in .github/workflows/release.yml and .github/workflows/ci.yml); LXGW WenKai Lite from https://github.com/lxgw/LxgwWenKai-Lite/releases/tag/v1.530 (commit b712c83d98acf977bacfb7fb010207802808bda9)"
licence = "OFL-1.1"
attribution = "https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md"
kind = "font"
-usage = "Japanese fallback in the interface (BIZ UDPGothic first) and Japanese glyphs in edited PDF text (Shippori Mincho); Arabic interface text, file names and document titles (Noto Sans Arabic); the web build embeds only BIZ UDPGothic Regular and Noto Sans Arabic. The checkout also holds Noto Sans CJK SC, which crates/fonts/build.rs never embeds (AGENTS.md §1.1)"
+usage = "Japanese fallback in the interface (BIZ UDPGothic first) and Japanese glyphs in edited PDF text (Shippori Mincho); Simplified Chinese interface fallback on native builds only (LXGW WenKai Lite Regular, font SHA-256 f799a538a3355877e597a0ae04050e897932c9ae7689eb9227c2953c5dd549ea, OFL SHA-256 0333a85fe077b6849f8e417acc44e8bd879442ceb681e271acf93e2d57fd4e2e, read from fonts/simplified-chinese-manifest.txt and never embedded on wasm); Arabic interface text, file names and document titles (Noto Sans Arabic); the web build embeds BIZ UDPGothic Regular and the pinned small Arabic, Hebrew, Thai and Devanagari faces; the selected craft-fonts revision contains no Telugu face. Other non-Japanese CJK faces retain the general 4 MiB cap; the reviewed native-only LXGW fallback has a separate 16 MiB cap. Open-source OFL releases are permitted under current AGENTS.md §1.1"
[[asset]]
path = "crates/sign/tests/data/x509-rsa-sha1.pdf"
@@ -3261,5 +3246,275 @@ source = "Contributor-original: hand-written PDF objects; signature made with `o
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "document"
-usage = "Signature validation tests (crates/sign/tests/pdf.rs): the legacy adbe.x509.rsa_sha1 format"
+usage = "Signature validation tests (crates/sign/tests/it/pdf.rs): the legacy adbe.x509.rsa_sha1 format"
sha256 = "b77bfb21166f4bd043597e45a1ea28b9d9f4ba6df0142b3a0fc8b7f8e0fc111b"
+
+[[asset]]
+path = "assets/icons/monitor.svg"
+title = "Lucide icon \"monitor\""
+author = "Lucide Contributors (portions Cole Bemis, Feather)"
+source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/monitor.svg)"
+licence = "ISC"
+licence_file = "assets/icons/LICENSE-lucide.txt"
+kind = "icon"
+usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs"
+sha256 = "d1a443233345724859de8e4fb48968ba91e885e12ddbd710701548bd91b39428"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/vi.tsv"
+title = "Vietnamese interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels; PhotoCraft and VectorCraft Vietnamese catalogs used only as translation memory when English source and semantic context matched; original catalog reviewed by a native Vietnamese-speaking contributor; 2026-10-15 coverage additions are AI-assisted and not separately native-reviewed; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-check wordings are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/sl.tsv"
+title = "Slovene interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-18 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Slovene UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+
+path = "vendor/vello_common/assets/probe.png"
+title = "vello_common probe reference image (rendered from probe.rgba)"
+author = "Linebender vello contributors"
+source = "vello_common 0.0.8 (crates.io), vendored in vendor/vello_common; regenerated by its vello_sparse_tests regenerate_probe_reference binary"
+licence = "MIT OR Apache-2.0"
+licence_file = "vendor/vello_common/LICENSE-MIT"
+kind = "image"
+usage = "Reference picture of the vendored vello_common probe module, for people only; the build reads probe.rgba, not this file"
+sha256 = "78c59a0cfd2c829909d77006f94e34dac1ae5d1f90e7f10f72e84de541fef697"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/nb.tsv"
+title = "Norwegian Bokmål interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Norwegian Bokmål UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "assets/icons/superscript.svg"
+title = "Lucide icon \"superscript\""
+author = "Lucide Contributors (portions Cole Bemis, Feather)"
+source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/superscript.svg)"
+licence = "ISC"
+licence_file = "assets/icons/LICENSE-lucide.txt"
+kind = "icon"
+usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs"
+sha256 = "34af289365aaa19295f874e4fda3b56196e203785d6fe1d9c3c929ae290518a0"
+
+[[asset]]
+path = "assets/icons/subscript.svg"
+title = "Lucide icon \"subscript\""
+author = "Lucide Contributors (portions Cole Bemis, Feather)"
+source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/subscript.svg)"
+licence = "ISC"
+licence_file = "assets/icons/LICENSE-lucide.txt"
+kind = "icon"
+usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs"
+sha256 = "06462f57e87a14e6496da9216eee9906b83ded0ff99b70498efa37ae88a5cba4"
+
+[[asset]]
+path = "assets/icons/pilcrow.svg"
+title = "Lucide icon \"pilcrow\""
+author = "Lucide Contributors (portions Cole Bemis, Feather)"
+source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pilcrow.svg)"
+licence = "ISC"
+licence_file = "assets/icons/LICENSE-lucide.txt"
+kind = "icon"
+usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs"
+sha256 = "d344d9f9222f6c1b698c0c82a753a2212d9bd7785f06c00cd6e4910fe2fee8f8"
+
+[[asset]]
+path = "assets/icons/move-horizontal.svg"
+title = "Lucide icon \"move-horizontal\""
+author = "Lucide Contributors (portions Cole Bemis, Feather)"
+source = "https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-horizontal.svg)"
+licence = "ISC"
+licence_file = "assets/icons/LICENSE-lucide.txt"
+kind = "icon"
+usage = "UI icon, embedded via crates/ui-egui/src/icon_data.rs"
+sha256 = "864ab2f19254e6ac7240bc6a98323197332e8f714d4d3f94831f41309e5ef2f7"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/sq.tsv"
+title = "Albanian interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 signature-appearance labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Albanian UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/th.tsv"
+title = "Thai interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Thai UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "crates/ui-egui/src/i18n/ca.tsv"
+title = "Catalan interface translation catalog"
+author = "PdfCraft contributors"
+source = "Contributor-original: clean-room translations of PdfCraft's English UI labels, written from their meaning; no proprietary localisation resources; 2026-10-22 page-gap labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 text-field-table labels are contributor-original AI-assisted translations from English, not separately native-reviewed; 2026-10-22 secured-document notice labels are contributor-original AI-assisted translations from English, not separately native-reviewed; the 2026-10-22 reply-count label is an AI-assisted translation from English, not separately native-reviewed"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "translation"
+usage = "Catalan UI strings, compiled in by crates/ui-egui/src/i18n.rs"
+
+[[asset]]
+path = "docs/images/pdfcraft-bookmarks.png"
+title = "PdfCraft screenshot: Bookmarks"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "4bae80dfa57ab0edbef73de503a84f54b8ec2cd9ef5e0b358b93f99263045b14"
+
+[[asset]]
+path = "docs/images/pdfcraft-dark.png"
+title = "PdfCraft screenshot: Dark theme"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "014303098d27cd866010bd75976ddae147301eb5bd5c535a264f0f0a715e96e0"
+
+[[asset]]
+path = "docs/images/pdfcraft-find.png"
+title = "PdfCraft screenshot: Find text"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "8e5683fef9c6443f72cb7c11443786dd7979dbe294614d00322d8bede4c401e1"
+
+[[asset]]
+path = "docs/images/pdfcraft-forms.png"
+title = "PdfCraft screenshot: Interactive form"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "aec8c79bb95ac97bbd63bdd65c1b4b26046fb43897cae76af40540dead0afa0d"
+
+[[asset]]
+path = "docs/images/pdfcraft-layers.png"
+title = "PdfCraft screenshot: Layers"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "06c8558117f4fc437cb5a6ec0041f640331174e222e320697e4597219dd6405b"
+
+[[asset]]
+path = "docs/images/pdfcraft-organize.png"
+title = "PdfCraft screenshot: Organize pages"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "78e6efd83b8b4916cfcbf6e99a48b0288026c383b7c005a00feaf56e6c63880e"
+
+[[asset]]
+path = "docs/images/pdfcraft-palette.png"
+title = "PdfCraft screenshot: Command palette"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "4a56444416b7140f1ac696732d19760ecf7cefa74291a1513443dd0b2af9f189"
+
+[[asset]]
+path = "docs/images/pdfcraft-properties.png"
+title = "PdfCraft screenshot: Document properties"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "ef7466e501b0da941dbf21e4829bc4aa1f78551af2ffafea9fb3dab04039b33b"
+
+[[asset]]
+path = "docs/images/pdfcraft-scripts.png"
+title = "PdfCraft screenshot: Scripts of the world"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "24375f19e0cde9396ff4bda222d9252e8cfb1643be93de7e53b9ae5d5e15ac84"
+
+[[asset]]
+path = "docs/images/pdfcraft-split.png"
+title = "PdfCraft screenshot: Split dialog"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "831ae570c16ab6700573a6a6af0db03d66be0e7fd4fca2df6f4109772da6a934"
+
+[[asset]]
+path = "docs/images/pdfcraft-tools.png"
+title = "PdfCraft screenshot: All tools"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: tool catalogue. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "0d8604f1d80df90f0fc9613ec292af5b7bc9f96038beb9eb70cc220926f20903"
+
+[[asset]]
+path = "docs/images/pdfcraft-twoup.png"
+title = "PdfCraft screenshot: Two-up reading"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "6264fe79427a83b481325c621b820e1e023335e9f236f18c964f5a3969118721"
+
+[[asset]]
+path = "docs/images/pdfcraft-viewer.png"
+title = "PdfCraft screenshot: Viewer with comments"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
+source = "this repository"
+licence = "MIT OR Apache-2.0"
+licence_file = "LICENSE-MIT"
+kind = "image"
+usage = "README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+sha256 = "c7db562f8a6a78e6ba452e5c7ff45c505c52fa7fab769819904c5f712a652025"
diff --git a/CLAUDE.md b/CLAUDE.md
index 760c917345..cf90b9f2e0 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -21,6 +21,8 @@ PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Ado
- See `plan/README.md` §Clean-room and `plan/adr/0001`.
- **Privacy.** When observing Acrobat, use synthetic fixtures only. Never capture the Home view, recent files or account info. Capture by window id (`plan/acrobat/tools/`). Never commit Acrobat outputs, corpus files or personal data.
- **Layering.** Nothing below L7 depends on egui/winit/eframe/rfd (`plan/architecture.md` §3). `cos`/`filters`/`crypt`/`arlington` stay standalone.
+- **Page input.** Page modules read `PagePointer` (`crates/ui-egui/src/page_pointer.rs`), never egui's raw pointer state (`hover_pos`, `interact_pos`, `latest_pos`, `press_origin`, button reads); `page_pointer::tests::page_modules_read_the_pointer_only_through_page_pointer` enforces it.
+- **Page cursor.** Page modules claim the cursor for what is under the pointer (`view.cursor.claim(Layer::…, icon)`, `crates/ui-egui/src/canvas/page_cursor.rs`), never set it (`set_cursor_icon`, `cursor_icon =`, `on_hover_cursor`); `document_area` sets it once, from the claim on the highest layer the active tool reaches. `page_pointer::tests::page_modules_claim_the_cursor_and_never_set_it` enforces it.
- **Fidelity.** The PDF object graph is the model. Preserve unknown data. Saves are incremental unless a full rewrite is required. Never silently drop or repair data without recording it.
- **Never panic.** Every PDF, script, MCP call, settings file and keystroke is untrusted input, and none of it may crash the app or lose the user's work. This outranks feature work. Return `Result` (the crate's error enum) and propagate with `?`, or fall back leniently and record it. In non-test code:
- No `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` unless it is provably infallible, with a comment saying why.
@@ -31,8 +33,18 @@ PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Ado
- No `unsafe` (`unsafe_code = "forbid"`).
- Every crash fix gets a synthetic regression test. See `AGENTS.md` §4 (and, for team members, the internal `craftrules/standards/never-crash.md`).
- **Rust only** in the product and build (`xtask`). No handwritten JS/TS.
-- **Quality gates** before every commit: `cargo fmt --check`, `cargo clippy --workspace -- -D warnings`, `cargo test --workspace`, and the wasm check once `xtask ci` exists (M0).
-- **Commits:** one task id per commit (e.g. `M1.4: xref stream reader`). Commit only green states. End messages with the attribution line required by the environment.
+- **Time goes through `chrono`** (workspace dependency). Never hand-roll UTC/calendar conversion (days-to-date algorithms, leap-year math); a crate owns only its output format string. The one exception is range extension: past the years chrono can represent, shift the date by whole 400-year Gregorian cycles (146,097 days, after which the calendar repeats), let chrono compute the month and day, and add the cycles back to the year (splitting seconds into hours, minutes and seconds is plain arithmetic).
+- **Review every update as you make it, at four zooms.** Not an end-of-task pass — a per-update habit, so a defect never gets built on. **Clause:** checked arithmetic, `get()` not `[i]`, char-boundary slicing, the right error through `?`, `<` against `<=`, the 1-based/0-based seam, capped allocations. **Function:** is it total — name an input that panics; walk empty, zero, max, malformed, cyclic; is the return type honest. **File/module:** two sources of truth, dead or duplicated code, is the public surface still smallest and the doc comment still true. **Project:** layering, wasm, undo/redo, save fidelity, encryption and permissions, a matching `automation` tool or registry entry, and whether a `parity/` status or note just became untrue. Scale the zoom to the change, and fix what a level turns up before widening.
+ - Tests mirror the zooms: property → unit → crate integration → end-to-end.
+ - **Prove a test fails before the fix by actually reverting the fix.** A test nobody has seen fail is not evidence. This has caught two worthless tests in this repo: one confinement test passed with path resolution switched off entirely, because the tools failed on a nonexistent document id before reaching the path.
+ - **Rebasing is a review step, not a mechanical one.** Read every hunk you resolve, and the auto-merged hunks in the files you touched too — `main` moves fast enough that a file can change by hundreds of lines under a branch.
+- **External PRs are held to safety, security and completeness before style.** Provenance first (no Adobe-derived asset, no committed font, no copied GPL/AGPL code, behaviour from the spec and not from reading another implementation), then no new panic path or `unsafe`, then `--root` confinement on every path including ones reached by nested dispatch, opt-in-only MCP and control channel, no new outbound network, then a headless `automation` tool, tests at the right zoom and an honest `parity/` entry. Provenance is the part a contributor cannot be expected to know, and the only part that cannot be undone after merge.
+- **Quality gates** before every commit: `cargo fmt --check`, clippy with `-D warnings`, the tests, `cargo xtask layers`, `cargo xtask assets`, and the wasm check once `xtask ci` exists (M0).
+ - New workspace crates must include `[lints] workspace = true` in `Cargo.toml` to inherit `[workspace.lints]`. Production crate roots must declare the required crate-level lint attributes before modules or other crate items; crate-level `//!` documentation may precede them.
+ - **Scope builds and tests to the crates you touched** — `cargo clippy -p -j 2 --all-targets` and `cargo test -p -j 2`, under a `timeout`. A full `--workspace` build has locked up a development machine's CPU; it is CI's job and CI runs it on every PR. Run the workspace sweep locally only when you have a reason to and the machine is free.
+- **Check for existing work before starting a fix or feature.** Search the issues and PRs, open and closed, with `gh issue list -R storytold/pdfcraft --state all --search ""` and the same with `gh pr list` (try a few phrasings), and check whether a merged fix is already on `main` (`git merge-base --is-ancestor origin/main`). If one is, the report is likely from an older build: say so rather than fixing it again. If an open PR covers it, review or build on that PR instead of opening a competing one. If an issue exists, reference it in the PR (`Fixes #123`).
+- **Commits and PRs:** `main` is the only integration branch and is **never pushed to directly**. Branch from an up-to-date `main` as `/` (`feat/`, `fix/`, `docs/`, `chore/`, `refactor/`), one task id per commit (e.g. `M1.4: xref stream reader`), commit only green states, and open a PR into `main` using `.github/pull_request_template.md`. Merge only when CI is green.
+ - **`main` moves fast enough that PRs rot.** It took 396 commits in the three days to 2026-10-12, and most open PRs are conflicting at any given time. Rebase your own branch the same day `main` moves under it, and ask the author to rebase theirs — never rewrite a contributor's branch. Conflict risk tracks how *contested* the files are, not how large the change is: tooling, tests and docs are nearly free, while `crates/fonts`, `ui-egui` and the i18n catalogues are where several people collide at once.
## Running and looking at the app
- `cargo run -p pdfcraft -- ` opens the desktop app.
@@ -45,3 +57,8 @@ PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Ado
## Current bootstrap debt (tracked in STATUS.md)
- `pdfcraft-render` renders through the `hayro` crate directly and inspects documents through `lopdf`. Both get replaced by `cos` / `model` / the DisplayList device (M1–M2, ADR-0004).
+
+## CI workflows
+- Workflows in `.github/workflows/` call the shared workflows in [`storytold/craft-common-actions`](https://github.com/storytold/craft-common-actions) at `@main`, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here.
+- Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time.
+- Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it.
diff --git a/Cargo.lock b/Cargo.lock
index e625f36903..8ede03596b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 4
[[package]]
name = "accesskit"
-version = "0.24.1"
+version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3b7f7f85a7e5f68090000ed7622545829afd484d210358702ae4cb97dd0c320"
+checksum = "ad442f58ee04714aaa0ba0a2768c1ea1935b29507bb22ddece8cbbc76db02932"
dependencies = [
"enumn",
"serde",
@@ -15,57 +15,51 @@ dependencies = [
[[package]]
name = "accesskit_atspi_common"
-version = "0.18.1"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e8c61bee90b42a772d39d06a740207dc71a4e780004ace1db8d99fb1baaa954"
+checksum = "52c182f9c282ac9c5638d876d551d15e5f7d397ec263349a0c6a2b61595dd5e4"
dependencies = [
"accesskit",
- "accesskit_consumer 0.36.0",
+ "accesskit_consumer",
"atspi-common",
- "phf 0.13.1",
+ "phf 0.14.0",
"serde",
"zvariant",
]
[[package]]
name = "accesskit_consumer"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53cf47daed85312e763fbf85ceca136e0d7abc68e0a7e12abe11f48172bc3b10"
-dependencies = [
- "accesskit",
- "hashbrown 0.16.1",
-]
-
-[[package]]
-name = "accesskit_consumer"
-version = "0.36.0"
+version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25e0d7e25d06f4dc21d1774d67146e9e80d6789216cbd4d1e88185b0095dba60"
+checksum = "8a45e2bb300bea6d5f33a82c3e051c3ddc6f41c209750f68a0acbe991a284344"
dependencies = [
"accesskit",
- "hashbrown 0.16.1",
+ "hashbrown 0.17.1",
]
[[package]]
-name = "accesskit_consumer"
-version = "0.38.0"
+name = "accesskit_ios"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d10a236f96f87d70732e44520046785431ef01d5bcd6b041317bfadd2f88245"
+checksum = "28e539d64b27fd4c14de8f78ada8f7c944c092f52f7e49fb63316507a57f6937"
dependencies = [
"accesskit",
- "hashbrown 0.16.1",
+ "accesskit_consumer",
+ "hashbrown 0.17.1",
+ "objc2 0.5.2",
+ "objc2-foundation 0.2.2",
+ "objc2-ui-kit 0.2.2",
]
[[package]]
name = "accesskit_macos"
-version = "0.26.3"
+version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce02dc63b43f0c9296af9ac946312a2dc8814427d7a64d2d600971dac55b6076"
+checksum = "5701624bf6a11efb6d4c8e922bf44126ed96250e5faa9a7a0468c979635839a4"
dependencies = [
"accesskit",
- "accesskit_consumer 0.38.0",
- "hashbrown 0.16.1",
+ "accesskit_consumer",
+ "hashbrown 0.17.1",
"objc2 0.5.2",
"objc2-app-kit 0.2.2",
"objc2-foundation 0.2.2",
@@ -73,9 +67,9 @@ dependencies = [
[[package]]
name = "accesskit_unix"
-version = "0.21.1"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b016ca8db0ea0ea2ceff29a9d6240391492d960716aa471967c00e8cc8cb197c"
+checksum = "202f24df034a7476d07b7f74284de84f6d62aabd858dbe7ee9cad3b7ad6f8f9d"
dependencies = [
"accesskit",
"accesskit_atspi_common",
@@ -91,13 +85,13 @@ dependencies = [
[[package]]
name = "accesskit_windows"
-version = "0.32.1"
+version = "0.35.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eff7009f1a532e917d66970a1e80c965140c6cfbbabbdde3d64e5431e6c78e21"
+checksum = "ce63f35d6bdcf59f26b76b3379063f738e6412cef46999cc772d46aa3de35adb"
dependencies = [
"accesskit",
- "accesskit_consumer 0.35.0",
- "hashbrown 0.16.1",
+ "accesskit_consumer",
+ "hashbrown 0.17.1",
"static_assertions",
"windows",
"windows-core",
@@ -105,11 +99,12 @@ dependencies = [
[[package]]
name = "accesskit_winit"
-version = "0.32.2"
+version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fe9a94394896352cc4660ca2288bd4ef883d83238853c038b44070c8f134313"
+checksum = "ee96dd150375c05912d8a473f98c2fb155fb3234fac88292d396548a2460fa77"
dependencies = [
"accesskit",
+ "accesskit_ios",
"accesskit_macos",
"accesskit_unix",
"accesskit_windows",
@@ -131,7 +126,7 @@ checksum = "35f0f96ce78e38c3dc6d8948aa8163d06385be74000f3c7a95bf1eef35d3ea32"
dependencies = [
"cipher",
"cpubits",
- "cpufeatures",
+ "cpufeatures 0.3.1",
]
[[package]]
@@ -220,21 +215,22 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]]
name = "arboard"
-version = "3.6.1"
+version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf"
+checksum = "aeb9553e62312c8756a5979254fc6d7da8bbeb5986a1e17037fab932f7037917"
dependencies = [
"clipboard-win",
"image",
"log",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.2",
"parking_lot",
"percent-encoding",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
+ "wl-clipboard-rs",
"x11rb",
]
@@ -447,19 +443,20 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "aws-lc-rs"
-version = "1.18.1"
+version = "1.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e"
+checksum = "faac5829c2b74c28f830747e7818ccfb684261b5f48a1118b1e2a13d36dfab13"
dependencies = [
"aws-lc-sys",
+ "untrusted 0.7.1",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
-version = "0.45.0"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27"
+checksum = "f1622d8446a2d4b2ce0c7eefc73dd43a99779028d5ee5c2dd8073a658ba8a2bc"
dependencies = [
"cc",
"cmake",
@@ -494,33 +491,37 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "bit-set"
-version = "0.8.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d"
dependencies = [
- "bit-vec 0.8.0",
+ "bit-vec 0.9.1",
]
[[package]]
name = "bit-set"
-version = "0.10.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d"
+checksum = "56d87354e4229f54a44f7bf2435906a4656dba36026ab6eaca629a2c436a691c"
dependencies = [
- "bit-vec 0.9.1",
+ "bit-vec 0.10.1",
]
[[package]]
name = "bit-vec"
-version = "0.8.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
[[package]]
name = "bit-vec"
-version = "0.9.1"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
+checksum = "5727b15fa97d4f4fee0a3b7c3d550ed0269f54329207b86388de918604e31269"
+dependencies = [
+ "borsh",
+ "serde",
+]
[[package]]
name = "bitflags"
@@ -537,6 +538,15 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
[[package]]
name = "block-buffer"
version = "0.12.1"
@@ -570,7 +580,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
dependencies = [
- "objc2 0.6.4",
+ "objc2 0.6.5",
]
[[package]]
@@ -639,7 +649,7 @@ dependencies = [
"oneshot",
"pastey",
"portable-atomic",
- "rand 0.10.3",
+ "rand",
"regress",
"rustc-hash 2.1.3",
"ryu-js",
@@ -730,6 +740,30 @@ dependencies = [
"static_assertions",
]
+[[package]]
+name = "borsh"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a"
+dependencies = [
+ "borsh-derive",
+ "bytes",
+ "cfg_aliases",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56"
+dependencies = [
+ "once_cell",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 3.0.6",
+]
+
[[package]]
name = "bp256"
version = "0.14.0"
@@ -913,7 +947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.3.1",
"rand_core 0.10.1",
]
@@ -924,7 +958,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
+ "js-sys",
"num-traits",
+ "serde",
+ "wasm-bindgen",
"windows-link",
]
@@ -934,7 +971,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
- "crypto-common",
+ "crypto-common 0.2.2",
"inout",
]
@@ -962,6 +999,39 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
+[[package]]
+name = "cmpv2"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "961b955a666e25ee5a1091d219128d6e6401e3dab84efb1a2bf6b4035d797b39"
+dependencies = [
+ "crmf",
+ "der 0.7.10",
+ "spki 0.7.3",
+ "x509-cert",
+]
+
+[[package]]
+name = "cms"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730"
+dependencies = [
+ "const-oid 0.9.6",
+ "der 0.7.10",
+ "spki 0.7.3",
+ "x509-cert",
+]
+
+[[package]]
+name = "cobs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
+dependencies = [
+ "thiserror 2.0.21",
+]
+
[[package]]
name = "codespan-reporting"
version = "0.13.1"
@@ -1007,6 +1077,12 @@ dependencies = [
"crossbeam-utils",
]
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
[[package]]
name = "const-oid"
version = "0.10.2"
@@ -1081,6 +1157,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae"
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "cpufeatures"
version = "0.3.1"
@@ -1090,13 +1175,139 @@ dependencies = [
"libc",
]
+[[package]]
+name = "craft-docpath"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+
+[[package]]
+name = "craft-fonts-build"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+
+[[package]]
+name = "craft-i18n"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "fixed_decimal",
+ "icu_decimal",
+ "icu_locale_core",
+ "icu_locale_fallback",
+ "icu_normalizer",
+ "icu_plurals",
+ "icu_properties",
+ "icu_provider",
+ "icu_provider_adapters",
+ "icu_provider_blob",
+ "log",
+ "objc2-foundation 0.3.2",
+ "sys-locale",
+ "unicode-bidi",
+ "windows-registry",
+ "writeable",
+]
+
+[[package]]
+name = "craft-keymap"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "egui",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "craft-menu"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "craft-keymap",
+ "craft-quit",
+ "egui",
+ "muda",
+ "objc2 0.6.5",
+ "objc2-app-kit 0.3.2",
+]
+
+[[package]]
+name = "craft-print"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "craft-winprint-gdi",
+ "miniz_oxide 0.9.1",
+ "roxmltree 0.21.2",
+ "tempfile",
+ "winprint",
+ "winsafe",
+]
+
+[[package]]
+name = "craft-quit"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "dispatch2",
+ "egui",
+ "objc2 0.6.5",
+ "objc2-app-kit 0.3.2",
+]
+
[[package]]
name = "craft-ui"
version = "0.1.0"
-source = "git+https://github.com/storytold/craft-libs?rev=5c874d51eeb3de70e735c8ce87a59a7dedd47675#5c874d51eeb3de70e735c8ce87a59a7dedd47675"
+source = "git+https://github.com/storytold/craft-libs?rev=e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545#e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545"
+dependencies = [
+ "craft-fonts-build",
+ "craft-i18n",
+ "egui",
+ "epaint",
+ "js-sys",
+ "log",
+ "objc2 0.6.5",
+ "objc2-app-kit 0.3.2",
+ "objc2-foundation 0.3.2",
+ "serde",
+ "skrifa 0.44.0",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "craft-update"
+version = "0.1.0"
+source = "git+https://github.com/storytold/craft-libs?rev=04aa1703b32d299e54f78fcde4182f2b393a9116#04aa1703b32d299e54f78fcde4182f2b393a9116"
dependencies = [
+ "chrono",
+ "dunce",
"egui",
+ "flate2",
+ "getrandom 0.3.4",
+ "image",
+ "log",
+ "plist",
+ "semver",
"serde",
+ "serde_json",
+ "sha2 0.10.9",
+ "tar",
+ "tempfile",
+ "ureq",
+ "verifysign",
+ "winreg",
+ "winsafe",
+ "zip",
+]
+
+[[package]]
+name = "craft-winprint-gdi"
+version = "0.1.0"
+source = "git+https://github.com/storytold/winprint.rs?rev=417ac3c4d14d3da5485a99c7d5ce8f05664ec312#417ac3c4d14d3da5485a99c7d5ce8f05664ec312"
+dependencies = [
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1108,6 +1319,27 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "crmf"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36fe21b96d5b87f5de4b5b7202ec41c00110ac817ce6728fe75fb2fe5962ed92"
+dependencies = [
+ "cms",
+ "der 0.7.10",
+ "spki 0.7.3",
+ "x509-cert",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1"
+dependencies = [
+ "crossbeam-utils",
+]
+
[[package]]
name = "crossbeam-deque"
version = "0.8.8"
@@ -1156,6 +1388,16 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
[[package]]
name = "crypto-common"
version = "0.2.2"
@@ -1200,9 +1442,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.3.1",
"curve25519-dalek-derive",
- "digest",
+ "digest 0.11.3",
"fiat-crypto",
"rustc_version",
"subtle",
@@ -1240,17 +1482,41 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
+[[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid 0.9.6",
+ "der_derive",
+ "flagset",
+ "pem-rfc7468 0.7.0",
+ "zeroize",
+]
+
[[package]]
name = "der"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a"
dependencies = [
- "const-oid",
- "pem-rfc7468",
+ "const-oid 0.10.2",
+ "pem-rfc7468 1.0.0",
"zeroize",
]
+[[package]]
+name = "der_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
[[package]]
name = "deranged"
version = "0.5.8"
@@ -1266,15 +1532,25 @@ dependencies = [
"cipher",
]
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "crypto-common 0.1.7",
+]
+
[[package]]
name = "digest"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
- "block-buffer",
- "const-oid",
- "crypto-common",
+ "block-buffer 0.12.1",
+ "const-oid 0.10.2",
+ "crypto-common 0.2.2",
"ctutils",
]
@@ -1293,7 +1569,7 @@ dependencies = [
"bitflags 2.13.2",
"block2 0.6.2",
"libc",
- "objc2 0.6.4",
+ "objc2 0.6.5",
]
[[package]]
@@ -1378,20 +1654,19 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0"
dependencies = [
- "der",
- "digest",
+ "der 0.8.2",
+ "digest 0.11.3",
"elliptic-curve",
"rfc6979",
- "signature",
- "spki",
+ "signature 3.0.0",
+ "spki 0.8.0",
"zeroize",
]
[[package]]
name = "ecolor"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0656a7530b9e2841ee7a5f983965bdd9840c32f4012f759cfd44b912cced6b34"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"bytemuck",
"emath",
@@ -1404,7 +1679,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a"
dependencies = [
- "signature",
+ "signature 3.0.0",
]
[[package]]
@@ -1415,16 +1690,15 @@ checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de"
dependencies = [
"curve25519-dalek",
"ed25519",
- "sha2",
+ "sha2 0.11.1",
"subtle",
"zeroize",
]
[[package]]
name = "eframe"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55ad41fac6e3149abb4866e93df37dbd33baa95db525c3368c944584e95a5dc2"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"ahash",
"bytemuck",
@@ -1439,7 +1713,7 @@ dependencies = [
"image",
"js-sys",
"log",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
"parking_lot",
@@ -1448,6 +1722,7 @@ dependencies = [
"profiling",
"raw-window-handle",
"ron",
+ "send_wrapper",
"serde",
"static_assertions",
"wasm-bindgen",
@@ -1460,9 +1735,8 @@ dependencies = [
[[package]]
name = "egui"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc938cc27cd911415e1e4d151bc56ff9df063d8db081374e87aeb805ea74b2ba"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"accesskit",
"ahash",
@@ -1482,7 +1756,8 @@ dependencies = [
[[package]]
name = "egui-wgpu"
-version = "0.36.2"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"ahash",
"bytemuck",
@@ -1500,32 +1775,35 @@ dependencies = [
[[package]]
name = "egui-winit"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"accesskit_winit",
"arboard",
+ "block2 0.6.2",
"bytemuck",
"egui",
+ "image",
"log",
- "objc2 0.6.4",
+ "objc2 0.6.5",
+ "objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
"objc2-ui-kit 0.3.2",
+ "parking_lot",
"profiling",
"raw-window-handle",
"serde",
"smithay-clipboard",
"web-time",
"webbrowser",
+ "windows-sys 0.61.2",
"winit",
]
[[package]]
name = "egui_extras"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05cbdc785020861553f230f23d330ba1fb72613b9d8e0e457f3bdc8ba6db6dcf"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"ahash",
"egui",
@@ -1538,9 +1816,8 @@ dependencies = [
[[package]]
name = "egui_glow"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "606ed4167daf341e5753d703285c4c1d562324b2c07aa8f405cd7d066fe58f3b"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"bytemuck",
"egui",
@@ -1552,9 +1829,8 @@ dependencies = [
[[package]]
name = "egui_kittest"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eb3f3effb2726fee23449293e67acbf6cc6ce35525b1722bd5743bb348114d5"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"eframe",
"egui",
@@ -1582,8 +1858,8 @@ checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65"
dependencies = [
"base16ct",
"crypto-bigint",
- "crypto-common",
- "digest",
+ "crypto-common 0.2.2",
+ "digest 0.11.3",
"ff",
"group",
"hybrid-array",
@@ -1596,9 +1872,8 @@ dependencies = [
[[package]]
name = "emath"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52c8d4141cf0f60fb2f7aefaf352d3ffa5171ef0ab09731c64391801e95e48f1"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"bytemuck",
"serde",
@@ -1626,22 +1901,22 @@ checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enum-map"
-version = "2.7.3"
+version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
+checksum = "d4532960034c15ba2f55e9eee631040ecc473c32e6c4b200828c759840f13a06"
dependencies = [
"enum-map-derive",
]
[[package]]
name = "enum-map-derive"
-version = "0.17.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
+checksum = "7127272f64b3e098f7d81f350d672081b879bff896d219c42370dc858b1af9ff"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.119",
+ "syn 3.0.6",
]
[[package]]
@@ -1678,9 +1953,8 @@ dependencies = [
[[package]]
name = "epaint"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0ec0308dc23130fc1a7d4623a8534c2ed069c6dc84e258ee4f3de99615aa1a3"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
dependencies = [
"ahash",
"bytemuck",
@@ -1697,16 +1971,17 @@ dependencies = [
"serde",
"skrifa 0.44.0",
"smallvec",
+ "unicode-bidi",
"unicode-general-category",
+ "unicode-properties",
"unicode-segmentation",
- "vello_cpu 0.1.0",
+ "vello_cpu 0.2.0",
]
[[package]]
name = "epaint_default_fonts"
-version = "0.36.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773fa9c96dd0dbef887e39d0ed6177f141cce4d68e6041df77570aa3702dfa13"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
[[package]]
name = "equator"
@@ -1828,6 +2103,16 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
+[[package]]
+name = "filetime"
+version = "0.2.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759"
+dependencies = [
+ "cfg-if",
+ "libc",
+]
+
[[package]]
name = "find-msvc-tools"
version = "0.1.14"
@@ -1835,11 +2120,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
[[package]]
-name = "fixedbitset"
+name = "fixed_decimal"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2214fb00f669ee96bee5bb29dfb1ddabe058b2bc426817efc79afa03c9bc55ae"
+dependencies = [
+ "displaydoc",
+ "smallvec",
+ "writeable",
+]
+
+[[package]]
+name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+[[package]]
+name = "flagset"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
+
[[package]]
name = "flatbuffers"
version = "24.12.23"
@@ -1867,13 +2169,35 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+[[package]]
+name = "fmt-derive"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cb4a4b45c26455885f8b462db12978e51f60cc914337bccb9a36faf93410169"
+dependencies = [
+ "fmt-derive-proc",
+]
+
+[[package]]
+name = "fmt-derive-proc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7704da0760734344ce8753f15b21e97c6be85dc5a8f2c3a963fbd042b3380d23"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
[[package]]
name = "fmv-macos-events"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90642cf66dde7f205dc8b42dfe57b47d0f3a29f571b832742883ef512e23fe55"
dependencies = [
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
]
@@ -1884,6 +2208,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
[[package]]
name = "foldhash"
version = "0.2.0"
@@ -1909,6 +2239,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "fontconfig-parser"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
+dependencies = [
+ "roxmltree 0.20.0",
+]
+
[[package]]
name = "foreign-types"
version = "0.5.0"
@@ -1951,6 +2290,16 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+[[package]]
+name = "futures-channel"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
[[package]]
name = "futures-concurrency"
version = "7.7.1"
@@ -2000,6 +2349,12 @@ dependencies = [
"syn 3.0.6",
]
+[[package]]
+name = "futures-sink"
+version = "0.3.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
+
[[package]]
name = "futures-task"
version = "0.3.34"
@@ -2013,12 +2368,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [
"futures-core",
+ "futures-io",
"futures-macro",
+ "futures-sink",
"futures-task",
+ "memchr",
"pin-project-lite",
"slab",
]
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
[[package]]
name = "gethostname"
version = "1.1.0"
@@ -2036,8 +2404,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"wasi",
+ "wasm-bindgen",
]
[[package]]
@@ -2094,7 +2464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e"
dependencies = [
"bytemuck",
- "foldhash",
+ "foldhash 0.2.0",
"hashbrown 0.17.1",
"log",
"peniko",
@@ -2106,18 +2476,18 @@ dependencies = [
[[package]]
name = "glifo"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a"
+checksum = "282a26c1e23de04bdab3e34a21b6f877a479b96737792516b9b8b8f69b6661be"
dependencies = [
"bytemuck",
- "foldhash",
+ "foldhash 0.2.0",
"hashbrown 0.17.1",
"log",
"peniko",
"skrifa 0.44.0",
"smallvec",
- "vello_common 0.1.0",
+ "vello_common 0.2.0",
]
[[package]]
@@ -2146,7 +2516,7 @@ dependencies = [
"glutin_glx_sys",
"glutin_wgl_sys",
"libloading",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
@@ -2232,6 +2602,25 @@ dependencies = [
"euclid",
]
+[[package]]
+name = "h2"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
[[package]]
name = "half"
version = "2.7.1"
@@ -2262,6 +2651,15 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash 0.1.5",
+]
+
[[package]]
name = "hashbrown"
version = "0.16.1"
@@ -2270,7 +2668,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash",
+ "foldhash 0.2.0",
]
[[package]]
@@ -2281,7 +2679,7 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash",
+ "foldhash 0.2.0",
]
[[package]]
@@ -2318,8 +2716,6 @@ checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a"
[[package]]
name = "hayro-cmap"
version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d285dc30731c8485de5fa732fbdf2b3affdf01e4da7c2135022ca6fa664bf6"
dependencies = [
"brotli",
"hayro-postscript",
@@ -2362,8 +2758,6 @@ dependencies = [
[[package]]
name = "hayro-postscript"
version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa"
[[package]]
name = "hayro-syntax"
@@ -2376,6 +2770,7 @@ dependencies = [
"memchr",
"rustc-hash 2.1.3",
"smallvec",
+ "stringprep",
"zune-jpeg",
]
@@ -2403,7 +2798,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
dependencies = [
- "digest",
+ "digest 0.11.3",
]
[[package]]
@@ -2416,6 +2811,29 @@ dependencies = [
"itoa",
]
+[[package]]
+name = "http-body"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
[[package]]
name = "httparse"
version = "1.10.1"
@@ -2433,6 +2851,68 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "hyper"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff"
+dependencies = [
+ "base64 0.23.1",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "httparse",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "system-configuration",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "windows-registry",
+]
+
[[package]]
name = "iana-time-zone"
version = "0.1.65"
@@ -2471,6 +2951,23 @@ dependencies = [
"zerovec",
]
+[[package]]
+name = "icu_decimal"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9eb8f655bba2d0c0459e43a5b0e6cd3cd388109898fb3d85d048165e8b0abd08"
+dependencies = [
+ "displaydoc",
+ "fixed_decimal",
+ "icu_locale_core",
+ "icu_pattern",
+ "icu_plurals",
+ "icu_provider",
+ "serde",
+ "writeable",
+ "zerovec",
+]
+
[[package]]
name = "icu_locale_core"
version = "2.3.0"
@@ -2479,11 +2976,32 @@ checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb"
dependencies = [
"displaydoc",
"litemap",
+ "serde",
"tinystr",
"writeable",
"zerovec",
]
+[[package]]
+name = "icu_locale_fallback"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9"
+dependencies = [
+ "icu_locale_core",
+ "icu_locale_fallback_data",
+ "icu_provider",
+ "potential_utf",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_fallback_data"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8"
+
[[package]]
name = "icu_normalizer"
version = "2.3.0"
@@ -2496,6 +3014,7 @@ dependencies = [
"icu_provider",
"smallvec",
"utf16_iter",
+ "utf8_iter",
"write16",
"zerovec",
]
@@ -2506,6 +3025,32 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
+[[package]]
+name = "icu_pattern"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b3db611446bd92c246b03e4aa0bafa71ddb194af431ddbb42b9d70e4bfce1a0"
+dependencies = [
+ "displaydoc",
+ "either",
+ "serde",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_plurals"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e475e6766ef87b1d3c1f97be6363995b0bfaeddbc789671615df598a97ff0593"
+dependencies = [
+ "displaydoc",
+ "fixed_decimal",
+ "icu_provider",
+ "serde",
+ "zerovec",
+]
+
[[package]]
name = "icu_properties"
version = "2.3.0"
@@ -2535,6 +3080,9 @@ checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73"
dependencies = [
"displaydoc",
"icu_locale_core",
+ "postcard",
+ "serde",
+ "stable_deref_trait",
"writeable",
"yoke",
"zerofrom",
@@ -2542,6 +3090,30 @@ dependencies = [
"zerovec",
]
+[[package]]
+name = "icu_provider_adapters"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df887bc4f55dbc773c7c45a0c7dfa75be886f7b7812830a71ab7271cc1801820"
+dependencies = [
+ "icu_locale_fallback",
+ "icu_provider",
+]
+
+[[package]]
+name = "icu_provider_blob"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5916b44fac319d3f58e4d8d805a627df19e27937b582cd99fcde3bb6b7ce1b0e"
+dependencies = [
+ "icu_provider",
+ "postcard",
+ "serde",
+ "writeable",
+ "zerotrie",
+ "zerovec",
+]
+
[[package]]
name = "idna"
version = "1.1.0"
@@ -2613,6 +3185,12 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4275b20e6057cd7733fd8df8a5a31701e4fe44497dad0f3fa0e1c4fb971506be"
+[[package]]
+name = "ipnet"
+version = "2.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0"
+
[[package]]
name = "itertools"
version = "0.15.0"
@@ -2714,7 +3292,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.3.1",
+]
+
+[[package]]
+name = "keyboard-types"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d"
+dependencies = [
+ "bitflags 2.13.2",
+ "serde",
]
[[package]]
@@ -2736,12 +3324,12 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kittest"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ceaa75eb0036a32b6b9833962eb18137449e9817e2e586006471925b727fd5"
+checksum = "0bb81a721ba76aa095b7f45deb180504f786904e56ca4b8e141f66eb89a78b75"
dependencies = [
"accesskit",
- "accesskit_consumer 0.35.0",
+ "accesskit_consumer",
]
[[package]]
@@ -2824,6 +3412,9 @@ name = "litemap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
+dependencies = [
+ "serde_core",
+]
[[package]]
name = "litrs"
@@ -2864,15 +3455,21 @@ dependencies = [
"log",
"md-5",
"nom",
- "rand 0.10.3",
+ "rand",
"rangemap",
"rayon",
- "sha2",
+ "sha2 0.11.1",
"stringprep",
"thiserror 2.0.21",
"weezl 0.2.1",
]
+[[package]]
+name = "lru-slab"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f"
+
[[package]]
name = "mail-parser"
version = "0.11.9"
@@ -2890,7 +3487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98"
dependencies = [
"cfg-if",
- "digest",
+ "digest 0.11.3",
]
[[package]]
@@ -2917,6 +3514,12 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -2937,6 +3540,17 @@ dependencies = [
"simd-adler32",
]
+[[package]]
+name = "mio"
+version = "1.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "moxcms"
version = "0.8.1"
@@ -2948,16 +3562,34 @@ dependencies = [
]
[[package]]
-name = "multiversion_no_op"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d"
-
-[[package]]
-name = "naga"
-version = "30.0.1"
+name = "muda"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a616d2fb8c89516ac2723a581f69d6c18576046bed761bd6b305e5618e6ae130"
+checksum = "4340e89c178916e62879c5c36b7f699019369be413e496178a6983ce91b8bc03"
+dependencies = [
+ "crossbeam-channel",
+ "dpi",
+ "keyboard-types",
+ "objc2 0.6.5",
+ "objc2-app-kit 0.3.2",
+ "objc2-core-foundation",
+ "objc2-foundation 0.3.2",
+ "png 0.18.1",
+ "thiserror 2.0.21",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "multiversion_no_op"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d"
+
+[[package]]
+name = "naga"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a616d2fb8c89516ac2723a581f69d6c18576046bed761bd6b305e5618e6ae130"
dependencies = [
"arrayvec",
"bit-set 0.10.0",
@@ -3021,6 +3653,18 @@ dependencies = [
"jni-sys 0.3.1",
]
+[[package]]
+name = "nix"
+version = "0.31.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
+dependencies = [
+ "bitflags 2.13.2",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
[[package]]
name = "nohash-hasher"
version = "0.2.0"
@@ -3131,9 +3775,9 @@ dependencies = [
[[package]]
name = "objc2"
-version = "0.6.4"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8"
dependencies = [
"objc2-encode",
]
@@ -3162,7 +3806,7 @@ checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
dependencies = [
"bitflags 2.13.2",
"block2 0.6.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.2",
@@ -3212,7 +3856,7 @@ checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
"bitflags 2.13.2",
"dispatch2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
]
[[package]]
@@ -3223,7 +3867,7 @@ checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
dependencies = [
"bitflags 2.13.2",
"dispatch2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-io-surface",
]
@@ -3279,7 +3923,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
"bitflags 2.13.2",
"block2 0.6.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
]
@@ -3290,7 +3934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
dependencies = [
"bitflags 2.13.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
]
@@ -3326,7 +3970,7 @@ checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
dependencies = [
"bitflags 2.13.2",
"block2 0.6.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-foundation 0.3.2",
]
@@ -3350,7 +3994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
dependencies = [
"bitflags 2.13.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.2",
@@ -3395,7 +4039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
dependencies = [
"bitflags 2.13.2",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
]
@@ -3486,6 +4130,16 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "os_pipe"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "p256"
version = "0.14.0"
@@ -3496,7 +4150,7 @@ dependencies = [
"elliptic-curve",
"primefield",
"primeorder",
- "sha2",
+ "sha2 0.11.1",
]
[[package]]
@@ -3510,7 +4164,7 @@ dependencies = [
"fiat-crypto",
"primefield",
"primeorder",
- "sha2",
+ "sha2 0.11.1",
]
[[package]]
@@ -3524,7 +4178,7 @@ dependencies = [
"elliptic-curve",
"primefield",
"primeorder",
- "sha2",
+ "sha2 0.11.1",
]
[[package]]
@@ -3568,34 +4222,41 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629"
dependencies = [
- "digest",
+ "digest 0.11.3",
"hmac",
]
[[package]]
name = "pdfcraft"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "chrono",
+ "craft-update",
"eframe",
"egui",
"fmv-macos-events",
"log",
+ "pdfcraft-engine",
"pdfcraft-ui-egui",
"pollster 1.0.1",
- "rustls-native-certs",
+ "raw-window-handle",
"serde_json",
"uds_windows",
- "ureq",
+ "wayland-client",
+ "wayland-protocols",
+ "windows",
+ "winit",
"winresource",
"winsafe",
]
[[package]]
name = "pdfcraft-a11y"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-content",
"pdfcraft-cos",
+ "pdfcraft-filters",
"pdfcraft-fonts",
"pdfcraft-model",
"thiserror 2.0.21",
@@ -3603,7 +4264,7 @@ dependencies = [
[[package]]
name = "pdfcraft-annot"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-cos",
@@ -3612,32 +4273,52 @@ dependencies = [
"thiserror 2.0.21",
]
+[[package]]
+name = "pdfcraft-audit"
+version = "0.15.0"
+dependencies = [
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-edit",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
[[package]]
name = "pdfcraft-automation"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
- "base64 0.22.1",
+ "base64 0.23.1",
+ "flate2",
"image",
"pdfcraft-cos",
"pdfcraft-engine",
+ "pdfcraft-fonts",
"pdfcraft-model",
"pdfcraft-organize",
"pdfcraft-platform",
"pdfcraft-render",
"pdfcraft-xfa",
"png 0.18.1",
+ "rustix 1.1.5",
"serde_json",
+ "sha2 0.11.1",
+ "tempfile",
]
[[package]]
name = "pdfcraft-cli"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
- "base64 0.22.1",
+ "base64 0.23.1",
+ "pdfcraft-audit",
"pdfcraft-automation",
"pdfcraft-cos",
"pdfcraft-engine",
+ "pdfcraft-platform",
+ "pdfcraft-preflight",
"pdfcraft-render",
+ "png 0.18.1",
"rustix 1.1.5",
"serde_json",
"winresource",
@@ -3645,22 +4326,26 @@ dependencies = [
[[package]]
name = "pdfcraft-compare"
-version = "0.6.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-content"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "hayro-syntax",
"pdfcraft-cos",
]
[[package]]
name = "pdfcraft-cos"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "chrono",
"hayro-syntax",
"pdfcraft-crypt",
"pdfcraft-filters",
+ "pdfcraft-oracle",
+ "pdfcraft-testkit",
"proptest",
"serde_json",
"thiserror 2.0.21",
@@ -3668,7 +4353,7 @@ dependencies = [
[[package]]
name = "pdfcraft-create"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"encoding_rs",
"hayro-syntax",
@@ -3677,29 +4362,32 @@ dependencies = [
"pdfcraft-cos",
"pdfcraft-fonts",
"pdfcraft-model",
+ "pdfcraft-xfa",
"png 0.18.1",
"pulldown-cmark",
"thiserror 2.0.21",
"tiff",
+ "zune-jpeg",
]
[[package]]
name = "pdfcraft-crypt"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"aes",
"md-5",
"proptest",
- "sha2",
+ "sha2 0.11.1",
"stringprep",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-edit"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
+ "kurbo 0.13.1",
"pdfcraft-annot",
"pdfcraft-content",
"pdfcraft-cos",
@@ -3711,14 +4399,16 @@ dependencies = [
[[package]]
name = "pdfcraft-engine"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"chrono",
+ "craft-docpath",
"icu_properties",
"idna",
"image",
"pdfcraft-a11y",
"pdfcraft-annot",
+ "pdfcraft-audit",
"pdfcraft-compare",
"pdfcraft-cos",
"pdfcraft-create",
@@ -3727,6 +4417,7 @@ dependencies = [
"pdfcraft-external",
"pdfcraft-fonts",
"pdfcraft-forms",
+ "pdfcraft-geom",
"pdfcraft-js",
"pdfcraft-measure",
"pdfcraft-model",
@@ -3738,23 +4429,26 @@ dependencies = [
"pdfcraft-redact",
"pdfcraft-render",
"pdfcraft-sign",
+ "pdfcraft-testkit",
"pdfcraft-xfa",
"pdfcraft-xfdf",
"png 0.18.1",
"thiserror 2.0.21",
+ "tiff",
+ "unicode-segmentation",
"url",
]
[[package]]
name = "pdfcraft-export"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"flate2",
]
[[package]]
name = "pdfcraft-external"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"rustix 1.1.5",
"tempfile",
@@ -3764,7 +4458,7 @@ dependencies = [
[[package]]
name = "pdfcraft-filters"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"flate2",
"proptest",
@@ -3774,116 +4468,136 @@ dependencies = [
[[package]]
name = "pdfcraft-fonts"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"harfrust",
"pdfcraft-cos",
"skrifa 0.44.0",
+ "unicode-bidi",
]
[[package]]
name = "pdfcraft-forms"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-content",
"pdfcraft-cos",
"pdfcraft-fonts",
"pdfcraft-model",
+ "proptest",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-geom"
-version = "0.6.0"
+version = "0.15.0"
[[package]]
name = "pdfcraft-js"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"boa_engine",
+ "chrono",
]
[[package]]
name = "pdfcraft-measure"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-content",
"pdfcraft-cos",
"pdfcraft-model",
+ "pdfcraft-testkit",
"serde",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-model"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-cos",
]
[[package]]
name = "pdfcraft-ocr"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"ocrs",
"pdfcraft-fonts",
"rten",
+ "tempfile",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-optimize"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"image",
"pdfcraft-annot",
"pdfcraft-content",
"pdfcraft-cos",
+ "pdfcraft-filters",
"pdfcraft-model",
"pdfcraft-render",
"thiserror 2.0.21",
+ "zune-jpeg",
]
+[[package]]
+name = "pdfcraft-oracle"
+version = "0.15.0"
+
[[package]]
name = "pdfcraft-organize"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"hayro-syntax",
"pdfcraft-content",
"pdfcraft-cos",
+ "pdfcraft-oracle",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-platform"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "async-channel",
+ "futures-lite",
+ "rustix 1.1.5",
"zbus",
]
[[package]]
name = "pdfcraft-preflight"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "flate2",
+ "pdfcraft-content",
"pdfcraft-cos",
"pdfcraft-model",
+ "roxmltree 0.21.2",
]
[[package]]
name = "pdfcraft-print"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
+ "craft-print",
"pdfcraft-content",
"pdfcraft-cos",
"pdfcraft-model",
+ "pdfcraft-render",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-redact"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-content",
@@ -3892,12 +4606,14 @@ dependencies = [
"pdfcraft-fonts",
"pdfcraft-forms",
"pdfcraft-model",
+ "pdfcraft-testkit",
+ "pdfcraft-xfa",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-render"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"bytemuck",
"flate2",
@@ -3909,20 +4625,22 @@ dependencies = [
"lopdf",
"pdfcraft-cos",
"pdfcraft-fonts",
+ "serde",
"skrifa 0.44.0",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-sign"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"aes",
"aws-lc-rs",
- "base64 0.22.1",
+ "base64 0.23.1",
"bp256",
"bp384",
"cbc",
+ "chrono",
"crypto-bigint",
"des",
"ecdsa",
@@ -3936,34 +4654,46 @@ dependencies = [
"pdfcraft-annot",
"pdfcraft-cos",
"pdfcraft-fonts",
+ "pdfcraft-model",
"rc2",
"ripemd",
"rsa",
"rustls-cng",
"security-framework",
- "sha1",
- "sha2",
+ "sha1 0.11.0",
+ "sha2 0.11.1",
"sha3",
"thiserror 2.0.21",
]
+[[package]]
+name = "pdfcraft-testkit"
+version = "0.15.0"
+
[[package]]
name = "pdfcraft-ui-egui"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"arboard",
- "base64 0.22.1",
+ "base64 0.23.1",
+ "block2 0.6.2",
"bytemuck",
+ "chrono",
+ "craft-keymap",
+ "craft-menu",
+ "craft-quit",
"craft-ui",
+ "craft-update",
"eframe",
"egui",
"egui_extras",
"egui_kittest",
+ "fontconfig-parser",
"getrandom 0.4.3",
"image",
"js-sys",
"log",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
"pdfcraft-cos",
@@ -3973,9 +4703,11 @@ dependencies = [
"pdfcraft-platform",
"pdfcraft-render",
"pdfcraft-xfa",
+ "plist",
"png 0.18.1",
"pollster 1.0.1",
"rfd",
+ "rustix 1.1.5",
"serde",
"serde_json",
"skrifa 0.44.0",
@@ -3985,11 +4717,14 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
+ "web-time",
+ "winsafe",
+ "xattr",
]
[[package]]
name = "pdfcraft-web"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"eframe",
"egui",
@@ -4001,30 +4736,49 @@ dependencies = [
[[package]]
name = "pdfcraft-xfa"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
- "base64 0.22.1",
+ "base64 0.23.1",
"image",
"pdfcraft-cos",
"pdfcraft-fonts",
"png 0.18.1",
- "roxmltree",
- "sha2",
+ "roxmltree 0.21.2",
+ "sha2 0.11.1",
"thiserror 2.0.21",
]
[[package]]
name = "pdfcraft-xfdf"
-version = "0.6.0"
+version = "0.15.0"
dependencies = [
"pdfcraft-annot",
"pdfcraft-cos",
"pdfcraft-forms",
"pdfcraft-model",
- "roxmltree",
+ "roxmltree 0.21.2",
"thiserror 2.0.21",
]
+[[package]]
+name = "pem"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
+dependencies = [
+ "base64 0.22.1",
+ "serde_core",
+]
+
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
+]
+
[[package]]
name = "pem-rfc7468"
version = "1.0.0"
@@ -4053,6 +4807,17 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+[[package]]
+name = "petgraph"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
+dependencies = [
+ "fixedbitset",
+ "hashbrown 0.15.5",
+ "indexmap",
+]
+
[[package]]
name = "phf"
version = "0.13.1"
@@ -4061,7 +4826,6 @@ checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
dependencies = [
"phf_macros 0.13.1",
"phf_shared 0.13.1",
- "serde",
]
[[package]]
@@ -4072,6 +4836,7 @@ checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
dependencies = [
"phf_macros 0.14.0",
"phf_shared 0.14.0",
+ "serde",
]
[[package]]
@@ -4197,8 +4962,8 @@ version = "0.8.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e"
dependencies = [
- "der",
- "spki",
+ "der 0.8.2",
+ "spki 0.8.0",
]
[[package]]
@@ -4207,8 +4972,8 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7"
dependencies = [
- "der",
- "spki",
+ "der 0.8.2",
+ "spki 0.8.0",
]
[[package]]
@@ -4223,6 +4988,19 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+[[package]]
+name = "plist"
+version = "1.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327a4cb2ad49dc48adfdc9da89e22c64d488b508c67a044d71ba729e4521a285"
+dependencies = [
+ "base64 0.23.1",
+ "indexmap",
+ "quick-xml 0.42.0",
+ "serde",
+ "time",
+]
+
[[package]]
name = "png"
version = "0.17.16"
@@ -4299,12 +5077,24 @@ dependencies = [
"portable-atomic",
]
+[[package]]
+name = "postcard"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
+dependencies = [
+ "cobs",
+ "serde",
+]
+
[[package]]
name = "potential_utf"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"
dependencies = [
+ "serde_core",
+ "writeable",
"zerovec",
]
@@ -4314,15 +5104,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-[[package]]
-name = "ppv-lite86"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
-dependencies = [
- "zerocopy",
-]
-
[[package]]
name = "presser"
version = "0.3.1"
@@ -4336,7 +5117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4"
dependencies = [
"crypto-bigint",
- "crypto-common",
+ "crypto-common 0.2.2",
"ff",
"rand_core 0.10.1",
"subtle",
@@ -4365,6 +5146,30 @@ dependencies = [
"toml_edit",
]
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.107"
@@ -4382,16 +5187,17 @@ checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
[[package]]
name = "proptest"
-version = "1.11.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
+checksum = "b8530004ccb15eae51c7e40009fbe317f341f804db54dc033eec1c50be28cfa0"
dependencies = [
- "bit-set 0.8.0",
- "bit-vec 0.8.0",
+ "bit-set 0.11.1",
+ "bit-vec 0.10.1",
"bitflags 2.13.2",
+ "chacha20",
+ "core_detect",
"num-traits",
- "rand 0.9.5",
- "rand_chacha",
+ "rand",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
@@ -4401,9 +5207,9 @@ dependencies = [
[[package]]
name = "pulldown-cmark"
-version = "0.13.5"
+version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb"
+checksum = "3db2be46835f013dd3f4fa7f5f7402c537787b54ebb6fe2b94bbdd7e2669bb7b"
dependencies = [
"bitflags 2.13.2",
"memchr",
@@ -4438,12 +5244,78 @@ dependencies = [
]
[[package]]
-name = "quote"
-version = "1.0.47"
+name = "quick-xml"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b"
dependencies = [
- "proc-macro2",
+ "memchr",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash 2.1.3",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.21",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe"
+dependencies = [
+ "aws-lc-rs",
+ "bytes",
+ "getrandom 0.4.3",
+ "lru-slab",
+ "rand",
+ "rand_pcg",
+ "ring",
+ "rustc-hash 2.1.3",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.21",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
]
[[package]]
@@ -4458,16 +5330,6 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
-[[package]]
-name = "rand"
-version = "0.9.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
-dependencies = [
- "rand_chacha",
- "rand_core 0.9.5",
-]
-
[[package]]
name = "rand"
version = "0.10.3"
@@ -4479,24 +5341,11 @@ dependencies = [
"rand_core 0.10.1",
]
-[[package]]
-name = "rand_chacha"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.9.5",
-]
-
[[package]]
name = "rand_core"
-version = "0.9.5"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
-dependencies = [
- "getrandom 0.3.4",
-]
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
@@ -4504,13 +5353,22 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+[[package]]
+name = "rand_pcg"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
+dependencies = [
+ "rand_core 0.10.1",
+]
+
[[package]]
name = "rand_xorshift"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
+checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf"
dependencies = [
- "rand_core 0.9.5",
+ "rand_core 0.10.1",
]
[[package]]
@@ -4537,7 +5395,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135"
dependencies = [
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
"objc2-quartz-core 0.3.2",
@@ -4652,6 +5510,49 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
+[[package]]
+name = "reqwest"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029"
+dependencies = [
+ "base64 0.23.1",
+ "bytes",
+ "encoding_rs",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
[[package]]
name = "resvg"
version = "0.45.1"
@@ -4687,7 +5588,7 @@ dependencies = [
"js-sys",
"libc",
"log",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-core-foundation",
"objc2-foundation 0.3.2",
@@ -4722,7 +5623,7 @@ dependencies = [
"cfg-if",
"getrandom 0.2.17",
"libc",
- "untrusted",
+ "untrusted 0.9.0",
"windows-sys 0.52.0",
]
@@ -4732,7 +5633,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd4211456b4172d7e44261920c25acf07367c4f04bb5f5d54fc21b090d9b159"
dependencies = [
- "digest",
+ "digest 0.11.3",
]
[[package]]
@@ -4755,20 +5656,29 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+[[package]]
+name = "roxmltree"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9da7f59328b09405b181fee1018925fad50f157afb43c0c0f5c522c256dd5907"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "rsa"
version = "0.10.0-rc.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf"
dependencies = [
- "const-oid",
+ "const-oid 0.10.2",
"crypto-bigint",
"crypto-primes",
- "digest",
+ "digest 0.11.3",
"pkcs1",
"pkcs8",
"rand_core 0.10.1",
- "signature",
+ "signature 3.0.0",
"zeroize",
]
@@ -4942,6 +5852,7 @@ version = "0.23.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf"
dependencies = [
+ "aws-lc-rs",
"log",
"once_cell",
"ring",
@@ -4964,9 +5875,9 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+checksum = "4a073f5dc7469f984c52ad2752b63b0807745133b6de880b7b64c1ac4c48aec4"
dependencies = [
"openssl-probe",
"rustls-pki-types",
@@ -4980,18 +5891,47 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
dependencies = [
+ "web-time",
"zeroize",
]
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98"
+dependencies = [
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f"
+
[[package]]
name = "rustls-webpki"
version = "0.103.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281"
dependencies = [
+ "aws-lc-rs",
"ring",
"rustls-pki-types",
- "untrusted",
+ "untrusted 0.9.0",
]
[[package]]
@@ -5012,6 +5952,12 @@ dependencies = [
"wait-timeout",
]
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
[[package]]
name = "ryu-js"
version = "1.0.3"
@@ -5056,7 +6002,7 @@ checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d"
dependencies = [
"base16ct",
"ctutils",
- "der",
+ "der 0.8.2",
"hybrid-array",
"subtle",
"zeroize",
@@ -5096,6 +6042,16 @@ name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "send_wrapper"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]]
name = "serde"
@@ -5129,9 +6085,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.151"
+version = "1.0.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
+checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
dependencies = [
"itoa",
"memchr",
@@ -5140,6 +6096,17 @@ dependencies = [
"zmij",
]
+[[package]]
+name = "serde_json_canonicalizer"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe52319a927259afbfa5180c5157cd8167edfd3e8c254f9558c7fef44c5649f2"
+dependencies = [
+ "ryu-js",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "serde_repr"
version = "0.1.21"
@@ -5160,6 +6127,18 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
[[package]]
name = "serdect"
version = "0.4.3"
@@ -5170,6 +6149,17 @@ dependencies = [
"serde",
]
+[[package]]
+name = "sha1"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
[[package]]
name = "sha1"
version = "0.11.0"
@@ -5177,19 +6167,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214"
dependencies = [
"cfg-if",
- "cpufeatures",
- "digest",
+ "cpufeatures 0.3.1",
+ "digest 0.11.3",
]
[[package]]
name = "sha2"
-version = "0.11.0"
+version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
- "cpufeatures",
- "digest",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha2"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.1",
+ "digest 0.11.3",
]
[[package]]
@@ -5198,7 +6199,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759"
dependencies = [
- "digest",
+ "digest 0.11.3",
"keccak",
"sponge-cursor",
]
@@ -5219,16 +6220,185 @@ dependencies = [
"libc",
]
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
[[package]]
name = "signature"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5"
dependencies = [
- "digest",
+ "digest 0.11.3",
"rand_core 0.10.1",
]
+[[package]]
+name = "sigstore-bundle"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7dc53c8a941858d01479622dbb7650aaa2ee0ca1fb58fb6cdddbfc3064abbb"
+dependencies = [
+ "base64 0.22.1",
+ "hex",
+ "serde",
+ "serde_json",
+ "sigstore-crypto",
+ "sigstore-merkle",
+ "sigstore-rekor",
+ "sigstore-tsa",
+ "sigstore-types",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "sigstore-crypto"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da90c3d9af638898a5fdc347479b18f950bb0dde11ecf2244f94cd28135da53b"
+dependencies = [
+ "aws-lc-rs",
+ "base64 0.22.1",
+ "const-oid 0.9.6",
+ "der 0.7.10",
+ "digest 0.10.7",
+ "pem",
+ "rand_core 0.10.1",
+ "sha2 0.10.9",
+ "signature 2.2.0",
+ "sigstore-types",
+ "spki 0.7.3",
+ "thiserror 2.0.21",
+ "tracing",
+ "x509-cert",
+]
+
+[[package]]
+name = "sigstore-merkle"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c0d53558825c77716855c13794306fff766854c1bf92948e77d7890da3f2455"
+dependencies = [
+ "base64 0.22.1",
+ "hex",
+ "sigstore-crypto",
+ "sigstore-types",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "sigstore-rekor"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "641fdaaa40d0cd6e249cf1671c2240beff1a3ece578062cf43e750779e8db2b3"
+dependencies = [
+ "base64 0.22.1",
+ "hex",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sigstore-crypto",
+ "sigstore-merkle",
+ "sigstore-types",
+ "thiserror 2.0.21",
+ "url",
+]
+
+[[package]]
+name = "sigstore-trust-root"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6b0d2550f05c096400066e858db13d91f9de3b750a7541fb1291c1dc80ca290"
+dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "hex",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "sigstore-crypto",
+ "sigstore-types",
+ "thiserror 2.0.21",
+ "x509-cert",
+]
+
+[[package]]
+name = "sigstore-tsa"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bc86c8abc1ece6832236e7e34e9baebb5d4d40490c0332b814a0d8624ca7255"
+dependencies = [
+ "aws-lc-rs",
+ "base64 0.22.1",
+ "chrono",
+ "cmpv2",
+ "cms",
+ "const-oid 0.9.6",
+ "der 0.7.10",
+ "hex",
+ "rand",
+ "reqwest",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "sigstore-crypto",
+ "sigstore-types",
+ "thiserror 2.0.21",
+ "tracing",
+ "x509-cert",
+ "x509-tsp",
+]
+
+[[package]]
+name = "sigstore-types"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8d870c9bcfdf83396ac2bd2d6a23c5d09ec02cc9fda50fa1cbb3dd71a9bee53"
+dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "hex",
+ "pem",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "sigstore-verify"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d30aff69036e4579b416956e9ba68cec45b793116f78f10842d04c7f8b924bab"
+dependencies = [
+ "base64 0.22.1",
+ "chrono",
+ "cms",
+ "const-oid 0.9.6",
+ "hex",
+ "pem",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "serde",
+ "serde_json",
+ "serde_json_canonicalizer",
+ "sigstore-bundle",
+ "sigstore-crypto",
+ "sigstore-merkle",
+ "sigstore-rekor",
+ "sigstore-trust-root",
+ "sigstore-tsa",
+ "sigstore-types",
+ "thiserror 2.0.21",
+ "tls_codec",
+ "tracing",
+ "x509-cert",
+]
+
[[package]]
name = "simd-adler32"
version = "0.3.10"
@@ -5401,6 +6571,16 @@ dependencies = [
"serde",
]
+[[package]]
+name = "socket2"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "spirv"
version = "0.4.0+sdk-1.4.341.0"
@@ -5410,6 +6590,16 @@ dependencies = [
"bitflags 2.13.2",
]
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der 0.7.10",
+]
+
[[package]]
name = "spki"
version = "0.8.0"
@@ -5417,7 +6607,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f"
dependencies = [
"base64ct",
- "der",
+ "der 0.8.2",
]
[[package]]
@@ -5495,6 +6685,16 @@ dependencies = [
"siphasher",
]
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "unicode-ident",
+]
+
[[package]]
name = "syn"
version = "2.0.119"
@@ -5517,6 +6717,15 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
[[package]]
name = "synstructure"
version = "0.14.0"
@@ -5534,6 +6743,30 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
+ "js-sys",
+ "libc",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
+dependencies = [
+ "bitflags 2.13.2",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
"libc",
]
@@ -5549,6 +6782,17 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+[[package]]
+name = "tar"
+version = "0.4.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
[[package]]
name = "tempfile"
version = "3.27.0"
@@ -5556,7 +6800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
- "getrandom 0.3.4",
+ "getrandom 0.4.3",
"once_cell",
"rustix 1.1.5",
"windows-sys 0.61.2",
@@ -5694,25 +6938,76 @@ dependencies = [
name = "tinystr"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
+checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
+dependencies = [
+ "displaydoc",
+ "serde_core",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
+
+[[package]]
+name = "tls_codec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b"
+dependencies = [
+ "tls_codec_derive",
+ "zeroize",
+]
+
+[[package]]
+name = "tls_codec_derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "tokio"
+version = "1.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
- "displaydoc",
- "zerovec",
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.61.2",
]
[[package]]
-name = "tinyvec"
-version = "1.13.3"
+name = "tokio-rustls"
+version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
+checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db"
+dependencies = [
+ "rustls",
+ "tokio",
+]
[[package]]
-name = "tokio"
-version = "1.53.1"
+name = "tokio-util"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
+checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b"
dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "libc",
"pin-project-lite",
+ "tokio",
]
[[package]]
@@ -5766,6 +7061,51 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
+dependencies = [
+ "bitflags 2.13.2",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "url",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
[[package]]
name = "tracing"
version = "0.1.44"
@@ -5798,6 +7138,23 @@ dependencies = [
"once_cell",
]
+[[package]]
+name = "tree_magic_mini"
+version = "3.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
+dependencies = [
+ "memchr",
+ "nom",
+ "petgraph",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
[[package]]
name = "type-map"
version = "0.5.1"
@@ -5807,6 +7164,12 @@ dependencies = [
"rustc-hash 2.1.3",
]
+[[package]]
+name = "typed-path"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce898823d8cd0f028662d2f349694b1af0a5cc9be83f1d213a00d3147445e1e"
+
[[package]]
name = "typeid"
version = "1.0.3"
@@ -5887,6 +7250,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
[[package]]
name = "untrusted"
version = "0.9.0"
@@ -5895,24 +7264,26 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
-version = "3.4.2"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc"
+checksum = "cde93ff05758a36a851a398a772b0b79a82fbe3c186a46f2696baaeaf84c966b"
dependencies = [
"base64 0.23.1",
+ "flate2",
"log",
"percent-encoding",
"rustls",
"rustls-pki-types",
+ "rustls-platform-verifier",
"ureq-proto",
"utf8-zero",
]
[[package]]
name = "ureq-proto"
-version = "0.6.4"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f86fd172ccca569e458f61b6bdd6220965a9ef36e672a6852953b51a0e1583be"
+checksum = "841583fc36089d7d59419568ae157f43a5a03a2e5a81ba87c77d1596ef46e922"
dependencies = [
"base64 0.23.1",
"http",
@@ -5945,7 +7316,7 @@ dependencies = [
"kurbo 0.11.3",
"log",
"pico-args",
- "roxmltree",
+ "roxmltree 0.20.0",
"simplecss",
"siphasher",
"strict-num",
@@ -5986,8 +7357,6 @@ dependencies = [
[[package]]
name = "vello_common"
version = "0.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee"
dependencies = [
"bytemuck",
"fearless_simd",
@@ -6019,9 +7388,9 @@ dependencies = [
[[package]]
name = "vello_common"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e9aed918117e8152c9eddfd8362d73c465c23f26c44786aa331707b8a64fa2"
+checksum = "bbb2141a2bca6e6d598e471fd4d1d7eed8e020aad6a28187edda07f091a325dd"
dependencies = [
"bytemuck",
"fearless_simd",
@@ -6035,8 +7404,6 @@ dependencies = [
[[package]]
name = "vello_cpu"
version = "0.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0"
dependencies = [
"bytemuck",
"glifo 0.1.1",
@@ -6047,14 +7414,24 @@ dependencies = [
[[package]]
name = "vello_cpu"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac7349e1f55f6b801c7c277958df4ea53e7f20f21e8014910ad888b2ecda93ea"
+checksum = "ace506ca414548966fcf3c283be94eb1cad8254de488791ee698bf438b0890a9"
dependencies = [
"bytemuck",
- "glifo 0.2.0",
+ "glifo 0.3.0",
"hashbrown 0.17.1",
- "vello_common 0.1.0",
+ "vello_common 0.2.0",
+]
+
+[[package]]
+name = "verifysign"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6acfcc42a8d44f340d001193d97ef56bf33210b51ad760ae8308c97d5241ca51"
+dependencies = [
+ "core-foundation 0.10.1",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -6082,6 +7459,15 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "want"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b"
+dependencies = [
+ "try-lock",
+]
+
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
@@ -6272,7 +7658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0"
dependencies = [
"proc-macro2",
- "quick-xml",
+ "quick-xml 0.41.0",
"quote",
]
@@ -6317,13 +7703,22 @@ dependencies = [
"jni",
"log",
"ndk-context",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2",
"url",
"web-sys",
]
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58ec80e73fd8baf57bf0d9615554c75348bda990d6d5bbeab964dd068319fecb"
+dependencies = [
+ "rustls-pki-types",
+]
+
[[package]]
name = "weezl"
version = "0.1.12"
@@ -6464,7 +7859,7 @@ dependencies = [
"naga",
"naga-types",
"ndk-sys",
- "objc2 0.6.4",
+ "objc2 0.6.5",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation 0.3.2",
@@ -6611,6 +8006,17 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "windows-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+dependencies = [
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
[[package]]
name = "windows-result"
version = "0.4.1"
@@ -6635,7 +8041,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
]
[[package]]
@@ -6644,16 +8050,7 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.5",
+ "windows-targets",
]
[[package]]
@@ -6671,31 +8068,14 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
-dependencies = [
- "windows-link",
- "windows_aarch64_gnullvm 0.53.1",
- "windows_aarch64_msvc 0.53.1",
- "windows_i686_gnu 0.53.1",
- "windows_i686_gnullvm 0.53.1",
- "windows_i686_msvc 0.53.1",
- "windows_x86_64_gnu 0.53.1",
- "windows_x86_64_gnullvm 0.53.1",
- "windows_x86_64_msvc 0.53.1",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
@@ -6713,99 +8093,52 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
-
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
-
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
-
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
-
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
-
[[package]]
name = "winit"
version = "0.30.13"
+source = "git+https://github.com/storytold/winit.git?rev=a517b3846ee8457d84ee4975110bfda6797c44dc#a517b3846ee8457d84ee4975110bfda6797c44dc"
dependencies = [
"ahash",
"android-activity",
@@ -6861,11 +8194,42 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "winprint"
+version = "0.2.1"
+source = "git+https://github.com/storytold/winprint.rs?rev=5f80b9baf6b58937c401656634e42d33f00ddf49#5f80b9baf6b58937c401656634e42d33f00ddf49"
+dependencies = [
+ "flate2",
+ "fmt-derive",
+ "reqwest",
+ "scopeguard",
+ "sigstore-trust-root",
+ "sigstore-types",
+ "sigstore-verify",
+ "strum",
+ "tar",
+ "thiserror 2.0.21",
+ "windows",
+ "windows-core",
+ "windows-implement",
+ "xml",
+]
+
+[[package]]
+name = "winreg"
+version = "0.55.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "winresource"
-version = "0.1.31"
+version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0986a8b1d586b7d3e4fe3d9ea39fb451ae22869dcea4aa109d287a374d866087"
+checksum = "a2bc6d36480b829272a5bdabf08e6dca8004761c1da7e35efef800540c66221b"
dependencies = [
"toml",
"version_check",
@@ -6883,6 +8247,24 @@ version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+[[package]]
+name = "wl-clipboard-rs"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d7888ccd4896447b2d14d3a9350a85df2aeb6f181e2e7a31349d104ac46cac1"
+dependencies = [
+ "libc",
+ "log",
+ "os_pipe",
+ "rustix 1.1.5",
+ "thiserror 2.0.21",
+ "tree_magic_mini",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-protocols-wlr",
+]
+
[[package]]
name = "wnaf"
version = "0.14.1"
@@ -6906,6 +8288,9 @@ name = "writeable"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
+dependencies = [
+ "either",
+]
[[package]]
name = "x11-dl"
@@ -6939,6 +8324,41 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
+[[package]]
+name = "x509-cert"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94"
+dependencies = [
+ "const-oid 0.9.6",
+ "der 0.7.10",
+ "sha1 0.10.7",
+ "signature 2.2.0",
+ "spki 0.7.3",
+ "tls_codec",
+]
+
+[[package]]
+name = "x509-tsp"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5ceece934a21607055b7ac5c25adb56a2ff559804b10705dc674d1d838c15e1"
+dependencies = [
+ "cmpv2",
+ "cms",
+ "der 0.7.10",
+]
+
+[[package]]
+name = "xattr"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
+dependencies = [
+ "libc",
+ "rustix 1.1.5",
+]
+
[[package]]
name = "xcursor"
version = "0.3.11"
@@ -6964,6 +8384,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
+[[package]]
+name = "xml"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f45bb2c13fec6a6cb4c0f76a7e94839e110a14ec803ec2940777a94c347bc52"
+
[[package]]
name = "xml-rs"
version = "0.8.29"
@@ -6981,11 +8407,14 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
+ "chrono",
"lopdf",
+ "pdfcraft-cos",
+ "pdfcraft-oracle",
"png 0.18.1",
"serde",
"serde_json",
- "sha2",
+ "sha2 0.11.1",
"toml",
]
@@ -7164,6 +8593,20 @@ name = "zeroize"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
[[package]]
name = "zerotrie"
@@ -7172,8 +8615,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
dependencies = [
"displaydoc",
+ "litemap",
+ "serde_core",
"yoke",
"zerofrom",
+ "zerovec",
]
[[package]]
@@ -7182,6 +8628,7 @@ version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8"
dependencies = [
+ "serde",
"yoke",
"zerofrom",
"zerovec-derive",
@@ -7198,6 +8645,23 @@ dependencies = [
"syn 3.0.6",
]
+[[package]]
+name = "zip"
+version = "9.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1156b39d142a34b999c2310a50455e0cb3760bf7efad0122f796d813bee26ccb"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "getrandom 0.4.3",
+ "indexmap",
+ "memchr",
+ "nix",
+ "typed-path",
+ "windows-sys 0.61.2",
+ "zopfli",
+]
+
[[package]]
name = "zlib-rs"
version = "0.6.8"
@@ -7210,6 +8674,18 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+[[package]]
+name = "zopfli"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaf7fc5d30c28483d93805c4a5e12b05bbb52407fa67c5f8bd552374cd01fb11"
+dependencies = [
+ "bumpalo",
+ "crc32fast",
+ "log",
+ "simd-adler32",
+]
+
[[package]]
name = "zune-core"
version = "0.5.3"
@@ -7265,3 +8741,18 @@ dependencies = [
"syn 3.0.6",
"winnow",
]
+
+[[patch.unused]]
+name = "egui_demo_lib"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
+
+[[patch.unused]]
+name = "egui_inspection"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
+
+[[patch.unused]]
+name = "egui_system_font_provider"
+version = "0.37.0"
+source = "git+https://github.com/storytold/egui.git?rev=6d518fc799681571963842f95b55a6b68431b15a#6d518fc799681571963842f95b55a6b68431b15a"
diff --git a/Cargo.toml b/Cargo.toml
index 7f77d57e14..bf8a8fba87 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,47 +5,61 @@ exclude = ["vendor"]
default-members = ["crates/*", "apps/pdfcraft", "apps/pdfcraft-cli", "xtask"]
[workspace.package]
-version = "0.6.0"
+version = "0.15.0"
edition = "2024"
license = "MIT OR Apache-2.0"
-rust-version = "1.90"
+rust-version = "1.95"
repository = "https://github.com/storytold/pdfcraft"
[workspace.dependencies]
# Shared frontend components; engines remain independent of egui.
-craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675", features = ["serde"] }
+craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545", features = ["serde"] }
+# Quit the macOS way (#1136): ⌘Q asks about unsaved changes, and closing quits through `terminate:`.
+craft-quit = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+# One menu definition for the native macOS menu bar and the in-window bar elsewhere.
+craft-menu = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+craft-keymap = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545", default-features = false }
+# Shared system spooler; document composition remains in pdfcraft-print.
+craft-print = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+# Whether a path stored in a document may be opened (GoToR link targets).
+craft-docpath = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "e11f9d9aebea5f6b8e74643c1ea1ed172ba5f545" }
+# craft-update: app-specific pretend versions apply to startup and manual checks.
+craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "04aa1703b32d299e54f78fcde4182f2b393a9116", features = ["egui"] }
# internal
-pdfcraft-geom = { path = "crates/geom", version = "0.6.0" }
-pdfcraft-filters = { path = "crates/filters", version = "0.6.0" }
-pdfcraft-cos = { path = "crates/cos", version = "0.6.0" }
-pdfcraft-crypt = { path = "crates/crypt", version = "0.6.0" }
-pdfcraft-organize = { path = "crates/organize", version = "0.6.0" }
-pdfcraft-measure = { path = "crates/measure", version = "0.6.0" }
-pdfcraft-annot = { path = "crates/annot", version = "0.6.0" }
-pdfcraft-fonts = { path = "crates/fonts", version = "0.6.0" }
-pdfcraft-model = { path = "crates/model", version = "0.6.0" }
-pdfcraft-content = { path = "crates/content", version = "0.6.0" }
-pdfcraft-redact = { path = "crates/redact", version = "0.6.0" }
-pdfcraft-print = { path = "crates/print", version = "0.6.0" }
-pdfcraft-xfdf = { path = "crates/xfdf", version = "0.6.0" }
-pdfcraft-sign = { path = "crates/sign", version = "0.6.0" }
-pdfcraft-optimize = { path = "crates/optimize", version = "0.6.0" }
-pdfcraft-a11y = { path = "crates/a11y", version = "0.6.0" }
-pdfcraft-ocr = { path = "crates/ocr", version = "0.6.0" }
-pdfcraft-js = { path = "crates/js", version = "0.6.0" }
-pdfcraft-compare = { path = "crates/compare", version = "0.6.0" }
-pdfcraft-preflight = { path = "crates/preflight", version = "0.6.0" }
-pdfcraft-export = { path = "crates/export", version = "0.6.0" }
-pdfcraft-edit = { path = "crates/edit", version = "0.6.0" }
-pdfcraft-create = { path = "crates/create", version = "0.6.0" }
-pdfcraft-external = { path = "crates/external", version = "0.6.0" }
-pdfcraft-forms = { path = "crates/forms", version = "0.6.0" }
-pdfcraft-xfa = { path = "crates/xfa", version = "0.6.0" }
-pdfcraft-render = { path = "crates/render", version = "0.6.0" }
-pdfcraft-engine = { path = "crates/engine", version = "0.6.0" }
-pdfcraft-platform = { path = "crates/platform", version = "0.6.0" }
-pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.6.0" }
-pdfcraft-automation = { path = "crates/automation", version = "0.6.0", default-features = false }
+pdfcraft-geom = { path = "crates/geom", version = "0.15.0" }
+pdfcraft-filters = { path = "crates/filters", version = "0.15.0" }
+pdfcraft-cos = { path = "crates/cos", version = "0.15.0" }
+pdfcraft-crypt = { path = "crates/crypt", version = "0.15.0" }
+pdfcraft-organize = { path = "crates/organize", version = "0.15.0" }
+pdfcraft-measure = { path = "crates/measure", version = "0.15.0" }
+pdfcraft-annot = { path = "crates/annot", version = "0.15.0" }
+pdfcraft-audit = { path = "crates/audit", version = "0.15.0" }
+pdfcraft-fonts = { path = "crates/fonts", version = "0.15.0" }
+pdfcraft-model = { path = "crates/model", version = "0.15.0" }
+pdfcraft-content = { path = "crates/content", version = "0.15.0" }
+pdfcraft-redact = { path = "crates/redact", version = "0.15.0" }
+pdfcraft-print = { path = "crates/print", version = "0.15.0" }
+pdfcraft-xfdf = { path = "crates/xfdf", version = "0.15.0" }
+pdfcraft-sign = { path = "crates/sign", version = "0.15.0" }
+pdfcraft-optimize = { path = "crates/optimize", version = "0.15.0" }
+pdfcraft-a11y = { path = "crates/a11y", version = "0.15.0" }
+pdfcraft-oracle = { path = "crates/oracle", version = "0.15.0" }
+pdfcraft-testkit = { path = "crates/testkit", version = "0.15.0" }
+pdfcraft-ocr = { path = "crates/ocr", version = "0.15.0" }
+pdfcraft-js = { path = "crates/js", version = "0.15.0" }
+pdfcraft-compare = { path = "crates/compare", version = "0.15.0" }
+pdfcraft-preflight = { path = "crates/preflight", version = "0.15.0" }
+pdfcraft-export = { path = "crates/export", version = "0.15.0" }
+pdfcraft-edit = { path = "crates/edit", version = "0.15.0" }
+pdfcraft-create = { path = "crates/create", version = "0.15.0" }
+pdfcraft-external = { path = "crates/external", version = "0.15.0" }
+pdfcraft-forms = { path = "crates/forms", version = "0.15.0" }
+pdfcraft-xfa = { path = "crates/xfa", version = "0.15.0" }
+pdfcraft-render = { path = "crates/render", version = "0.15.0" }
+pdfcraft-engine = { path = "crates/engine", version = "0.15.0" }
+pdfcraft-platform = { path = "crates/platform", version = "0.15.0" }
+pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.15.0" }
+pdfcraft-automation = { path = "crates/automation", version = "0.15.0", default-features = false }
# pdf
hayro = "0.7.1"
@@ -60,35 +74,47 @@ serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1"
log = "0.4"
kurbo = "0.13"
+# All date/time conversion goes through chrono (no hand-rolled calendar code beyond the 400-year range extension; AGENTS.md).
+chrono = { version = "0.4.45", default-features = false, features = ["std"] }
# testing
proptest = "1"
# ui
-egui = "0.36"
-egui_extras = { version = "0.36", default-features = false, features = ["svg"] }
-eframe = { version = "0.36", default-features = false }
-egui_kittest = "0.36"
+egui = "0.37"
+egui_extras = { version = "0.37", default-features = false, features = ["svg"] }
+eframe = { version = "0.37", default-features = false }
+egui_kittest = "0.37"
rfd = "0.17"
+# Monotonic time for logic-only work on native and web (`App::logic` runs without a UI pass).
+web-time = "1.1"
[workspace.lints.rust]
unsafe_code = "forbid"
[workspace.lints.clippy]
+cognitive_complexity = "deny"
+too_many_arguments = "deny"
+wildcard_imports = "deny"
dbg_macro = "warn"
todo = "warn"
# `"*"` matches every non-workspace package: crates.io dependencies and the
-# vendored crates under `vendor/` (excluded from the workspace). Our own crates
-# keep full debug info. Dependencies keep only line tables, so backtraces still
-# show file and line, but debug info for the whole dependency graph stays out of
-# every test binary (each UI test binary had a 500-600 MB PDB on Windows, #454).
+# vendored crates under `vendor/` (excluded from the workspace). Dependencies
+# carry no debug info and our own crates only line tables: backtraces and
+# panics still show file and line, while test binaries and the target dir stay
+# small (each UI test binary had a 500-600 MB PDB on Windows, #454).
[profile.dev.package."*"]
opt-level = 2
-debug = "line-tables-only"
+debug = false
[profile.dev]
opt-level = 1
+debug = "line-tables-only"
+
+[profile.low-disk]
+inherits = "dev"
+incremental = false
[profile.release]
lto = "thin"
@@ -99,7 +125,29 @@ codegen-units = 1
hayro-interpret = { path = "vendor/hayro-interpret" }
hayro = { path = "vendor/hayro" }
hayro-syntax = { path = "vendor/hayro-syntax" }
+hayro-cmap = { path = "vendor/hayro-cmap" }
+hayro-postscript = { path = "vendor/hayro-postscript" }
hayro-jbig2 = { path = "vendor/hayro-jbig2" }
lopdf = { path = "vendor/lopdf" }
-winit = { path = "vendor/winit" }
-egui-wgpu = { path = "vendor/egui-wgpu" }
+vello_common = { path = "vendor/vello_common" }
+vello_cpu = { path = "vendor/vello_cpu" }
+# The egui and winit crates below are pinned to immutable storytold git revisions (egui
+# 6d518fc799681571963842f95b55a6b68431b15a, winit a517b3846ee8457d84ee4975110bfda6797c44dc).
+# Only the retained `vendor/winit` and `vendor/egui-wgpu` copies are provenance for the app's
+# earlier patches and their source guards, not path patches; the other `vendor/` entries above
+# remain real path patches. See vendor/README.md and the migration plan.
+ecolor = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+emath = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+epaint = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+epaint_default_fonts = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui-winit = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui-wgpu = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_glow = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_extras = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_kittest = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_system_font_provider = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+eframe = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_demo_lib = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+egui_inspection = { git = "https://github.com/storytold/egui.git", rev = "6d518fc799681571963842f95b55a6b68431b15a" }
+winit = { git = "https://github.com/storytold/winit.git", rev = "a517b3846ee8457d84ee4975110bfda6797c44dc" }
diff --git a/NOTICE b/NOTICE
index 214d3f8968..3939d3782e 100644
--- a/NOTICE
+++ b/NOTICE
@@ -21,20 +21,22 @@ list (author, source, license) is in ATTRIBUTION.md.
- Inter typeface (assets/fonts/Inter-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-Inter.txt.
- JetBrains Mono typeface (assets/fonts/JetBrainsMono-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-JetBrainsMono.txt.
- Dancing Script typeface (assets/fonts/DancingScript.ttf), Copyright 2016 The Dancing Script Project Authors — SIL Open Font License 1.1 (Reserved Font Name "Dancing Script"). See assets/fonts/OFL-DancingScript.txt.
-- Japanese fonts from craft-fonts (https://github.com/storytold/craft-fonts), an optional build input
+- Fonts from craft-fonts (https://github.com/storytold/craft-fonts), an optional build input
(CRAFT_FONTS_DIR) that is not part of this repository. Builds made with it, which includes every
official release, embed the fonts listed in
https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md (BIZ UDPGothic, Shippori Mincho,
BIZ UDMincho; the web build only BIZ UDPGothic Regular) under the SIL Open Font License 1.1. Those
- packages carry each font's licence as OFL-.txt.
+ packages carry each font's licence as OFL-.txt. Builds made with the craft-fonts revision
+ pinned in .github/workflows/ also include Noto Sans Thai (in the web build too), Copyright 2022
+ The Noto Project Authors (https://github.com/notofonts/thai), under SIL OFL 1.1; its licence is
+ fonts/noto-sans-thai/OFL.txt in the craft-fonts build input.
- hayro (rendering, via crates.io) — Apache-2.0 OR MIT. Its `embed-fonts` feature bundles the Foxit
standard-14 Type 1 fonts under BSD-3-Clause ("Copyright 2014 PDFium Authors"), and hayro-cmap bundles
Adobe CMap resources under BSD-3-Clause.
- lopdf (bootstrap document inspection, via crates.io) — MIT.
- egui default fonts (epaint_default_fonts, via eframe) — Ubuntu Light (Ubuntu Font Licence 1.0),
Hack (MIT / Bitstream Vera licence), Noto Emoji (SIL OFL 1.1), emoji-icon-font (MIT).
-- Colour profiles in hayro-interpret — CGATS001Compat-v2-micro.icc (CC0-1.0, Clinton Ingram) and
- LAB.icc (generated by the hayro authors with LittleCMS 2; MIT OR Apache-2.0).
+- Colour profile in hayro-interpret — CGATS001Compat-v2-micro.icc (CC0-1.0, Clinton Ingram).
Required notices:
@@ -57,3 +59,21 @@ dependencies change (plan/adr/0002, 0006).
Vendored (vendor/, patched; see vendor/README.md):
- hayro 0.7.1 — Apache-2.0 OR MIT, Copyright the hayro authors (licence files kept in vendor/hayro).
- hayro-interpret 0.7.0 — Apache-2.0 OR MIT, Copyright the hayro authors (LICENSE-APACHE, LICENSE-MIT kept in vendor/hayro-interpret).
+
+Bundled egui font icons
+
+The pinned egui dependency includes egui-icons.ttf, a small subset of John Slegers'
+emoji-icon-font, through default_fonts. The parent emoji-icon-font.ttf face is
+included through monochrome_emoji_fonts. Their upstream project is
+https://github.com/jslegers/emoji-icon-font; both use the same exact copyright
+and permission notice below.
+
+MIT License
+
+Copyright (c) 2014 John Slegers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/PATCHES.md b/PATCHES.md
new file mode 100644
index 0000000000..68f385aba2
--- /dev/null
+++ b/PATCHES.md
@@ -0,0 +1,41 @@
+# What this fork carries
+
+PlutarchPages is upstream [PdfCraft](https://github.com/storytold/pdfcraft) plus the changes below.
+[Fork changes](README.md#fork-changes) describes them for users; this file is for whoever merges
+upstream next.
+
+Last upstream merge: `1d1cbc4e` (30 October 2026).
+
+## Stricter than upstream on purpose
+
+Upstream's tests for these were changed to assert the fork's behaviour. Keep them that way.
+
+- **Redaction** refuses when content under the marks is also used where the marks don't reach.
+ Upstream goes ahead. Tests in `crates/redact` and `crates/automation`.
+- **Copy-restricted documents** refuse text extraction through the tools, including `text_find`.
+- **An empty password** never skips the Document Open prompt or lifts restrictions. `pdfcraft-cli
+ check-one` checks before it renders.
+- **CSV exports** write formula-like cells as text, and import doesn't strip the apostrophe, so a
+ neutralised cell doesn't round-trip back into a formula.
+
+## Only here
+
+- The PDF-XChange-style converters, speech, bookmark, optimiser, colour and Excel features.
+- Mermaid colour scheme: `crates/ui-egui/src/theme.rs` holds every interface colour, and
+ `chrome_literals_stay_in_the_theme` fails when a merge brings a colour literal back. The catalogue
+ hues in `crates/engine/src/catalog.rs` and the app icon follow it.
+- Brand: no ArtCraft name or logos (`AGENTS.md` section 1.2). Upstream merges add them back, in new
+ files too, so search for them after every merge.
+- Update check and repository links point at EquityBot.
+- Shared CI: workflows from `storytold/craft-common-actions` are pinned to a commit, and SonarCloud
+ receives only `SONAR_TOKEN`. Upstream merges restore `@main` and `secrets: inherit`, so reapply both.
+- CodeQL: `.github/codeql/codeql-config.yml` excludes tests and `vendor/`.
+
+## Merging upstream
+
+1. `git merge --no-ff` upstream's `main` on a `ryan/` branch. Never rewrite history.
+2. Search for ArtCraft names, trademark-licensed assets, `storytold/pdfcraft` links in app code and
+ new colour literals.
+3. Run `cargo xtask ci`. `cargo xtask assets --write` regenerates `ATTRIBUTION.md`.
+4. A failure that also occurs on plain upstream isn't the merge's fault: check before patching it.
+5. Update the commit above.
diff --git a/README.md b/README.md
index 7e75f9fca3..b43334ce2c 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,12 @@
[](https://github.com/EquityBot/PlutarchPages/actions/workflows/ci.yml) [](https://github.com/EquityBot/PlutarchPages/actions/workflows/codeql.yml)
-[](https://www.rust-lang.org/) [](#license-and-credits) [](https://github.com/storytold/pdfcraft)
+[](https://www.rust-lang.org/) [](#license-and-credits) [](https://github.com/storytold/pdfcraft)
- The PDF workbench; an open-source, clean-room reimplementation of Adobe Acrobat, rebuilt in pure Rust.
+ The PDF workbench; an open-source, modern PDF reader and editor, built in pure Rust.
Read, organize, combine, split and secure PDFs in a fast, native app, written in Rust from the ground up.
macOS · Windows · Linux · FreeBSD · the web
@@ -30,9 +30,9 @@
-
+
- The PdfCraft Showcase, a 13-page specimen PDF, open with the All tools panel and threaded comments.
+ The PlutarchPages Showcase, a 13-page specimen PDF, open with the All tools panel and threaded comments.
---
@@ -101,7 +100,7 @@ PdfCraft renders PDFs with care for the details that make a page feel right: ker
- **Deep zoom stays sharp.** Large pages render in tiles, so text stays crisp at any magnification.
- **Built to survive bad files.** Every page renders in isolation and damaged documents are repaired. Across the 983-file pdf.js test corpus the result is 0 crashes.
- **Layouts for every task:** continuous, single page, two-up, view rotation, full screen and a distraction-free Read mode.
-- **Light and dark themes** in black, ivory, Tyrian purple and crimson: ivory chrome in the light theme, and a true black dark theme for OLED screens. Pages stay white.
+- **Light and dark themes** in one colour scheme: ivory chrome or true black for OLED screens, crimson and Tyrian purple accents, gold frames and links. Pages stay white.
@@ -120,8 +119,12 @@ Search the whole document as you type, step through matches with ⌘G
## Navigate long documents
+Right-click a PDF tab to close it, reopen the last closed file-backed tab, or reveal its file. Closing still asks about unsaved changes. Reopening reads the saved file from disk; it does not restore discarded edits. Reveal selects the file in Explorer or Finder. On Linux and FreeBSD it requests `org.freedesktop.FileManager1.ShowItems`, falling back to opening the containing directory with `xdg-open` when that service is unavailable. Reopen and Reveal are unavailable on the web; Reveal is also unavailable for pathless documents.
+
Bookmarks, page thumbnails and the document's own page labels (i, ii, 1, 2…) keep you oriented in long documents. Search bookmark titles in the Bookmarks panel to find nested entries even when their parents are collapsed. Matches keep their ancestors for context; Clear restores the unfiltered tree without changing its expansion state.
+In **Inspector > Pages**, use **Thumbnail size** and the smaller/larger buttons to show more pages or inspect larger previews (50–150%). This changes only the thumbnails, keeping multi-page selection and the current page in view. The size belongs to the open document view and survives reloading its file; it is not remembered after restarting. Agents can set it with `ui.set {"key":"thumbnail-zoom","value":"75"}` and read `active.thumbnail_zoom` from `ui.state`.
+
@@ -157,7 +160,7 @@ Open **Organize pages** to see every page at once:
**Saves you can trust:**
- *Incremental:* the original bytes stay byte-for-byte intact.
- *Atomic:* the file is written to a temporary copy, then swapped in.
-- *Verified:* independently checked with qpdf.
+- *Verified:* independently checked with qpdf, on every CI run.
When open documents exceed the window width, scroll over the tab strip with the mouse wheel or trackpad, or use its horizontal scrollbar. Opening or switching to a document brings its tab into view.
@@ -184,7 +187,7 @@ Every page of a combined document renders pixel-identical to its source.
```sh
pdfcraft-cli combine report.pdf appendix.pdf --out combined.pdf
-pdfcraft-cli extract report.pdf --pages 1,3,5 --out highlights.pdf
+pdfcraft-cli extract report.pdf --pages 1,3,5-8 --out highlights.pdf
pdfcraft-cli split report.pdf --every 10 --out-dir parts/
```
@@ -265,6 +268,7 @@ Every engine feature is reachable without the GUI, through one table of JSON-Sch
pdfcraft-cli run text_find doc=1 query=invoice # key=value; values parse as JSON
pdfcraft-cli run --script review.json # e.g. comment_add {"type": "highlight", "find": "total due"}
pdfcraft-cli run --script steps.json --root ./work # several steps in one session
+ pdfcraft-cli run --script steps.json --report # one JSON document: per step its number, tool, status, result or error
```
With `--root`, every file the script's steps read or write stays in that directory, including the PNG a step saves with `"out"` (the script itself is read from wherever you name it).
@@ -302,15 +306,13 @@ pdfcraft-cli ui --control ~/.pdfcraft-control.json inspect focused=true
pdfcraft-cli ui --control ~/.pdfcraft-control.json quit
```
-`ui.dock` arranges the `tools` and `inspector` panels; `canvas` is the protected document view.
-Each per-panel request requires a `panel` ID and an `operation`: `open`, `close`,
-`activate`, `float` with `rect: [x, y, width, height]`, or `move` with `target` and
-`zone: center|left|right|top|bottom`. For example,
-`{"operation":"float","panel":"tools","rect":[100,100,320,440]}` floats Tools.
-`ui.dock.reset` restores the default
-arrangement. The control channel accepts these methods directly; `ui.command` also accepts
-`{"id":"ui.dock","params":{...}}`. Saved preferences retain groups, active tabs, visibility
-and floating geometry. Invalid requests return an error without changing the document or layout.
+`ui.panel` opens, closes or sizes a side panel: `{"panel":"tools"|"side","open":true|false,"width":320}`.
+`tools` is the Tools panel and `side` the panel the rail opens (reopening it shows the one open last).
+`width` is clamped to the panel's limits (Tools 240–520, side panel 260–520 points). `ui.dock.reset`
+resets the side panels: Tools open on the left, default widths. The control channel accepts these
+methods directly; `ui.command` also accepts `{"id":"ui.panel","params":{...}}`. Saved preferences keep
+the Tools side, the open panels and their widths. Invalid requests return an error without changing
+the document or the panels.
`resize` requests a native inner-window size in logical points (each dimension must be between 320 and 8192); the window manager may constrain it. `state` reports the observed `window.width`, `window.height` and `window.pixels_per_point`. `focus` accepts exactly one widget `id` or unique enabled, focusable `label`; subsequent `key` requests traverse or activate the actual widgets. `inspect` includes focusability and accepts a `focused` filter. `quit` takes no parameters: clean documents exit normally, while unsaved edits or typing open the existing Save/Don't save/Cancel prompt and return `quitting: false, needs_confirmation: true`. It never silently discards work. Window resizing and application quit are native-only.
@@ -345,15 +347,19 @@ On top of those, two corpus sweeps run over real-world files:
- **Opening and rendering:** of the 983 pdf.js test files, 963 open and render cleanly, with 0 crashes.
- **Open, edit and save round trips:** 958 succeed.
-The output is verified with independent tools: hayro, qpdf and poppler.
+The output is verified against independent implementations: hayro and qpdf on every CI run, and
+poppler over the corpus on demand (`cargo xtask text-oracle`).
PdfCraft is a clean-room implementation. Its behaviour comes from the ISO 32000 specification and black-box observation, never from anyone else's code. Every icon, font and image is openly licensed and listed in [ATTRIBUTION.md](ATTRIBUTION.md).
## Get started
+Building needs Rust 1.95 or later.
+
```sh
-git clone https://github.com/storytold/pdfcraft
-cd pdfcraft
+git clone https://github.com/EquityBot/PlutarchPages
+cd PlutarchPages
+cargo xtask models # fetch the OCR models Scan & OCR needs (release builds include them)
cargo run --release -p pdfcraft -- some.pdf # desktop app
cargo xtask demo-pdf # build the showcase PDF used in these screenshots
cargo xtask screenshots # regenerate every screenshot in this README
@@ -375,33 +381,20 @@ git clone https://github.com/storytold/craft-fonts ../craft-fonts
CRAFT_FONTS_DIR=../craft-fonts cargo run --release -p pdfcraft -- some.pdf
```
-Each [GitHub release](https://github.com/storytold/pdfcraft/releases) has ready-made builds for macOS,
-Windows, Linux (AppImage, Flatpak, `.deb`, `.rpm` and a tarball), FreeBSD and the web; see
-[Downloads](#downloads). On Gentoo, the community [::snakebyte
-overlay](https://github.com/switch87/snakebyte-overlay) packages the Linux release as
-`app-text/pdfcraft-bin` (not maintained by the PdfCraft team):
-
-```sh
-eselect repository add snakebyte git https://github.com/switch87/snakebyte-overlay.git
-emaint sync -r snakebyte
-echo 'app-text/pdfcraft-bin ~amd64' >> /etc/portage/package.accept_keywords/pdfcraft
-emerge --ask app-text/pdfcraft-bin
-```
-
Logs, environment variables and other development notes are in [docs/development.md](docs/development.md).
## What's next
-PdfCraft is young and moving fast. The aim is a workbench where you can view, organize, annotate, fill, sign and edit PDFs, at parity with Acrobat Pro.
+PdfCraft is young and moving fast. The aim is a workbench where you can view, organize, annotate, fill, sign and edit PDFs, for professional and everyday workflows.
-**Where it stands (October 2026), honestly:** PdfCraft is **alpha**. Most of Acrobat Pro's offline features exist in some form (57% of all tracked features, 94% of the must-haves). For everyday work (viewing, commenting, filling and signing forms, organizing pages) it is about 55% of the way to replacing Acrobat; against all of Acrobat Pro, about 49%; for someone who only needs the essentials, about 66%. Every everyday workflow can be completed, but converting and sharing is weak: password-protected files Acrobat can't open, no Office-to-PDF, and Word export that loses layout.
+**Where it stands (October 2026), honestly:** PdfCraft is **alpha**. Most essential offline PDF features exist in some form (57% of the features tracked in [docs/target-app-parity.md](docs/target-app-parity.md), 94% of core essentials). For everyday work (viewing, commenting, filling and signing forms, organizing pages) readiness is about 55%; across all professional workflows, about 49%; for someone who only needs the essentials, about 66%. Every everyday workflow can be completed, but converting and sharing is weak: no office-document-to-PDF, and .docx export that loses layout.
- **Good today:** viewing and search; organizing, combining and splitting; most kinds of comment; filling and authoring forms (with sandboxed JavaScript); passwords, redaction and sanitizing; basic digital signatures; printing; the Accessibility Checker; agent control through the CLI and MCP.
- **Still borrowed:** pages are drawn by the `hayro` crate while our own renderer is built.
-- **Thin or missing:** reliable editing of existing text (especially CJK and right-to-left), OCR beyond Latin script, Office import/export, signature tokens and online long-term validation, Preflight and PDF/X/UA, printing on Windows, and full XFA forms.
-- **Hardening:** fuzzing still turns up crashes and hangs on hostile files; each one is fixed with a regression test. Quality has not yet been compared with Acrobat side by side.
+- **Thin or missing:** reliable editing of existing text (especially CJK and right-to-left), OCR beyond Latin script, office document import/export, signature tokens and online long-term validation, Preflight and PDF/X/UA, printing from the web build, physical printer fidelity, and full XFA forms.
+- **Hardening:** fuzzing still turns up crashes and hangs on hostile files; each one is fixed with a regression test. Quality has not yet been benchmarked side by side.
-**Next, in order:** encrypted files that Acrobat opens, the reported bugs and Windows printing, a fidelity harness against Acrobat and the renderer, editing existing content, then the Pro workflows (OCR, Office, Preflight, signatures, accessibility tagging) and 1.0 polish.
+**Next, in order:** office-document-to-PDF and a .docx export that keeps layout, the reported bugs and the Chinese interface font, a fidelity harness against a reference renderer, editing existing content, then professional workflows (OCR, office formats, Preflight, signatures, accessibility tagging) and 1.0 polish.
The summary is in **[ROADMAP.md](ROADMAP.md)**; the full assessment by dimension and area is in [docs/target-app-parity.md](docs/target-app-parity.md), the ranked gaps in [docs/gaps.md](docs/gaps.md), and the milestones in [docs/roadmap.md](docs/roadmap.md).
@@ -411,63 +404,6 @@ The summary is in **[ROADMAP.md](ROADMAP.md)**; the full assessment by dimension
This fork publishes no builds of its own yet; build it from source (see [Development](docs/development.md)). Upstream PdfCraft builds are on the [latest release](https://github.com/storytold/pdfcraft/releases/latest) has every build listed below, and [all releases](https://github.com/storytold/pdfcraft/releases) has earlier versions and their notes. `` in the file names is the version number, and `SHA256SUMS.txt` lists a checksum for every file.
-### Windows
-
-| Build | Installer | Portable |
-|---|---|---|
-| x64 (64-bit Intel/AMD) | `pdfcraft--windows-x64.msi` | `pdfcraft--windows-x64-portable.zip` |
-| arm64 (Snapdragon and other ARM PCs) | `pdfcraft--windows-arm64.msi` | `pdfcraft--windows-arm64-portable.zip` |
-| x86 (32-bit) | `pdfcraft--windows-x86.msi` | `pdfcraft--windows-x86-portable.zip` |
-
-Installers and executables are code-signed.
-
-The portable zip runs from any folder, a USB stick included. Its `portable.txt` keeps the settings,
-logs and crash recovery in a `PdfCraftData` folder next to `pdfcraft.exe`, so nothing is written to
-`%APPDATA%`; delete that file to use the normal per-user folders.
-
-The MSI installs for all users and requires administrator privileges. For unattended deployment
-without a desktop shortcut, run from an elevated terminal:
-
-```powershell
-msiexec /i "pdfcraft--windows-x64.msi" /qn /norestart INSTALLDESKTOPSHORTCUT=0
-```
-
-Use the MSI for your architecture. Per-user installation overrides are not supported.
-
-### macOS
-
-| Build | File | Notes |
-|---|---|---|
-| App, universal (Apple silicon + Intel) | `pdfcraft--macos-universal.dmg` | Signed and notarized |
-| Command-line tool, universal | `pdfcraft-cli--macos-universal.zip` | Signed and notarized |
-
-### Linux
-
-| Format | x86_64 | aarch64 (ARM64) | Notes |
-|---|---|---|---|
-| AppImage | `pdfcraft--linux-x86_64.AppImage` | `pdfcraft--linux-aarch64.AppImage` | Runs anywhere; updates itself with [AppImageUpdate](https://github.com/AppImageCommunity/AppImageUpdate) (`.zsync` files) |
-| Flatpak | `pdfcraft--linux-x86_64.flatpak` | `pdfcraft--linux-aarch64.flatpak` | Sandboxed; `flatpak install --user ` |
-| Debian/Ubuntu | `pdfcraft--linux-x86_64.deb` | `pdfcraft--linux-aarch64.deb` | |
-| Fedora/RHEL/openSUSE | `pdfcraft--linux-x86_64.rpm` | `pdfcraft--linux-aarch64.rpm` | |
-| Tarball | `pdfcraft--linux-x86_64.tar.gz` | `pdfcraft--linux-aarch64.tar.gz` | Unpack anywhere |
-| Command-line tool | `pdfcraft-cli--linux-x86_64.tar.gz` | `pdfcraft-cli--linux-aarch64.tar.gz` | `pdfcraft-cli` alone (and its opt-in MCP server), for servers, CI and agents |
-
-RISC-V (riscv64) builds come as tarballs only: `pdfcraft--linux-riscv64.tar.gz` and `pdfcraft-cli--linux-riscv64.tar.gz`. They are cross-compiled and need glibc 2.39 or newer (Ubuntu 24.04+, Debian 13+).
-
-Every other Linux build needs glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+, RHEL 10).
-
-### FreeBSD
-
-| Build | File |
-|---|---|
-| x86_64 | `pdfcraft--freebsd-x86_64.tar.gz` |
-
-### Web (WebAssembly)
-
-| Build | File | Notes |
-|---|---|---|
-| Static site | `pdfcraft-web-.zip` | Runs in a modern browser; host it on any static server |
-
---
## Fork changes
@@ -540,13 +476,4 @@ The banner's lettering and emblem are drawn from Cascadia Mono glyphs (SIL OFL 1
Adobe, Photoshop, Illustrator, Premiere Pro, Lightroom, Acrobat, After Effects and InDesign are trademarks or registered trademarks of Adobe Inc. in the United States and/or other countries. PdfCraft is an independent, open-source project and is not affiliated with, sponsored by or endorsed by Adobe Inc.; these names are used only to describe the workflows it is compatible with.
-Tools and Inspector panels can be dragged into tab groups, split beside the PDF, or floated within the app window. Read and full-screen modes keep their existing focused document view. Drag a panel header to a target edge or another header. Its context menu offers Float panel, Move to group, and Close panel. Existing panel toggles reopen panels at their saved location; Reset Panel Layout restores the app layout. Floating panels remain inside the current app window.
-
-Advanced `ui.dock` operations use the same validated transaction as pointer gestures:
-`moveFloating` updates `rect`, `resizeSplit` accepts a boolean child `path` and
-`size` (`{"Ratio":0.5}`, `{"FixedFirst":280}`, or `{"FixedSecond":280}`),
-`setStackOpen` takes `open`, and `resizeStack` takes a point `height` or null.
-A center `move` can include `before` (panel ID or null to append) for tab order.
-The equivalent `{"action": ...}` form accepts a serialized shared docking action;
-this is also the form emitted by the renderer. Protected-canvas and app-specific panel
-rules apply equally to both forms.
+The Tools panel sits on the left, or on the right with Preferences ▸ Tools panel side. The rail stays at the right edge and opens one side panel beside it. Drag a panel's inner edge to resize it; widths are remembered. F4 shows or hides the side panel and Shift+F4 the Tools panel (also in the View menu); View ▸ Reset side panels restores the default arrangement.
diff --git a/ROADMAP.md b/ROADMAP.md
index 8ebf5f515d..0fd79458f2 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -1,8 +1,74 @@
# PdfCraft roadmap
-**Stage: alpha** · next: beta, ~26% (ready for real work 49% → 75%) and ~400–700 h away
-
-> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (parser cancellation regression; localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+**Stage: alpha** · next: beta, ~25% (ready for real work 50% → 75%) and ~400–700 h away
+
+> **Last reviewed:** 2026-10-27 | **Last updated:** 2026-10-27 | **Change:** minor (M10: OCR model downloads use verified ONNX pairs with legacy discovery fallback; estimates unchanged)
+> **Last reviewed:** 2026-10-25 | **Last updated:** 2026-10-25 | **Change:** minor (M14 localization current state: Arabic logical catalog, explicit RTL label direction and mirrored stock chrome; native/browser RTL workflows unqualified. Native release Hans face via LXGW WenKai Lite; estimates unchanged)
+> **Last reviewed:** 2026-10-23 · **Last updated:** 2026-10-23 · **Change:** minor (M7, #2636 partial: pasting added text boxes and images in the engine and through `content_copy`; estimates unchanged)
+> **Last reviewed:** 2026-10-23 · **Last updated:** 2026-10-23 · **Change:** minor (M11: image optimization accounts for page-local UserUnit; estimates unchanged)
+> **Last reviewed:** 2026-10-23 | **Last updated:** 2026-10-23 | **Change:** minor (M10: Word table cells use the widths of their own grid columns; estimates unchanged)
+> **Last reviewed:** 2026-10-23 | **Last updated:** 2026-10-23 | **Change:** minor (M10: table spans retain text from covered slots in Office exports; estimates unchanged)
+> **Last reviewed:** 2026-10-23 · **Last updated:** 2026-10-23 · **Change:** minor (M10: image export preserves soft-mask Decode opacity ranges; estimates unchanged)
+> **Last reviewed:** 2026-10-23 · **Last updated:** 2026-10-23 · **Change:** minor (M10: vector printing preserves existing page XObjects when adding annotation appearances; estimates unchanged)
+> **Last reviewed:** 2026-10-21 · **Last updated:** 2026-10-21 · **Change:** minor (M3, #3808: the Pages inspector has an independent 50–150% thumbnail size slider and buttons; selection and current-page following are retained, with headless ui.set coverage. Estimates unchanged.)
+> **Last reviewed:** 2026-10-20 | **Last updated:** 2026-10-20 | **Change:** minor (M11 #3507: image merging preserves content stream boundaries; estimates unchanged)
+> **Last reviewed:** 2026-10-20 | **Last updated:** 2026-10-20 | **Change:** minor (M10, #3532 partial: vector printing retains existing appearances with absent Subtype; estimates unchanged)
+> **Last reviewed:** 2026-10-17 · **Last updated:** 2026-10-17 · **Change:** minor (M8, gap 6 #2662: the redaction audit counts a cover over one word of a long line; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-20 · **Last updated:** 2026-10-20 · **Change:** minor (M12 #3673: Character encoding accepts Identity-H/V with Adobe CJK collections; estimates unchanged)
+> **Last reviewed:** 2026-10-20 · **Last updated:** 2026-10-20 · **Change:** minor (M2, #3601: missing spacing glyphs in non-embedded Japanese CID substitutes draw as blanks while PDF widths and Unicode stay unchanged; estimates unchanged)
+> **Last reviewed:** 2026-10-20 · **Last updated:** 2026-10-20 · **Change:** minor (M3, #3541/#3620: comment hover follows individual marked lines and original annotation paint order; estimates unchanged)
+> **Last reviewed:** 2026-10-20 - **Last updated:** 2026-10-20 - **Change:** minor (M6, #3502: form detection uses the existing content-stream boundary policy; estimates unchanged)
+> **Last reviewed:** 2026-10-20 | **Last updated:** 2026-10-20 | **Change:** minor (M2, #3574: named form properties retain page origin and own dictionary boundaries; estimates unchanged)
+> **Last reviewed:** 2026-10-20 · **Last updated:** 2026-10-20 · **Change:** minor (M4: initial-view options resolve indirect boolean preferences; estimates unchanged)
+> **Last reviewed:** 2026-10-16; **Last updated:** 2026-10-16; **Change:** minor (M5 #2669, item 5: reply groups and page root counts per frame; estimates unchanged)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-15 · **Change:** minor (M7: the Edit text caret is as tall as the row it is on; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-15 · **Change:** minor (M6: CSV tab-containing headers; estimates unchanged)
+> **Last reviewed:** 2026-10-18 · **Last updated:** 2026-10-18 · **Change:** minor (M3, #3149: discard render demand after page geometry changes and check the GPU texture limit before upload; estimates unchanged)
+> **Last reviewed:** 2026-10-18 · **Last updated:** 2026-10-18 · **Change:** minor (M4, #1919: repeated page indices accumulate rotations; M3, #3149: discard render demand after page geometry changes and check the GPU texture limit before upload; estimates unchanged)
+> **Last reviewed:** 2026-10-18 · **Last updated:** 2026-10-18 · **Change:** minor (M8, #1350: named replacement descriptions retired during Sanitize and across shared resources; estimates unchanged)
+> **Last reviewed:** 2026-10-17 · **Last updated:** 2026-10-17 · **Change:** minor (M4 #2997: Ctrl-drag (Option on macOS) in the Organize grid copies the pages into the drop gap; `page_duplicate` takes `at`; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-15 · **Change:** minor (M6: AcroForm XML text; estimates unchanged)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-15 · **Change:** minor (M2/gap 12: the Annex D.2 alias codes read as the ink they draw in both tables; the text oracle scores reading order; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-15 · **Change:** minor (M14/#2383 GPU-limit candidate; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-13 · **Change:** minor (M4: indirect page rotations; M13: CLI check visits each directory once through aliases and cycles; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (M6: preserve XML/XFDF attribute whitespace; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (M1: raw-deflate fallback preserves decoding-limit errors; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-16 | **Last updated:** 2026-10-16 | **Change:** minor (M10 #1201 partial: lossless image Decode; estimates unchanged) | **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-16 · **Change:** minor (M14: Czech catalog completed and reviewed; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-14 · **Change:** minor (M14: the Italian catalog has every entry the other catalogs had and the code looks up; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (M3 #2080 candidate: explicit search jumps join per-tab history; rail and control-channel Back/Forward; estimates unchanged)
+> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (M4 #1910: Organize Pages opens on the current page; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (M3 candidate: coordinate control clicks keep press/release together on slow frames and preserve text multi-click selection; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (M10 #2156 candidate: remember selected print paper by canonical name; estimates unchanged)
+> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (M3 candidate: native opens retain chosen tools through password retries and defer startup intake while preparation is pending; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M4 #1310 #1311 #1312: undo, revert and the next save keep the last saved revision; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (M3 #1980: exact quit modifiers preserve Ctrl+Alt+Q email input; M3 candidate: native opens retain chosen tools through password retries and defer startup intake while preparation is pending; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M13: CLI check visits each directory once through aliases and cycles; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M4: Extract and Split preserve shared Type 3 glyph resources; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M2: packed TIFF-predictor RGB rows retain their byte boundaries; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M3 #1364 candidate: consent before absolute local GoToR access; estimates unchanged); earlier: minor (M1 #1339: an unchanged incremental save of a classic cross-reference table writes a zero-length subsection; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M5 #1398: stamps read upright on rotated pages; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (gap 6: cloudy comments stay when flatten cannot draw them, a refused text-box edit keeps its properties, arrow defaults stay off lines, a custom match stops at a separator, and the vertical-text redaction error no longer claims an overlap; #1317, #1327, #1302, #1315, #1340; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M7 #1316: replacing a line keeps a neighbouring line whose glyph box overlaps; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M5: comment submission shortcuts; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M1 #1339: an unchanged incremental save of a classic cross-reference table writes a zero-length subsection; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M14 Windows low-DPI font-hinting candidate measured on macOS; no Windows runtime claim; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M3: Windows' Animation effects setting is followed, and Preferences has Animation effects: system, on or off); earlier: exclusive image-crop resize follow-up; M2 short same-line redraws split before placement; estimates unchanged · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (M7 #1200 candidate: local GoToR links and confined automation; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** exclusive image-crop resize follow-up; minor (M2 short same-line redraws split before placement; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (M10, #1028: OCR reads pictures on pages that have text, on request); earlier: M14 #307 Plan 3 uses one marker traversal on open and full refresh, and the combined scanner borrows metadata instead of cloning scan-only containers; includes a behavior-preserving `organize` binding for the workspace Clippy gate · earlier: minor (localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (#594 paragraph drags validated in the Linux test environment; localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (architectural paper controls from #599; localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (closed issues synced: #774, #756 and the #799–#821 batch; earlier: localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M6 #2892: Push-button normal labels are editable per widget through Options and form_set_props, independently of field names; rendering, undo/redo and incremental/full save/reopen are covered. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M12 #2589: Active XFA skips PDF-container fallback scripts while retaining requested messages and saved scripts; ordinary/static/unlaid-out documents and explicit console/field calls keep their existing behavior. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M7 #2592: Styled fallback fonts batch up to 240 glyphs per actual face and retain source styles. Budget refusal and distinct same-BaseFont descriptor weights have mutation-checked regressions; coverage and complex mixed runs remain limited. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M7 #3187: Added-image automation normalizes extreme signed rotation angles before combining them with the current orientation; integer bounds, history, pixels, save/reopen and MCP have regressions. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M12 #2569: Growable multiline XFA text reflows after edits, with undo/redo, save/reopen and print coverage; oversized fields still become read-only page text. Structured-data synchronization warnings retain accepted whitespace without relayout from stale data. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M12 #2572: Every repeated page-master button resolves its own field to the shared XFA click script, including print buttons. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M12 #2570: Dynamic XFA rich-text fields carry exData/maxLength into AcroForm MaxLen for reported and enforced Unicode character limits, retained after save/reopen. Estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M4 #3309: bounded iterative named-destination pruning on page deletion; estimates unchanged)
+> **Last reviewed:** 2026-10-18 - **Last updated:** 2026-10-18 - **Change:** minor (M1 #2658: macOS atomic saves retain destination extended attributes, including Finder tags, and reject partial resource-fork reads after size changes. Metadata failures retain the original PDF and unsaved edit. Estimates unchanged)
PdfCraft's one-page summary: how close it is to Adobe Acrobat Pro's offline feature set, and what
comes next. Adobe's cloud services (Document Cloud, Acrobat Sign requests, shared review, the AI
@@ -31,7 +97,7 @@ and add a line to the [progress log](#progress-log); when a gap closes, remove i
|---|---|---|
| **Feature breadth** | **≈ 67%** tier-weighted (56.9% unweighted: 423 shipped + 74 partial of 808; P0 94.2%) | measured, `parity/acrobat-features.toml` |
| Feature breadth, mainstream practitioner | ≈ 70% tier-weighted (63.2% unweighted; P0 95.3%) | measured ([split](docs/target-app-parity.md#mainstream-practitioner-vs-full-acrobat-pro)) |
-| **Ready for real work**, full Acrobat Pro | **≈ 49%** (45–53%) | estimated, weighted sum over [dimensions](#by-dimension) |
+| **Ready for real work**, full Acrobat Pro | **≈ 50%** (45–53%) | estimated, weighted sum over [dimensions](#by-dimension) |
| **Ready for real work**, mainstream practitioner | **≈ 55%** (50–60%) | estimated ([split](docs/target-app-parity.md#mainstream-practitioner-vs-full-acrobat-pro)) |
| **Ready for real work**, essentials user | **≈ 66%** (60–70%) | estimated ([method](docs/target-app-parity.md#essentials-user)) |
| Remaining to **beta** | ≈ 400–700 Opus 5.5 agent-hours | estimated |
@@ -40,17 +106,17 @@ and add a line to the [progress log](#progress-log); when a gap closes, remove i
**Why alpha:** all six of Acrobat Pro's everyday workflows can be completed end to end on macOS
(the [alpha gate](docs/roadmap.md#alpha-gate)), and users praise them (7.6k stars, ≈ 217k downloads
of 0.4–0.5, switching reports such as #179). Two are only partial: editing (no CJK/RTL) and convert
-and share (password-protected files we write don't open in Acrobat or Reader, #774; no in-app
-Office→PDF; Word export loses layout, #773). Those, unmeasured quality against Acrobat, the borrowed
-`hayro` renderer, no printing on Windows (#756) and 245 open issues keep it far from beta.
+and share (no in-app Office→PDF; Word export loses layout, #773; password-protected files open in
+Acrobat since #836, #774). Those, unmeasured quality against Acrobat, the borrowed `hayro` renderer,
+and 245 open issues keep it far from beta.
### Readiness by audience
| Audience | Ready | Opus 5.5 agent-hours to ≈ 95% | Work that dominates |
|---|---|---|---|
-| Full Acrobat Pro (ready for real work) | ≈ 49% | ≈ 780–1,400 h (≈ 300–550 h wall clock with 3–5 agents; 60–70% parallelizes) | Own renderer and fidelity harness, editing existing content, OCR and Office conversion, Preflight and PDF/A/X/UA, accessibility tagging, signatures for institutions |
-| Mainstream practitioner | ≈ 55% | ≈ 500–900 h (≈ 200–400 h wall clock; ≈ 60% parallelizes) | Rendering fidelity, editing existing text (CJK, RTL, subsets), conversion (Word layout, Excel, PowerPoint, Office→PDF), OCR languages, Windows printing, the bug backlog |
-| Essentials user | ≈ 66% | ≈ 180–330 h (≈ 90–180 h wall clock; ≈ 50% parallelizes) | Rendering fidelity on everyday files, Windows printing, launch and GPU stability, encrypted output Acrobat opens (#774), simple text fixes, Word export layout, Chinese UI glyphs |
+| Full Acrobat Pro (ready for real work) | ≈ 50% | ≈ 780–1,400 h (≈ 300–550 h wall clock with 3–5 agents; 60–70% parallelizes) | Own renderer and fidelity harness, editing existing content, OCR and Office conversion, Preflight and PDF/A/X/UA, accessibility tagging, signatures for institutions |
+| Mainstream practitioner | ≈ 55% | ≈ 500–900 h (≈ 200–400 h wall clock; ≈ 60% parallelizes) | Rendering fidelity, editing existing text (CJK, RTL, subsets), conversion (Word layout, Excel, PowerPoint, Office→PDF), OCR languages, the bug backlog |
+| Essentials user | ≈ 66% | ≈ 180–330 h (≈ 90–180 h wall clock; ≈ 50% parallelizes) | Rendering fidelity on everyday files, launch and GPU stability, simple text fixes, Word export layout, Chinese UI glyphs |
Hours are calibrated as in [Effort and calibration](docs/target-app-parity.md#effort-and-calibration) (≈ 1k kept lines per agent-hour for new features, 3–10× slower for hardening and fidelity). The audiences are nested subsets, so essentials ≤ mainstream ≤ full.
@@ -63,13 +129,13 @@ Hours are calibrated as in [Effort and calibration](docs/target-app-parity.md#ef
| File formats and conversion | ≈ 40% | 12% | 120–220 (within features) | [file-format-parity.md](docs/file-format-parity.md) |
| PDF specification and standards | ≈ 60% | 8% | 150–260 (within features) | [pdf-spec-parity.md](docs/pdf-spec-parity.md) |
| Hardware | ≈ 35% | 4% | 25–50 | [hardware-parity.md](docs/hardware-parity.md) |
-| Localization | ≈ 59% | 5% | 35–60 | [localization-parity.md](docs/localization-parity.md) |
+| Localization | ≈ 68% | 5% | 35–60 | [localization-parity.md](docs/localization-parity.md) |
| Performance | ≈ 40% | 6% | 25–45 | [gaps.md](docs/gaps.md) gap 13 |
| Stability | ≈ 50% | 8% | 45–80 | [gaps.md](docs/gaps.md) gap 6 |
| Platforms | ≈ 70% | 5% | 15–30 | [hardware-parity.md](docs/hardware-parity.md#platforms) |
| Ecosystem and plug-ins | ≈ 30% | 1% | 10–20 (within features) | [gaps.md](docs/gaps.md) |
| AI features | ≈ 0% (in scope: local providers) | 1% | 20–40 (within features) | [gaps.md](docs/gaps.md) gap 23 |
-| **Total (weighted sum)** | **≈ 49%** | 100% | **≈ 780–1,400** | |
+| **Total (weighted sum)** | **≈ 50%** | 100% | **≈ 780–1,400** | |
## Features
@@ -94,26 +160,27 @@ What's strong and missing in each: [target-app-parity.md](docs/target-app-parity
## Languages
-Measured from `crates/ui-egui/src/i18n/*.tsv` (2,143 keys). Detail and script notes:
-[localization-parity.md](docs/localization-parity.md).
+Twelve key languages (historical % snapshot vs 2,143 keys, except Vietnamese, Brazilian
+Portuguese and Spanish vs the current union). Detail and script notes: [localization-parity.md](docs/localization-parity.md).
| Language | Code | Strings | Status |
|---|---|---|---|
| English | `en` | 100% | full |
-| Simplified Chinese | `zh-hans` | 97.4% | partial (no Hans UI face in releases, #826) |
-| Spanish | `es` | 95.5% | partial |
+| Simplified Chinese | `zh-hans` | 97.4% | partial (native LXGW WenKai Lite; no Hans face in the web build, #826) |
+| Spanish | `es` | 100% of current union | partial (dialogs / tooltips; no help) |
| Hindi | `hi` | 0% | none |
-| Arabic | `ar` | 100% | partial (layout not mirrored) |
+| Arabic | `ar` | 100% | partial (logical catalog, explicit RTL labels, mirrored stock chrome; native/browser/IME workflows unqualified) |
| French | `fr` | 99.3% | partial |
-| Portuguese (Brazil) | `pt-br` | 99.4% | partial |
+| Portuguese (Brazil) | `pt-br` | 100% of current union | partial |
| Indonesian | `id` | 0% | none |
| Japanese | `ja` | 99.1% | partial |
| German | `de` | 99.3% | partial |
| Korean | `ko` | 0% | none |
-| Vietnamese | `vi` | 0% | none |
+| Vietnamese | `vi` | 100% of current union | partial (dialogs / tooltips; no help) |
-Also shipped: Traditional Chinese, Russian, Bulgarian, Telugu, Hungarian, Ukrainian, Italian
-(94–100%) and Czech (menus only): **8 more languages**.
+Also shipped: Traditional Chinese, Russian, Bulgarian, Telugu, Hungarian, Ukrainian, Italian,
+Kazakh, Polish, Slovenian, Greek, Turkish, Lithuanian, Romanian and Czech: **15 more catalogs**
+(24 interface languages including English).
## Upcoming
@@ -121,8 +188,8 @@ Ranked; detail and the full milestone table in [docs/roadmap.md](docs/roadmap.md
| Rank | Milestone | Estimate (h) |
|---|---|---|
-| 0 | Convert and share: encrypted output opens in Acrobat (#774), Create PDF from Office, Word export that keeps layout (#773) | 40–70 |
-| 1 | Backlog and platform: crash and wrong-result reports, Windows printing (#756), Chinese UI face (#826) | 65–120 |
+| 0 | Convert and share: Create PDF from Office, Word export that keeps layout (#773) | 32–55 |
+| 1 | Backlog and platform: crash and wrong-result reports, Chinese web UI face (#826) | 50–90 |
| 2 | Fidelity harness against Acrobat and the renderer decision (M2; owner decision on #841) | 110–190 |
| 3 | Editing existing content (M7) | 100–180 |
| 4 | OCR languages and Office export/import (M10) | 95–175 |
@@ -133,12 +200,305 @@ Ranked; detail and the full milestone table in [docs/roadmap.md](docs/roadmap.md
## Progress log
+- **2026-10-27 (M10, OCR models):** Model staging downloads and verifies the ONNX pair after the upstream RTEN URL brownout; runtime discovery prefers complete ONNX pairs per directory, retains complete RTEN fallback and preserves directory precedence.
+- **2026-10-24 (M10, #4158 partial):** Word, HTML, RTF and PowerPoint export keep a block that continues another on its line (an italic case name, a link, a superscript) as a run in its own style inside that paragraph, with the source's word space, instead of a paragraph of its own. Style changes that wrap onto the next line still split paragraphs (the reading blocks keep style boundaries). Estimates unchanged.
+- **2026-10-24 (M3, window move on Wayland, #3970 follow-up):** After a move or resize by PdfCraft's own title bar or edges, the button release given back to egui goes before the pointer leaving the window, so hover no longer sticks at the old place until the pointer moves. Found by CodeRabbit in review of #3970; a unit test covers it. Estimates unchanged.
+- **2026-10-24 (M14, #4253):** The annotation quick bar remembers Keep tool selected across restarts, including unpinning. Old and malformed settings keep safe defaults; the opt-in UI control channel reads and changes the same preference. Estimates unchanged.
+
+- **2026-10-23 (M7, #4280):** Edit text names each standard stand-in font after its face (`PCEdTimesBold`, ...) instead of one shared `PCEdHelv`. Rewriting a bold paragraph whose subset lacks an accent no longer repoints the paragraphs set earlier in a regular stand-in at Times-Bold, and the editor's frame stays on the paragraph being edited. Pages saved by older builds keep their shared name and are not repaired. Estimates unchanged.
+- **2026-10-23 (M8, #3205 follow-up):** Phone-pattern redaction matches complete labelled Italian geographic numbers such as `Tel. +39 0426/123456`, with synthetic matcher and mark/apply/save/reopen coverage; unlabelled international slash numbers remain unsupported.
+- **2026-10-23 (M7, #2636 partial):** A new `PasteContent` edit pastes an added text box or image copied in the same document or another, keeping its style, picture, turns, flips and crop, as one undo step; `content_copy` drives it headlessly. A paste lands beside earlier copies (18 pt steps) and stays on the page. A pasted image reuses its picture object in its own document and after the first paste into another; there a colour profile is dropped and CMYK colours stored losslessly are turned to RGB. The desktop keys and menus follow in separate PRs. Estimates unchanged.
+- **2026-10-23 (M11, optimizer resolution):** Image downsampling includes each page's `/UserUnit` scale, preserving images already below the physical resolution threshold, including shared nested forms.
+ Synthetic measurement and optimization regressions cover direct and indirect units and page-local defaults.
+ Estimates unchanged.
+- **2026-10-23 (M10, Word table widths):** Word export sizes each cell from the grid columns it spans, keeping unequal columns and cells after a merged cell consistent with the table grid.
+- **2026-10-23 (M10, table continuation text):** Office exporters retain text from table slots covered by another cell's span as paragraph text.
+ Synthetic regressions check every input fragment survives exactly once in Word, HTML, RTF and PowerPoint, while ordinary superscripts stay in their table cells.
+- **2026-10-23 (M10, image export):** Soft-mask Decode intervals preserve partial opacity in Export all images and Save Image As.
+ Synthetic regressions cover direct and indirect ranges, inverted/subrange alpha, packed masks, JPEG masks and unchanged image component Decode.
+- **2026-10-23 (M10, print resources):** Vector printing preserves original page artwork when existing XObjects use annotation resource names.
+ The regression checks two distinct appearances, inherited resources, print/reopen pixels and unchanged source data.
+ Estimates unchanged.
+- **2026-10-21 (M3, window resize and move on Wayland):** With PdfCraft's own title bar on GNOME/Wayland, a second resize by a window edge, or a second move by the empty tab strip, works straight after the first; it waited for a click inside the window, because the compositor keeps the button's release from egui. A unit test covers the release given back; checked by hand in a test build. Estimates unchanged.
+- **2026-10-22 (M4, #3916 partial):** Document edits and Undo/Redo cancel an Organize page drag. Pointer-release regressions check exact page order and save/reopen.
+- **2026-10-22 (M10, #3752 paper):** CUPS jobs ask for the chosen paper in every size. The 13 sizes the Print dialog sent no paper for (A6, A0–A2, ARCH, ANSI C–E) use PWG 5101.1 names, checked against a synthetic PPD with `cupsfilter`, and `doc_print` to a printer sends the paper too. The macOS tray half (Auto Select instead of the PPD's default tray) is a craft-print change that needs a pin bump here. Estimates unchanged.
+- **2026-10-22 (M14, macOS association recovery candidate):** Successful desktop open/save/sign can queue recovery of an existing per-file binding to the running PDFCraft bundle through NSWorkspace. Metadata-only watcher changes retain undo and avoid false overwrite prompts; real same-length/same-mtime edits remain protected. Rebased on 0.12.0 and reuses #3042's shared atomic metadata preservation; the bounded recovery parser does not narrow save limits. Prior native Preview TEST-signature and Finder workflows passed on macOS 27.0.1; other versions remain unqualified. Estimates unchanged.
+- **2026-10-13 (M7, free image rotation):** A selected page image has a rotate knob (Shift: 15 degree steps) and `image_edit` a `rotate_by` action; the angle is written as one undoable `cm`. Snapping to page edges while moving is in #1740; resize snapping is not done. Estimates unchanged.
+
+- **2026-10-20 (M4, initial view):** Window and interface options read indirect boolean ViewerPreferences values. Synthetic regressions cover true/false, direct/indirect preference dictionaries and save/reopen; malformed entries retain false defaults. Estimates unchanged.
+- **2026-10-20 (M3, #3535):** Escape with a menu open closes the menu and keeps the text selection; the next Escape clears it, as before. One keypress used to do both. A synthetic UI regression checks it. Estimates unchanged.
+- **2026-10-16 (M3, close prompt keyboard):** The "Save changes?" prompt opens with Save chosen (Enter saves, as before) and the arrow keys and Tab / Shift+Tab move the choice to Cancel or Don't save, shown with a focus ring; Enter or Space press the chosen button and Escape still cancels. Before, Enter always saved whatever was Tab-focused. Estimates unchanged.
+- **2026-10-21 (M3, #3808):** Page thumbnails in the Inspector can be resized independently from the document and Organize, with a slider, buttons and `thumbnail-zoom` control option. Selection, page following and reload are covered by regressions. Estimates unchanged.
+- **2026-10-22 (M5, comment threads):** Replies join the comment their `/IRT` references, not every comment sharing its `/NM`; PyMuPDF names each page's first comment `fitz-A0`, so all replies used to land under page 1. The Comments header counts comments without their replies, with the number of replies in small text under it (in every catalogue), and a reply's thread line runs from the avatar above it to its own. A reply to a reply shows in its thread in the panel too (it was listed nowhere), an `/IRT` that leads to no comment (itself, a loop, a pop-up, an unlisted object) leaves its annotation a comment of its own instead of hiding it (a status or checkmark that leads nowhere is listed nowhere), and a Replace Text caret isn't counted as a reply. The comment tools refuse an `id` several comments share instead of acting on the first (page 1's), and take `page` + `index` for those; `comment_list` reads a status or checkmark from the annotation it was set on, as the panel does, and reports a reply's own on the reply. UI, engine and automation regressions cover it. Estimates unchanged.
+- **2026-10-22 (M2, #3107 / PR #3438):** Inline-image parsing falls back to the existing EI heuristic when missing declared samples, headers or terminators exceed the content-window budget, instead of waiting for an impossible allocation. Exact-length parsing for available samples and ordinary large streamed images is retained. Estimates unchanged.
+- **2026-10-21 (M14, Brazilian Portuguese):** Completed the `pt-br` catalog against the current 2,674-key union, including signature validation and accessibility messages; no build or compilation run. Localization remains partial because help and unpredictable engine/OS error details are not translated.
+- **2026-10-21 (M14, #3557):** Preferences: the OK button stays below the scrolling settings instead of being the last thing in them, so it is in reach in a short window.
+
+- **2026-10-19 (M11, #2178):** Optimize checks image and soft-mask dimensions and byte counts before decoding; hostile-dimension regressions pass. Estimates unchanged.
+
+- **2026-10-20 (M11, #3507):** Image merging keeps trailing comments, split operands and graphics state across content streams. Synthetic tool tests check saved text, rendered regions and exact image rows.
+
+- **2026-10-17 (M8, gap 6, #2662):** A filled cover over a long line counts when it hides half of any one word, not only 40% of the line's words or box, so a black box over one number in a long line — or an unapplied redaction mark over it — no longer audits clean while the number is still extractable; a sliver under half of every word it touches and under 40% of the line is still not flagged
+- **2026-10-13 (M10, #1757):** Office export keeps each dotted-leader contents entry in one paragraph, with its page number, instead of inferring table cells from its separate text objects.
+- **2026-10-22 (M6, calculation scripts):** The Calculate tab and a rename read simplified field notation only from a comment, where Acrobat writes it: a string that spells `BVCALC … EVCALC` is no longer taken for the notation, or rewritten by a rename. A `/` after the condition of `if`, `while`, `for` or `with` starts a regular expression, so a rename no longer rewrites a name inside one, and a quote inside one no longer hides the `getField` calls after it. Both found in review of #3550. A `//` comment ends at `\r`, U+2028 or U+2029 as well as `\n`, so in a script with `\r` line endings the code after one is no longer hidden from a rename, or taken for the notation. Estimates unchanged.
+- **2026-10-20 (M6, calculation order page):** Prepare a form ▸ Calculation order, a page of its own, lists the calculated fields in the order they calculate with their formulas and values, moved with Up/Down arrows (as Acrobat's Set Field Calculation Order), Alt+↑/↓ or by dragging. A card says what is wrong with the order and holds Fix order; a loop has a card of its own that opens one of its formulas. On the page, each calculated field shows its step, and arrows show what the field in focus reads and what reads it. Estimates unchanged.
+- **2026-10-20 (M6, calculation order):** The order a form's fields calculate in (`/CO`) is read, checked, fixed and set headlessly with `form_calculation_order`: it says which fields read one calculated later (they show stale values), which read each other in a loop, and which the PDF's order leaves out; Fix order moves only what must move, in one undo step, and the form recalculates. Editing a formula no longer moves its field to the end of the order, and a field the order lists twice calculates once. Estimates unchanged.
+- **2026-10-20 (M2, #3574):** Forms without Resources use page Properties for ActualText and layer visibility. Synthetic tests cover boundaries, nested/shared forms, and save/reopen. Estimates unchanged.
+- **2026-10-20 (M2, PR #3348 review):** Tracking samples retain short repeated punctuation (up to four glyphs), keeping tracked ellipses intact and searchable while longer TOC leaders still preserve title word spaces. Synthetic regressions cover isolated and surrounded ellipses. Estimates unchanged.
+- **2026-10-20 (M2, #3601):** A missing spacing glyph in an OpenType substitute uses its ordinary-space glyph. Synthetic Japanese CID renderer tests check blank spaces, `/W` and `/DW` placement, and unchanged Unicode extraction. Font selection and embedded fonts are unchanged. Estimates unchanged.
+- **2026-10-20 (M12, #3673):** Character encoding accepts Identity-H/V fonts with Adobe CJK collections and recognizes predefined non-Identity CMaps independently. Unknown CMaps and foreign registries remain refused; synthetic checker and read-only automation regressions passed after failing before the fix. Per-glyph mapping validation and embedded-font extraction remain separate. Estimates unchanged.
+- **2026-10-19 (M6, renames keep formulas):** Renaming a field renames it in every calculation that reads it, in the same undo step: `AFSimple_Calculate` field lists, simplified field notation (the comment and the JavaScript after it) and `getField` calls naming it in one string literal; the rest of each script is kept as written. A sum used to drop the renamed field, notation read it as 0 and a script kept a stale value. Field Properties says how many formulas changed and `form_set_props` lists them as `formulas_updated`. Names built at run time and other events' scripts are not rewritten. Estimates unchanged.
+- **2026-10-19 (M6, text field table):** Prepare a form ▸ Text field table drags out an area and adds rows and columns of named text fields as one undoable edit, laid out on the page as displayed, with a live preview, per-column name patterns and widths, and refusal before anything is added when a cell would be too small or a name taken; `form_add_field_table` does the same headlessly. `form.multiple-copies` is partial: copying an existing field into a grid is still missing. Estimates unchanged.
+
+- **2026-10-16 (M7, #2516):** A paragraph number from `text_paragraphs` keeps naming the paragraph it listed after edits regroup the page: `text_edit`, `text_edit_layout` and `page_render`'s `hide_text_block` find it again by its text and box, and refuse one that was merged into a neighbour (the edited paragraph included) instead of rewriting the paragraph that took its number (`stale_paragraphs` lists the numbers gone). The inline editor's switch-paragraph click holds the same key. No stable identity across save and reopen yet (#2508).
+- **2026-10-19 (M7, #3591):** A background added to a page that already has one is painted over the old one instead of going under it and staying hidden. Behind the content, backgrounds come first, in the order added, and then behind-content watermarks, so a watermark added after a background no longer disappears. Synthetic regressions in `crates/edit` check the order. Estimates unchanged.
+- **2026-10-19 (M2, radial luminosity masks):** Added synthetic radial-fade coverage for the existing masked-gradient fix (#2132): centre, midpoint, antialiased clip and per-pixel shading reference, including previews, scales and tiles. Removing the existing native-gradient mask guard reproduces an opaque midpoint; restoring it passes. No new renderer behavior or estimate change.
+- **2026-10-20 (M6, #3502):** Form detection preserves comments across content streams and does not add fields over rectangles hidden by those comments. Synthetic tests cover visible controls, graphics state, and saved field inventories. Estimates unchanged.
+- **2026-10-20 (M6, #2273 / PR #2279):** Rebased the field-highlight default and Appearance preference onto main, retaining secured-form parity evidence and updating secured AcroForm/XFA toggle expectations. Build and test validation delegated to GitHub CI. Estimates unchanged.
+- **2026-10-20 (M5, reshape lines):** A line or arrow could only be moved after it was drawn; its length and angle stayed. A selected line, connected lines, polygon or cloud now has a handle on each end or corner: dragging one reshapes it (Shift holds it to 45°), as one undo step, with the new shape drawn while dragging. `pdfcraft_annot::set_points`, `Edit::ReshapeAnnotation`, `comment_edit points`; comment lists carry the points. Estimates unchanged.
+- **2026-10-20 (M3, #3620):** Overlapping comment hover uses the original annotation index independently of spatial inspection order. A synthetic UI regression covers different annotation upper edges. Estimates unchanged.
+
+- **2026-10-20 (M3, #3541/#3620):** Comment hover follows the individual marked lines instead of the enclosing multiline rectangle, and overlapping comments follow paint order. Synthetic UI regressions cover all four text-markup kinds, page/view rotations, neighboring highlights, legacy rectangle fallback and unchanged PDF bytes. Estimates unchanged.
+- **2026-10-20 (M10, #3532 partial):** Vector printing retains existing widget artwork when its appearance lacks Subtype. A print-owned copy adds Form dispatch metadata. The source stream and all explicit subtypes stay unchanged. Synthetic source/output raster checks cover resources, selected/shared appearances, placement, flags and content modes. Appearance regeneration and physical printer validation remain outside this fix. Estimates unchanged.
+
+- **2026-10-20 (M5, arrow keys move comments):** With a comment selected, the arrow keys move it a screen pixel and ⌘/Ctrl or Shift and an arrow ten, instead of scrolling the view or turning the page; up is up on screen at any zoom and rotation, and each press is one undo step. Text markup and locked comments stay put. Estimates unchanged.
+
+- **2026-10-19 (M14, #3373):** The main menu and its long submenus scroll in short windows, keeping their commands reachable. Estimates unchanged.
+
+- **2026-10-19 (M3, #3387):** Save-prompt shortcuts yield to later consent and utility dialogs; a synthetic UI regression checks that an edited document stays open. Estimates unchanged.
+
+- **2026-10-18 (M3, PR #3101 review):** Gap changes in Organize Pages preserve document scroll position; menu and control changes apply to both comparison panes without changing unrelated tabs. Three synthetic UI regressions were observed failing before the fixes. Readiness estimates unchanged.
+
+- **2026-10-18 (M3, PR #3101):** Optional gapless continuous page display with persisted defaults and UI control support; both new labels translated in all 22 catalogs. Rebased onto current main, preserving navigation and rendering fixes. Readiness estimates unchanged.
+
+- **2026-10-18 (M10, #3120):** Export to Word, PowerPoint, HTML and RTF reads text from form XObjects nested as deep as the renderer draws them (50 levels), and up to 50 000 forms a page (the renderer's budget for nested ones); it stopped at 12 levels and 4 096 forms and left the rest out silently. A page past those limits is listed in `doc_export_office`'s `truncated_pages`, with a warning. Estimates unchanged.
+
+- **2026-10-18 (M5, PR #1971 review):** Nested FDF annotation values that identify a source `/Page` or `/Pages` dictionary become null at every copy depth. A synthetic three-page PDF saved and reopened before export verifies that destination actions cannot pull source page content into the FDF, while unrelated nested metadata and shared references remain intact. FDF import semantics, copied-graph limits and estimates are unchanged.
+- **2026-10-15 (M5, PR #1971 refresh):** Nested FDF annotation values retain shared or cyclic copied graphs. Discovery borrows direct values and records annotation positions with lazy array owners; retained entries are budgeted before cloning. Synthetic stress fixtures include repeated aliases and saved-PDF cache eviction. Limits cover the copied graph; source parsing and page discovery retain their existing limits, with no total source-memory bound. FDF import semantics and estimates are unchanged.
+- **2026-10-13 (M5, nested FDF values):** Comment export copies and renumbers nested indirect values, retaining geometry, colours, borders and shared graphs. Graph/data limits return an error before the destination is written; synthetic saved-PDF and automation exchange regressions. Estimates unchanged.
+- **2026-10-18 (M2, #3086):** Text extraction estimates letter tracking without repeated punctuation gaps so dotted TOC leaders do not swallow word spaces. Synthetic PDF regressions cover leader lengths, phrase search and selection; strongly tracked text stays intact. Estimates unchanged.
+
+- **2026-10-18 (M6, #2892):** Push-button normal labels are editable per widget through Options and form_set_props, independently of field names; rendering, undo/redo and incremental/full save/reopen are covered. Estimates unchanged.
+
+- **2026-10-18 (M7, #3212):** Headers, Bates numbers, watermarks and added text stay visible after unfinished marked content, with original content preserved.
+- **2026-10-18 (M12, #2589):** Active XFA skips PDF-container fallback scripts while retaining requested messages and saved scripts; ordinary/static/unlaid-out documents and explicit console/field calls keep their existing behavior. Estimates unchanged.
+- **2026-10-18 (M7, #2592):** Styled fallback fonts batch up to 240 glyphs per actual face and retain source styles. Budget refusal and distinct same-BaseFont descriptor weights have mutation-checked regressions; coverage and complex mixed runs remain limited. Estimates unchanged.
+- **2026-10-18 (M7, #3187):** Added-image automation normalizes extreme signed rotation angles before combining them with the current orientation; integer bounds, history, pixels, save/reopen and MCP have regressions. Estimates unchanged.
+- **2026-10-18 (M12, #2569):** Growable multiline XFA text reflows after edits, with undo/redo, save/reopen and print coverage; oversized fields still become read-only page text. Structured-data synchronization warnings retain accepted whitespace without relayout from stale data. Estimates unchanged.
+- **2026-10-18 (M12, #2572):** Every repeated page-master button resolves its own field to the shared XFA click script, including print buttons. Estimates unchanged.
+- **2026-10-18 (M12, #2570):** Dynamic XFA rich-text fields carry exData/maxLength into AcroForm MaxLen for reported and enforced Unicode character limits, retained after save/reopen. Estimates unchanged.
+- **2026-10-19 (M4, #3309 review):** Page deletion keeps working with 60,000 named destinations, without a name-count traversal limit. Synthetic regressions verify every surviving target after deletion and restoration of the deleted page and its destinations by undo/redo, full/incremental save/reopen and unchanged rendering. Estimates unchanged.
+- **2026-10-18 (M4, #3309):** Deleting a page prunes named destinations without recursive calls. Cyclic and shared indirect nodes are visited once. Synthetic deep/cyclic graph, save/reopen and automation regressions cover the change. Estimates unchanged.
+- **2026-10-18 (M1, #2658):** macOS atomic saves retain destination extended attributes, including Finder tags, and reject partial resource-fork reads after size changes. Metadata failures retain the original PDF and unsaved edit. Estimates unchanged.
+- **2026-10-15 (M7, Edit text caret):** In a text region that mixes sizes (a 24 pt title over 12 pt lines), the inline editor's caret on a small row was as tall as the region's first size and reached into the row below: egui draws the caret at least one row of the text field's font tall, and that font had the paragraph's first size. The field's font is now half the region's smallest size, so each row's own height decides. Kittest regression; checked in the app on a real document. Estimates unchanged.
+- **2026-10-16 (M3, #2781):** The Pages panel follows the current page, as Acrobat's page thumbnails do: going to a page whose thumbnail is out of sight (scrolling, Page Down, Go to page, a bookmark) scrolls the panel just enough to show it. A thumbnail already in view, or clicked, leaves the panel where it is, and a page change while the user scrolls the panel or drags thumbnails does not move it. Estimates unchanged.
+- **2026-10-16 (M12, #1645):** CLI info, text and render use the engine's dynamic XFA layout rather than placeholder pages. Synthetic two-page and encrypted-form regressions cover counts, text, pixels, copy permissions and unchanged input bytes. Estimates unchanged.
+
+- **2026-10-18 (M4, PR #1919 review):** repeated page indices apply each rotation to the latest page-local value, preserving indirect/inherited angles. Synthetic adjacent/interleaved duplicates retain siblings and page contents through incremental and full saves. Estimates unchanged.
+- **2026-10-15 (M4, #1919 refresh):** Integrated upstream `99941daa` while retaining the indirect page rotation correction and all upstream progress. Only independent documentation conflicts required resolution; focused production and test files are unchanged from the previously green CI head. Estimates unchanged.
+- **2026-10-18 (M3, #3149):** Page replacement cancels render demand collected for the previous geometry; all viewer raster upload paths reject empty or oversized textures before cache eviction. Synthetic regressions reproduce the reported 1880×2350 upload at a 2048 limit, retain cached images and unsaved edits, and resume bounded backdrops and tiles. Estimates unchanged.
+- **2026-10-19 (M3, #3360):** Switching between Read and the docking workspace retains the current document’s scroll position at fixed zoom, including within-page position; separate tabs retain their own offsets. Estimates unchanged.
+- **2026-10-18 (M8, #1350):** Integrated current main while preserving content-stream comment boundaries. Hidden-text cleanup retires unused named replacement descriptions on rewritten pages and forms, including inherited/shared resource holders, without removing descriptions still used by surviving content. Synthetic saved-byte and preservation regressions cover the cleanup. Estimates unchanged.
+- **2026-10-17 (M4, #2997):** Dragging page thumbnails in the Organize grid with Ctrl held (Option on macOS) drops copies at the gap instead of moving the pages: a "+" badge sits by the pointer, the copies land at the gap selected, and one undo step ("Duplicate pages") takes them out again. `page_duplicate` takes `at` (1-based, where the first copy goes; left out, after the last of them) so agents can drive the same thing, and the UI control channel's `ui.drag` modifiers now reach gestures that read the input state. Estimates unchanged.
+- **2026-10-15 (M6, AcroForm XML text):** Plain AcroForm XML imports retain all direct text around comments and processing instructions, including CDATA and character references. Synthetic regressions verify exact values and unknown catalog data after incremental and full save/reopen. Nested-element and XFA interpretation are unchanged. Estimates unchanged.
+- **2026-10-15 (M6, #1917 refresh):** Integrated upstream `99941daa` while retaining the XML/XFDF attribute whitespace correction and all upstream progress. Only independent documentation conflicts required resolution; focused production and test files are unchanged from the previously green CI head. Estimates unchanged.
+- **2026-10-15 (M1, #2267 refresh):** Integrated upstream `99941daa` while retaining the raw-deflate fallback correction and all upstream progress. Only independent documentation conflicts required resolution; focused production and test files are unchanged from the previously green CI head. Estimates unchanged.
+- **2026-10-16 (M10, #1201 partial):** Lossless image export applies each component's Decode pair. Indexed values round and clip before palette lookup. Color-key masks keep raw samples. The existing 16-bit precision limit remains. JPEG and mask Decode, ICC transforms, and calibrated colors remain outside this fix. Estimates unchanged.
+- **2026-10-16 (M3, #2739):** Wrapped revision buttons stay above Binding in Document Properties. A synthetic regression checks control bounds and opens a saved revision at two viewport widths. Estimates unchanged.
+- **2026-10-19 (M7, tracked text):** Editable paragraphs and object labels distinguish repeated glyph tracking from word gaps in TJ arrays and separately positioned glyphs. Synthetic regressions cover character spacing, horizontal scaling, rotated baselines, larger word gaps, and rows of one-glyph words or cells (inferred tracking is capped at half an em, so `a b c` and digit or Y/N columns keep their spaces). Estimates unchanged.
+- **2026-10-16 (M5, #2669, item 5):** The Comments panel groups replies by name and counts all page roots once per frame. Estimates unchanged.
+- **2026-10-16 (M7, #2140):** Header & footer (and Bates numbering, which uses the same dialog) can shrink the page content so the header and footer don't cover it: the original content is scaled evenly into the band they leave free, centred across, also on rotated pages; Remove and Update take the scaling away, and margins that leave no room are refused. Dialog checkbox with a preview of the band, `shrink` on `doc_header_footer`, all catalogs. Annotations and added text and images are not moved yet. Estimates unchanged.
+- **2026-10-20 (M14, Spanish catalog gaps):** `es.tsv` gains the 143 `(context, English)` keys the other catalogs carried and it was missing, so Spanish covers the whole bundled key union like Lithuanian and Vietnamese: calendar months and weekdays, the `certificate` context, X.509 key usages, signature-revision and digital-ID lines, password validation, eight plural messages, the combine-from-folder strings, the rendering and stale-file notices and the shortcut-spelled tooltips. Counts in `localization-parity.md` re-measured against the current union (`vi` restated against it for the same reason). Status stays `partial`: no translated help, and OS details stay outside the catalog. Estimates unchanged.
+- **2026-10-16 (M14, localization):** Czech goes from menus-and-dialogs to the whole surface: 2,674 entries after adding the ~220 keys the other catalogs had -- the sentences the engine words (signature details, accessibility findings and report, PDF/A problems, pages to print, history labels), the date picker's weekday heads, the certificate viewer's fields and shared buttons. "Tag" is *tag* throughout (the Tags panel said *značky*, which is also a redaction mark), and "{n} tags" no longer reads "1 značek". Two new catalog tests. Estimates unchanged.
+- **2026-10-16 (M5, #2583, #1869):** A sticky note on a page with `/Rotate` is drawn upright, with its top-left where it was placed. Notes are saved with the NoRotate flag, and the renderer now honours it: the appearance is turned against the page's rotation about the upper-left corner of `/Rect`, which stays put (ISO 32000-2 §12.5.3; vendored hayro-interpret patch 37). Attachment icons follow the same rule. Selection, hover, the edit composer, the Comments panel's flash and the `comment_list` and `doc_info` rectangles use the drawn box, and `comment_add` anchors an icon's displayed top-left at `at`. Estimates unchanged.
+- **2026-10-16 (M11, #1201):** Optimize decodes a JPEG with its colour transform: an Adobe APP14 marker's flag, else the filter's `/ColorTransform` (ISO 32000-2 §7.4.8). An RGB JPEG stored untransformed (`/ColorTransform 0`, no marker) used to be converted from YCbCr anyway and came out in other colours, recompressed or merged from strips; it now keeps them. A JPEG whose marker and `/ColorTransform` disagree, or whose components are named R, G and B without `/ColorTransform 0`, is left as it is, since readers differ on it. Estimates unchanged.
+- **2026-10-15 (M2, gap 12):** `cargo xtask text-oracle` scores reading order as well as word F1: the longest common subsequence of the two word sequences over the longer one. F1 is a bag of words and cannot see order at all -- measuring #2431, a change that moves text and nothing else, it called 26 of the 29 files whose output changed identical, where the order score separated 18 improvements from 6 regressions. Reports, does not gate; a disagreement with Poppler, not a verdict. Estimates unchanged.
+- **2026-10-15 (M2, #2305 follow-up):** WinAnsiEncoding 0xA0 and 0xAD and MacRomanEncoding 0xCA extract as the ordinary space and hyphen Annex D.2 names them, in the vendored hayro tables (patch 30) as well as `crates/fonts`, so search, copy and redaction see characters that were hidden behind U+00A0 and U+00AD. Across the pdf.js corpus the soft hyphens we extract fall 117 to 13 and the non-breaking spaces 30 to 26; the rest come from `/ToUnicode`. An explicit `/Differences` name keeps its glyph list value, as pdftotext does. Estimates unchanged.
+- **2026-10-15 (M12, XFA, #2574):** A `pageArea` with no `` repeats without limit instead of taking a subform's default of one use, so a later page area with `occur max="1"` is no longer drawn (with a copy of its fields) over every body page. A page area's `occur min` is honoured too: one the body never reached gets the pages it still needs after the body (the once-only closing page of a form, with its button, comes last). Acrobat Pro also puts that page last, and when printing keeps it but leaves it blank (`relevant="-print"` on the page area), which PdfCraft does not do yet; both re-observed on a synthetic fixture, see the 2026-10-19 line. Synthetic regression tests. Estimates unchanged.
+- **2026-10-19 (M12, XFA, #2574):** The Acrobat observations behind the line above were first made on a public real-world form, which the Privacy rule does not allow; they are replaced by ones made on a synthetic form (three `breakBefore pageArea` sections, then a page area with `occur min="1" max="1"`, with and without `relevant="-print"`). Acrobat Pro shows the closing page last in both and prints it in both, blank only with `relevant="-print"`: confirmed. The synthetic form also shows a difference not fixed yet: Acrobat opens it as 5 pages, with an empty first body page before the first section, where PdfCraft lays out 4. Two more synthetic forms narrow it down: with `breakBefore targetType="pageArea"` on the first section, with or without `startNew`, Acrobat opens an empty body page first; without a break on the first section it lays out 4, as PdfCraft does (so `startNew` is not the cause). Not fixed yet: `layout.rs` skips a break while the page is still empty. Estimates unchanged.
+- **2026-10-15 (M8, #2447):** Removing links or comments (Remove Hidden Information, Sanitize) also drops the tagged-PDF structure tree's object references to them, so the full rewrite no longer keeps a removed link's URL or a comment's text. Regression seen to fail without the fix. Estimates unchanged.
+- **2026-10-15 (M6, CSV tab-containing headers):** CSV export and spreadsheet merging quote tabs, and import distinguishes quoted tabs from TSV delimiters without changing field identities. Synthetic export/import and incremental/full save regressions cover header tabs, quotes and line breaks, plus ordinary TSV controls. Formula-cell policy is unchanged. Estimates unchanged.
+- **2026-10-15 (M6, AcroForm XML text):** Plain AcroForm XML imports retain all direct text around comments and processing instructions, including CDATA and character references. Synthetic regressions verify exact values and unknown catalog data after incremental and full save/reopen. Nested-element and XFA interpretation are unchanged. Estimates unchanged.
+- **2026-10-13 (M6, data exchange fidelity):** XML and XFDF exports preserve tabs and line breaks in field names and comment metadata using character references. Saved-PDF regressions cover distinct names that XML would normalize to the same attribute value, restored field values and replacement of the original comment identities. Estimates unchanged.
+- **2026-10-15 (M12, XFA, #2574):** A `pageArea` with no `` repeats without limit instead of taking a subform's default of one use, so a later page area with `occur max="1"` is no longer drawn (with a copy of its fields) over every body page. Synthetic regression test; the page area's `occur min` (a once-only page of its own) is still not laid out, recorded in `form.xfa-dynamic`. Estimates unchanged.
+- **2026-10-14 (M12, reading colours, #2059):** Pending page backgrounds use the document's reading colour immediately, preventing white flashes while scrolling to uncached pages. A headless canvas regression covers three pending pages in every preset and a custom background. Estimates unchanged.
+- **2026-10-15 (community, M6, #2608):** In Prepare a form the selected field moves with the arrow keys: a point per press, ten with Shift, as the object nudge and dragging it do. Each press is one undo step ("Change field properties"), and the keys no longer turn the page while a field is selected. Estimates unchanged.
+- **2026-10-15 (M3, closable community card):** The ArtCraft community card on Home has a close button that hides it for the rest of the run; it returns on the next launch, and its links stay in the top bar's Discord button and the Help menu. A UI regression covers closing and the fresh-launch default. Estimates unchanged.
+- **2026-10-13 (community, M3, #1569 review):** Pixel-only Wayland wheel, wheel-tilt and continuous input use standalone moved events, so Ctrl zoom does not remain latched after the modifier is released (#991); vendored winit patch (13), with a policy test. Estimates unchanged.
+- **2026-10-15 (M14, #2383 candidate):** Device-limit requests now clamp unsupported maxima and minimum alignments before enabling the adapter's full 2D texture extent. This addresses the reported V3D request of 16 shader variables on an adapter supporting 15. Synthetic regressions fail before the clamp and pass afterward, along with the existing HiDPI case and Windows GPU-required application tests. Raspberry Pi startup remains unverified; milestone and overall estimates are unchanged.
+- **2026-10-12 (M6):** XFDF field import and data-file extraction join all text nodes in a value, preserving text after XML comments and processing instructions. Synthetic regressions cover Unicode, CDATA, empty values and PDF save/reopen. Estimates unchanged.
+- **2026-10-12 (M7, picture right-click menu):** The Edit text & images menu of a picture gains Cut Image, Redact Image (a redaction mark over the picture, applied from Redact a PDF), Create Link… and Recognize Text… (for that page), in all 21 catalogs. The menu was drawn only while the pointer was over the picture, so its items outside the picture (most of a logo's menu, and Delete below a page) could not be clicked; an open menu now stays drawn. Still missing from Acrobat's menu: Arrange (bring to front, send backward), Remove crop, Draw freehand and Edit image using… (opening an external editor).
+- **2026-10-15 (M14, Norwegian Bokmål localization):** Added Norwegian Bokmål (`nb`) as an interface and date language: a catalog covering every key the other catalogs have, Norwegian key names, month and weekday names for Fill & Sign dates, and `no`/`nn` locales resolving to it until a Nynorsk catalog exists. Written from the meaning of the English labels; terminology reviewed by a native-speaking contributor, not yet every line. Estimates unchanged.
+- **2026-10-12 (M2, inline-image boundaries):** Unfiltered inline images with known sample layouts keep pixel bytes that look like the `EI` terminator when content is rewritten. Regression tests cover row padding, colour-space and parameter aliases, masks and malformed sizes; classic and packed saved PDFs retain the pixels in independent readers and renderers. Filtered and resource-defined layouts retain the existing tolerant heuristic. Estimates unchanged.
+- **2026-10-12 (M3, drawing markups):** While a comment is being drawn, the pointer in a band along any edge of the view (or just past it) scrolls the view up, down, left or right, so points beyond what is shown can be reached. A polygon, cloud or run of connected lines takes back its last point with Backspace, Delete or Undo (the first point's removal cancels it). Edge scrolling has unit tests of its maths only; it has not been exercised end to end in the app by an automated test.
+- **2026-10-15 (M2, large object streams):** An object stream's index of `objnum offset` pairs is read once per stream instead of once per object fetched from it (vendored hayro-syntax patch 22), so reading every object of a stream of N objects no longer takes N² steps. A Firefox page whose 65,542 objects share one stream (pdf.js corpus `bug1978317.pdf`) drew in 37 s and extracted its text in 40 s; it now takes 0.5 s and 1.9 s, and leaves the robustness baseline's known timeouts. 40,000 pages in one stream open in 0.2 s instead of 54 s. The regression fails before the fix. Estimates unchanged.
+- **2026-10-12 (gap 6, #1319, #1305, #1324):** Editing an XFA form keeps a radio item's stored text when it contains a space, so a later layout still selects it. Replace Pages on a split selection replaces those pages and leaves the gap; editing the dialog range still replaces the span. Marking a figure decorative rewrites only that figure's content stream, so a header, added text and unknown stream entries stay. Estimates unchanged.
+- **2026-10-15 (M14, gap 24):** `misc.localization` and `misc.installers` move from planned to partial. Localization: 22 catalogs ship, but Chinese shows tofu in releases, Telugu has no release font and Arabic is not mirrored. Installers: macOS and Windows releases are signed, Linux packages are not. The Acrobat menu diff itself remains open. Estimates unchanged.
+- **2026-10-15 (M14, PNG export):** Export ▸ Image as PNG, `pdfcraft-cli render` and the `page_render` automation/MCP tool write an opaque page as RGB at deflate level 3 instead of RGBA at the default level 6: the files stay the same size and are written 3–5× faster (a 300-dpi scan drawn at 220 dpi: 805 → 167 ms; a text page at 220 dpi: 70 → 40 ms; an annual-report page at 150 dpi: 179 → 64 ms). A page with translucent pixels is still written as RGBA. The automation tools use the engine's encoder instead of a copy of it. Estimates unchanged.
+- **2026-10-15 (G14, Romanian localization):** Added Romanian (`ro`, Română) as an interface and date language with a 2,673-entry catalog covering every bundled key, and a CLDR plural rule (`plural_ro`: one / few / other, "20 de pagini"). Locale tags `ro` / `ro-RO` / `ro_RO.UTF-8` / `ro-MD` resolve, so Auto picks it on Romanian Windows. Coverage and plural tests added. Status `partial` like the other catalogs (no translated help).
+- **2026-10-22 (M14, JPEG and TIFF export):** Export ▸ Image as JPEG or TIFF refuses a raster that is not exactly width × height pixels, as PNG export has since #2425. A raster a pixel short panicked inside the JPEG and TIFF encoders, and a partial pixel at the end was dropped and the rest written as a valid image. Rendered pages are always the right size, so what exports is unchanged. Estimates unchanged.
+- **2026-10-13 (G14, Vietnamese localization):** Added Vietnamese (`vi`, Tiếng Việt) as an interface and date language with a 2,591-entry catalog (`plural_none`) covering 100% of the current localizable key union (plus `theme`/`Appearance`). Locale tags `vi` / `vi-VN` / `vi_VN.UTF-8` resolve; calendar months use numeric `Tháng 1`…`12` / `tháng 1`…`12`. Native-speaker community review recorded. The twelve-language localization mean moves from ≈59% to ≈68%; weighted readiness ≈49% → ≈50%. Status stays `partial`: engine/OS details, document contents, filenames, CLI/MCP and external help stay outside the catalog by design.
+
+- **2026-10-12 (M10, Edit on a scanned page):** Turning Edit on (its tab, Edit text & images or Add text) for a scanned page (an image covering at least half of a page with no text of its own; comments and text boxes over it do not count) recognizes the page first, like Acrobat's "Converting scanned page to Editable Text and Images", so its words open for editing. Once per page per window, one undoable "Recognize text" step, with the language of the Recognize Text dialog (English only for now, gap 7). Pages with real text (a flyer with a background picture), read-only files and other tools are left alone. The photographs on a scan are still part of the one page image.
+- **2026-10-13 (M3, typed zoom):** The right rail's zoom percentage is an editable field: type 150, 150% or 62.5 % and press Enter, Escape discards, and nonsense keeps the current zoom. The control channel's zoom option shares its parser, which now refuses zero, negative and non-finite values.
+- **2026-10-13 (M4, indirect page rotation):** Rotation queries and edits resolve indirect integer values on pages and their page-tree ancestors. Turning a page already at 270° by 90° now saves it at 0°, including when its rotation is inherited. Synthetic full/incremental save-and-reopen tests cover nested inheritance, sibling preservation, negative/large angles and invalid-value fallback. Estimates unchanged.
+- **2026-10-14 (M1, Flate fallback):** Raw deflate whose first bytes resemble a zlib header no longer loses a decoding-limit error during fallback. Strict and tolerant filter regressions and a COS stream regression cover refusal at the caller limit and successful decoding within it. No parity status or estimate changes.
+- **2026-10-12 (M6, XML field names):** AcroForm XML data export constrains generated element names to XML 1.0 NCNames, so Latin-1 names such as `Area²` and `Aµ` produce readable data files. Original PDF field names travel through the existing `xfdf:original` attribute; previously valid tags, including Greek and CJK, keep their spelling. Saved-PDF regressions cover invalid prefixes, combining letters and normalized-name collisions. Estimates unchanged.
+- **2026-10-12 (M6, CSV carriage returns):** Form-data CSV export quotes carriage returns in field names and values, so a trailing carriage return cannot turn into a record separator and disappear on reimport. Saved-PDF round-trip regressions cover CR, LF, CRLF, commas and quotes; estimates unchanged.
+- **2026-10-13 (community, M14, #1553 review):** Relative Fontconfig includes resolve beside each including config, including nested configuration selected through `FONTCONFIG_PATH`. Directory includes accept only digit-prefixed `*.conf` in lexical order. Isolated regressions reproduce both review findings; configuration size/count/depth limits, cycles, symlinked config and valid reset ordering are covered. Estimates unchanged.
+- **2026-10-12 (community, M14, NixOS UI fonts):** Linux/Unix interface fallback fonts are also discovered in Fontconfig's configured directories, including Nix store and user font paths. Existing candidate names, glyph checks, size limits and the screenshot opt-out are retained. Synthetic regressions cover included configuration, symlinks, cycles, depth limits and candidate ordering. Estimates unchanged.
+- **2026-10-12 (M7, local text-box candidate):** Add Text opens source text for editing and both text tools retype added items on one click. Draft boxes grow toward the page edge and downwards, with the grown width saved. Single visual rows grow across style boundaries, while multi-row paragraph widths stay fixed. Added-text previews remove only the selected item on a clone, with UI and read-only tool regressions. Arabic shaping, ordering and alignment are outside this candidate. Estimates unchanged.
+- **2026-10-12 (M14, #1395):** XDG desktops use the configuration base for app.ron, safely copying existing preferences without overwriting a destination. Original preferences, logs, recovery and digital IDs are retained; failed migration falls back to the original location. Portable and non-XDG locations remain unchanged; estimates unchanged.
+
+- **2026-10-12 (M10, Windows print progress, follow-up to #944):** While a job spools, the progress card counts its sheets ("Sending sheet 2 of 3 to Office…") as craft-print reports them (`submit_with_progress`, storytold/craft-libs#27), and steps aside for another long job's card. Pins craft-libs 666c358. Estimates unchanged.
+- **2026-10-15 (M2, renderer speed):** Three vendored hayro-interpret patches (31–33), pixel for pixel the same over the first three pages of every pdf.js corpus file. A sampled (Type 0) function keeps its samples in one flat array instead of a hash map rebuilt every time a shading using it is painted: `bug1721218` (InDesign) draws in 0.49 s (was 1.34 s), and a 2,097,152-sample ramp painted 30 times in under a second (was 38 s). One decode of a JPEG or Flate image serves every size it is drawn at (only JPX decodes for a size), so zooming a 300-dpi scan in and out costs 35–40% less render work. Coons and tensor patch meshes copy their vertices' colours less: mesh-gradient pages draw 10–16% faster (page 8 of #1584's annual report 773 → 696 ms). Estimates unchanged.
+- 2026-10-12 · M3: selected page text can be copied from Edit and the canvas context menu (#1225). Five focused regressions, full CI and native Unicode clipboard checks pass; floating Copy shares the document permission gate. Estimates unchanged.
+
+- **2026-10-13 (M2, page-label prefixes):** Preserve literal leading and trailing whitespace in page-label prefixes without changing generic metadata normalization. Nine original public-inspection cases cover prefix spaces, encodings and empty-prefix controls. Existing empty-prefix fallback remains a compatibility policy, not a conformance claim. Estimates unchanged.
+- **2026-10-14 (M14, Italian catalog):** Italian gains the 201 entries the other catalogs had and the code looks up: the sentences the accessibility checker, preflight, signature validation and page-range parser word, certificate and calendar labels, digital-ID dialog messages and five plurals. It now has 2,528 entries. 64 keys other catalogs carry but no code looks up (tooltip texts with a fixed shortcut, older wordings, generic labels only Lithuanian has) were left out. AI-assisted, written from the meaning of the English; native review welcome. Estimates unchanged.
+- **2026-10-15 (M3, #2166 part 1):** Save asks before writing over a version of the file the document did not come from (something else wrote it since the open or the last save), with Save as… to keep it, and the changed-on-disk notice says what Reload and Save each do; a file that is open already comes to the front instead of opening twice; a running instance's autosaves are locked, so a second instance neither offers nor discards them. Part 2 (every writer checked and atomic) is #2182.
+- **2026-10-14 (M1, #2166):** No PDF leaves the engine unchecked and no writer truncates: new files from Combine, Extract, Split and Create, signed, timestamped and LTV-embedded files and the OCR batch output reopen with their pages before anyone writes them, as saves already did; the desktop app, the automation tools (with or without `--root`) and the CLI's edit, combine, extract and split all write through the one staging-file writer in `pdfcraft-platform`, so a failed write or `--out` naming the input never leaves a half-written file. Special files such as `/dev/stdout` are still written as given.
+- **2026-10-14 (M3 #2080 candidate):** Existing per-tab page history gains explicit search jumps, rail buttons and control-channel commands. Continuous scrolling and automatic search refresh stay outside history; page-level restoration and estimates unchanged.
+
+- **2026-10-13 (M2, page-unit transform precision):** Preserve small transform coefficients in page marks, added content and print output. Regression cases cover accepted page units of 4096 and 75000; existing page-unit interpretation and estimates are unchanged.
+- **2026-10-14 (M5, PR #1457 branch refresh):** Merged upstream main and reconciled roadmap entries while preserving comment submission shortcuts. Estimates unchanged.
+
+- **2026-10-12 (M3, page-label navigation):** The page box displays logical labels and keeps the current page when its unchanged value is submitted, including duplicate labels. Editable-control regressions also cover numeric fallback, invalid input, active typing and focused same-document replacement with changed labels or fewer pages. Clean file-watcher reload preserves the chosen scrolling mode, preventing a Single Page reader from jumping to page 1 during replacement. Estimates unchanged.
+- **2026-10-13 (community, M2/M6, form-heavy documents):** An image whose pixels hold at most 16 bits of samples (an 8-bit Separation or DeviceN spot-colour image, a 1-4-bit gray or indexed one) is converted once per possible pixel value instead of once per pixel (vendored hayro-interpret patch 28). A fillable character sheet whose 3304 × 4105 DeviceN background ran a PostScript tint transform per pixel drew each page in 3.8 s and 430 MB, on opening and again after every field was filled; it now draws in 0.11 s and 100 MB, pixel for pixel the same. The inspector places widgets without `/P` in one pass over the pages (a form of 8,000 such fields opened in 1.17 s), and the Fields panel pairs its rows with the form through one map a frame and draws only the rows in view (8,000 fields: about 15× less CPU a frame with the panel open). Regressions fail before each fix.
+- **2026-10-14 (M9, signature appearance labels):** A visible signature's labels ("Digitally signed by", "Reason: ", …) follow the interface language when Helvetica can draw all of them, and fall back to English as a set otherwise, with a note under the preview; the preview shows the same labels and the signing time. A drawn label the font can't draw is refused naming the label and character, never written as `?`. `sign_document` takes `labels` and `appearance`. Sign, automation and kittest regressions cover German, Chinese and the refusals. Estimates unchanged.
+- **2026-10-13 (M4, #1910 Organize on the current page):** Opening Organize Pages from the toolbar, tool panel, command or `--organize` selects the page being read and scrolls its cell into view, replacing a stale grid selection that did not include it. One UI regression covers a middle page, the last page and reopening after an earlier selection. Estimates unchanged.
+- **2026-10-13 (M5, signature pad undo):** The Draw tab of Create signature/initials has an Undo button and Ctrl/Cmd+Z that take back the last stroke (#1963). Pad is UI-only, so no automation tool. Estimates unchanged.
+- **2026-10-13 (M2, raw crop and page-unit floor):** The renderer applies its existing one-point minimum in physical points for non-nearly-zero raw crop dimensions on scaled pages. Five synthetic regressions cover inspection, crop origins and rotations, reciprocal rounding and bounded raster controls. Existing UserUnit policy, nearly-zero fallback, feature statuses and estimates are unchanged.
+- **2026-10-13 (M5, text box font size, #1908):** Comment Properties has a Font size control for text boxes, typewriter text and callouts (1-400 pt); it writes `/DA` and the rich-text strings, redraws the appearance and grows the box to fit. `comment_edit` takes `font_size`. Annot, tool and UI regressions. Estimates unchanged.
+- **2026-10-13 (M3, Single Page edge paging, #1924):** In Single Page view a page taller than the window pans with the wheel, and one more notch (or a fresh trackpad swipe) at the bottom/top edge shows the next page at its top / the previous page at its bottom. A swipe that panned to the edge, momentum included, does not turn. Estimates unchanged.
+- **2026-10-13 (M3, #1980):** Ctrl+Alt+Q in the digital ID email field no longer requests application exit. Quit requires exact Ctrl+Q/Cmd+Q modifiers and uses the existing unsaved-document confirmation. Synthetic keyboard regressions cover email input and clean/dirty quit requests; estimates unchanged.
+
+- **2026-10-14 (M4, page transitions read, §12.4.4):** `/Trans` and `/Dur` are read into `DocInfo::transitions` and listed by `doc_info`, the data a full-screen presentation needs to play transitions and auto-advance; playing and editing them stay planned.
+- **2026-10-14 (M4, page transitions set, §12.4.4):** `page_transition_set` (one undoable edit) writes or removes `/Trans` and `/Dur` on chosen pages with the values checked first, the counterpart of reading them into `DocInfo::transitions`; playing them and the dialog stay planned.
+- **2026-10-14 (M12, transition geometry):** `pdfcraft_render::transition` gives the picture of any of the twelve page transitions at a moment of its run (which parts of the old and new page to paint, where, how opaque), in page fractions, tested for every style and direction; the full-screen presentation will paint from it once it plays transitions.
+- **2026-10-14 (M3, Open in Full Screen mode honoured):** a document with `/PageMode /FullScreen` now asks (Full Screen / Not now) before the app enters full screen, as Acrobat does; before, the setting was written and read but never acted on when opening.
+- **2026-10-14 (M3, control-click candidate):** Coordinate clicks retain hover warmup and pair press/release in one input pass so slow frames do not turn a click into a hold. Text multi-click selection accepts the actual press event when egui has already cleared its origin. Regression cases cover slow-frame button activation, disabled controls and coalesced text selection; estimates unchanged.
+- **2026-10-14 (community, M7, #128 Hebrew in Add text):** Add text and `page_add_text` draw Hebrew with the craft-fonts Hebr face (Noto Sans Hebrew), through the same shaped path as Arabic and Thai: right-to-left display order with numbers and Latin in place, points and cantillation kept on their letter as one Type 3 glyph, ToUnicode and per-line ActualText so extraction, search and the editor get typing order. Builds without the face refuse Hebrew rather than write `?`. Regular style only. Estimates unchanged.
+- **2026-10-14 (M9, #1787):** Changes after signing are judged by the role an object held when signed for a page's resources too: a rewritten font, XObject, graphics state or resources dictionary is page content however its new version is labelled, so a `/FT` or `/Subtype /Widget` added by the attacker no longer reads as a permitted form fill. A category dictionary that only gained a name is judged as before.
+- **2026-10-14 (M3, full screen as presentation, #379/#1459/#1353):** Full Screen Mode shows one page (or one spread) at a time fitted to the screen on black, with no tools; click, Space, Enter and the arrows turn pages; Esc restores the display from before. Transitions, auto-advance and loop remain planned.
+- **2026-10-14 (M10, #1818):** Properties… reads a CUPS printer's driver options off the GUI thread, the dialog saying so meanwhile, and `lpoptions` is given ten seconds before it is killed and the PPD's defaults stand; a read that dies leaves the panel with nothing rather than a frozen window. The bounded wait is tested with a stand-in command that never answers.
+- **2026-10-14 (M10 #2156 candidate):** Print paper selection survives Cancel and settings restoration; canonical names avoid preset-index dependence. Other print preferences and estimates unchanged.
+
+- **2026-10-15 (community, M14, Polish signature panel):** A Polish signature panel listed its details in English: the catalog lacked every signature wording, the changes after signing they name and 34 UI literals. All 101 are translated; `polish_covers_ui_literals` and `polish_says_what_a_signature_says` keep them so. Estimates unchanged.
+- **2026-10-14 (M14, Finnish localization):** Added Finnish as another interface and date language, with a 2,674-entry catalog covering every key of the other bundled catalogs and two-form plurals (partitive after numbers other than 1). Calendar dates use partitive month names (`14. lokakuuta 2026`). Coverage tests check commands/tools, scanned UI literals and bundled catalog keys. AI-assisted; native proofreading pending.
+- **2026-10-14 (M14, Catalan localization):** Added Catalan as another interface and date language, with a 2,592-entry clean-room catalog, one/other plurals and coverage tests for commands, tools, UI literals and every key in the other catalogs. A native Catalan speaker (the contributor) has reviewed the translation. Estimates unchanged.
+
+- **2026-10-15 (M3, #1248):** A fresh install follows the desktop's appearance: the theme preference defaults to System (dark on a dark desktop, Light where the desktop says nothing); saved settings and `--theme` still win. Dark page rendering is Reading colours, and the page reading themes are #1732.
+- **2026-10-15 (M3, #1767):** Restore last view settings when reopening documents, as Acrobat's preference does: a file opened again shows the page, zoom and page display it was last shown with (remembered for the last 100 files when a tab closes or settings are saved), over the file's own initial view; on by default, Preferences ▸ Documents and view turns it off.
+- **2026-10-13 (M3, native-opening candidate):** Chosen tools survive preparation, conversion and password retries; startup intake waits for pending preparation. Regression tests cover completion, cancellation and document identity. Estimates unchanged.
+- **2026-10-13 (community, M3, #531 touchpad momentum):** On Wayland a two-finger swipe keeps gliding after the fingers lift and slows to a stop, measured from the gesture's last 0.1 s and decaying with a 0.35 s time constant through the #759 1:1 path. Any wheel input, click, key, zoom or edge ends it (fingers resting on the touchpad don't yet: the vendored winit binds no Wayland hold gestures); single-page paging, macOS (which sends its own momentum), the web, and Animation effects Off never glide. Unit tests for the physics and two headless view tests. Estimates unchanged.
+- **2026-10-13 (M3, native-open admission):** Later prepared replies stay queued while a modal or native picker owns the foreground. Picker completion, cancellation and abandonment wake retained opens. Regressions cover recipient ownership, exactly-once admission, source/history preservation and one-shot repaint requests. Estimates unchanged.
+- **2026-10-13 (M6, choice indices):** Multi-select choice fields write ascending `/I` option indices while preserving the caller's `/V` order. Synthetic forms and headless engine regressions cover reverse selection and save/reopen. Estimates unchanged.
+
+- **2026-10-12 (M10, Windows printing without PowerShell, #1107):** craft-print now prints on Windows in-process: printers from EnumPrinters/GetDefaultPrinter, jobs drawn as vectors by Windows.Data.Pdf into the XPS print API with a driver-validated PrintTicket (exact paper, orientation, no scaling), so printing works where App Control for Business or AppLocker run PowerShell in Constrained Language Mode. Portrait and landscape sheets still print as one job (turned with /Rotate); a sheet size the driver lacks is refused rather than shrunk. Pins craft-libs f03ec27 (craft-libs#28); deny.toml allows the storytold/winprint.rs fork and adds a webpki-root-certs licence exception and a RUSTSEC-2024-0370 ignore for winprint's build-dependencies. An earlier craft-print revision was checked in Windows Sandbox under enforced WDAC: printers listed, CLI and desktop jobs spooled, and no powershell.exe in the 4688 audit. The final pinned revision passed craft-libs Windows CI, including a real paused-queue job; that Sandbox run has not been repeated. Estimates unchanged.
+- **2026-10-12 (M1, #1338):** A full rewrite used to build a new trailer from `/Root`, `/Info`, `/Encrypt` and `/ID`, so accepted unknown entries such as a custom string or `/Version` disappeared, including when an incremental save was forced to rewrite. Those entries are copied, and objects reachable only from them are written and renumbered with the rest of the file. Ordinary incremental saves are unchanged. Estimates unchanged.
+- **2026-10-12 (M4, #1310, #1311, #1312):** Undo back to the opened file left it marked unsaved, so recovery and close treated unchanged work as dirty. After a save, Revert followed the restored snapshot's older base and the next save dropped the latest saved revision. The last saved file is remembered on its own: undo and redo are clean only when they land on it, Revert opens it, and a later save appends to it. Estimates unchanged.
+- **2026-10-12 (M13, CLI robustness scans):** `pdfcraft-cli check` visits a directory once even when input roots overlap or directory symlinks lead back into the tree. PDFs reached through file symlinks remain accepted. Three real CLI regressions cover overlapping roots, a directory cycle and directory/file aliases. Estimates unchanged.
+- **2026-10-12 (M4, Type 3 extraction fidelity):** Extract and Split preserve shared image/resource dictionaries reached through Type 3 glyphs, including nested forms, patterns and soft masks. A bounded object-graph walk protects unknown glyph content; unreadable pages/forms retain their glyph resources, and shared explicit fonts are visited once. Separate page dictionaries still prune unused images. Synthetic save/reopen regressions and an opt-in Poppler pixel oracle cover resource ownership, nested forms, cycles, limits and repeated fonts. Estimates unchanged.
+- **2026-10-12 (M2, TIFF predictor rows):** Packed RGB images using TIFF horizontal differencing keep every row when samples do not fill the last byte. The renderer aligns each decoded row before moving to the next. Synthetic decoding tests cover 1/2/4-bit samples, horizontal differencing and an 8-bit control; a red/green page-render regression verifies visible output. Estimates unchanged.
+- **2026-10-12 (M3, #1364 candidate):** Absolute local GoToR links wait for Allow/Cancel before target-file access. Pending requests preserve their source and page/view destination; relative links retain their existing behavior. Headless `link_open` requires explicit `allow_absolute: true`, preserving existing root, symlink, file and password validation. Estimates unchanged.
+
+- **2026-10-12 (community, M7, inline Arabic ActualText):** A single-glyph lam-alef `/ActualText` span joins its surrounding word in Edit text instead of splitting it into separate lines. Pure RTL ligature text is put in visual order before line assembly and recovered to typing order with its neighbours. Multi-glyph and mixed-direction replacements retain their authoritative order. Synthetic regressions cover lam-alef variants, marks, two-byte glyph codes, nested spans, replacement and save/reopen. Estimates unchanged.
+- **2026-10-12 (M5, #1398):** A stamp placed on a page with `/Rotate` reads upright as that page is displayed. Rubber stamps (including Sign Here), natural-size and explicit-rectangle images, and PDF-page stamps counterrotate their appearance; restyling a picture stamp keeps that correction, and a saved file reopens the same way. Estimates unchanged.
+- **2026-10-12 (M10, file formats):** Create PDF reads BigTIFF scans; a malformed GIF header is no longer detected as an image only to fail conversion. file-format-parity.md now lists XDP data import/export for XFA forms (already shipped under `form.xfa-data`) separately from opening `.xdp` as a document. Estimates unchanged.
+- **2026-10-12 (gap 6, #1317, #1327, #1302, #1315, #1340):** Flattening keeps a visible comment it cannot draw, such as a cloudy square with no stored appearance, and still draws a solid square, a hidden comment and a cloudy square that already has an appearance. A text box another program drew is left unchanged when a restyle or resize is refused. Make Current Properties Default on an arrow updates the Arrow tool and leaves plain lines alone. A custom text match that ends on a reconstructed word or line separator no longer includes the next glyph. The vertical-writing redaction refusal still fails closed, and its message no longer says the text was under the mark. Estimates unchanged.
+- **2026-10-12 (M12, text-only auto-tag):** Automatically tag PDF now writes marked text objects, paragraph tags, a Document element and a parent tree for untagged text-only PDFs. The result is undoable and opens the Tags panel for review. Mixed paint, forms, annotations, existing tags and malformed streams are refused before mutation. Synthetic two-page engine and tool tests check the tree, checker, unchanged rendering and save/reopen. Richer content and role classification remain open. Estimates unchanged.
+- **2026-10-12 (M7, #1316):** Replacing a line or paragraph no longer removes a distinct neighbour whose glyph box overlaps the edited line. A second drawing is removed only when it also sits on the same baseline, so fake-bold and invisible copies still go. Synthetic regressions cover 6 pt leading, the same word on the next line, ordinary spacing, a separate paragraph, same-position copies, and incremental and full save/reopen. Estimates unchanged.
+- **2026-10-12 (M5, comment shortcuts):** Ctrl+Enter posts highlight comment text and replies; Shift+Enter adds a newline. Replies keep Enter-to-post, and floating comment composers only submit from their focused editor. Estimates unchanged.
+
+- **2026-10-12 (M7, #1443):** Adding a word to a multi-line paragraph no longer reflows or merges its lines. Two causes: in Chrome- and Skia-made subset fonts, `/W` leaves out glyphs of the `/DW` width, which were treated as missing, so unchanged rows measured too wide and rewrapped (and new letters fell back to Helvetica); and lines drawn turned on the page (a landscape page drawn a quarter turn round) were compared along the page's x axis, so all of them became one line. Lines and rows are now found along each text's own baseline, a turned paragraph is rewritten in its own text space, and that rewrite keeps explicit line breaks. Formatting part of turned text is refused rather than misplaced. Synthetic regressions cover three turns and a default-width subset. Estimates unchanged.
+- **2026-10-12 (M1, #1339):** An incremental save of an unchanged classic-table file used to append `xref` and then `trailer` with no subsection, which qpdf reports as a damaged file. The section now has a zero-length subsection, so no object entry changes and a trailer-only edit is still written. Estimates unchanged.
+- **2026-10-12 (M12, auto-tag preview):** The engine and `accessibility_autotag_preview` propose paragraph and large-heading roles for bounded text blocks on one page, with locations and reasons. Every proposal needs review; images remain unclassified. No PDF tags are written yet. Synthetic tool tests cover normal text, a larger heading, bounds and unchanged source bytes. Estimates unchanged.
+- **2026-10-12 (M10, editing OCR text on scans):** Editing a recognised word on a scanned page now changes what the page shows. Before, the rewrite stayed invisible OCR text, so the scan still showed the old word; on a form, the whole OCR layer also grouped into one paragraph that rewrapped when one word changed. OCR words now group into phrases (a table cell or a tab stop splits them, and lines stay apart); an edit draws the phrase visibly in the scan's sampled ink colour over a cover in the sampled paper colour, keeping each word's width and growing rightwards. The editor covers the scanned word while typing. OCR words are now sized from their letters (a capitals-only word's box spans the cap height, not the full ascender-descender span), so recognised and rewritten text is as tall as the scanned word and sits on its baseline. Five engine tests on synthetic scans and a kittest UI test; `ocr.editable-text-output` is partial.
+- **2026-10-12 (M2, Lab Bradford follow-up):** Lab white-point adaptation scales Bradford LMS cone responses using LMS white-point ratios. Independent D50 and equal-energy neutral/chromatic render oracles, D65 identity, direct/Indexed consistency with asymmetric chromatic Range, and degenerate-cone fallback cover the correction. CalRGB and the merged Indexed/Range scaling retain their behavior. Estimates unchanged.
+- **2026-10-12 (community, M14, recovery metadata):** A recovery snapshot whose metadata is missing, damaged or names another snapshot is no longer deleted when the folder is listed: it is offered for recovery without an original path (Save asks for a destination), and encrypted snapshots still ask for their password. Recovering one writes fresh metadata in place of the damaged file, and clearing the folder also removes metadata left without a snapshot. Before, a failed metadata write meant the next start deleted the finished snapshot. Synthetic regressions cover the failed write, missing, corrupt, mismatched and encrypted cases. Estimates unchanged.
+- **2026-10-12 (M7, Arabic ActualText):** Add text records each shaped line in typing order with `/ActualText`, so copy and search preserve mixed Arabic, Latin, digits and brackets. Edit text keeps the logical order supplied by `/ActualText` instead of reversing Arabic or Hebrew a second time. Adjacent visual glyph runs retain their own bidi recovery. Font-independent tests cover Arabic marks, numbers, Latin words, reopen and complete replacement; automation checks saved editor text and unchanged rendering. Font fallback and bidi typing remain separate gaps; estimates unchanged.
+- **2026-10-12 (M5, Fill & Sign text size):** The active Fill & Sign toolbar now chooses 4–300 pt for new text and dates; the in-place editor and saved annotation use that size, which persists in local settings. `fill_sign_add` accepts the same `font_size`. Feature and readiness estimates unchanged.
+- **2026-10-12 (community, M3, Greek search):** Case-insensitive Find treats normal, final and capital sigma (`σ`, `ς`, `Σ`) as the same letter, so `κόσμος` and `ΚΌΣΜΟΣ` find each other. Case-sensitive and whole-word options, glyph ranges and match limits retain their behavior. Synthetic text-search regressions cover both directions. The tab-menu regression selects the platform's Reveal label (Finder on macOS), restoring the macOS test without changing the menu. Estimates unchanged.
+- **2026-10-12 (M2, soft scans):** A shrunk, interpolated, axis-aligned image (a 300 dpi scan on a screen) is snapped to whole device pixels and shrunk once, not resampled a second time at a fractional scale and offset. On a synthetic scan page the error against an area-average reference fell from 3.4 to 1.6 grey levels at 96 dpi, and edge sharpness is within 2% of the reference (was 10% soft). Rotated, skewed, flipped and non-interpolated images are unchanged; downscaling of those is still open.
+- **2026-10-12 (M14, Lithuanian localization):** Added Lithuanian as another interface and date language alongside the existing languages, with a 2,578-entry catalog and three-form plurals. Calendar, inspector and password-dialog regressions check localized labels and unchanged document values. The contributor has reviewed the translation as a native Lithuanian speaker. Estimates unchanged.
+- **2026-10-12 (M12, XFA scripts turned off):** When a runaway script turns an XFA form's scripts off, the app now says so: a toast as it happens (at open or after a click), and the notice bar from then on, ahead of its other notices, with a JavaScript Console button. Before, the error was only in the console, so calculations and buttons just stopped. A notice bar the user had closed comes back for it; closed again, it stays closed. The engine reports the state (`Document::xfa_scripts_off`, and `xfa_scripts_off` in `doc_info`) instead of the UI reading error text. Two kittest UI tests (a runaway at open; a runaway click after the bar was closed), engine assertions and a `doc_info` tool test. Overall unchanged.
+- **2026-10-12 (M14, Windows low-DPI font-hinting candidate):** The Windows policy disables symmetric rendering for embedded JetBrains Mono only. On the locked-font macOS probe, horizontal alpha-edge energy per ink improves 2.78%, 3.87% and 1.59% at 100%, 125% and 150% scaling, and is down 0.79% at 200%; Inter is pixel-identical. Logical layout hashes and 8 MiB atlas size match, repeated fractional offsets add no atlas dimensions, and baseline/candidate time and RSS ranges overlap. Windows runtime and hardware remain unverified; estimates unchanged.
+- **2026-10-12 (M7, #1200 candidate):** Bounded local GoToR file specifications open in desktop tabs; explicit numeric page views apply, while named destinations open at the default view with a warning. The automation tool resolves relative to the source and uses existing `--root` confinement. Appearance-only Link Properties edits preserve the existing action. URL/network paths remain refused; `/NewWindow` is a tab hint. Estimates unchanged.
+- **2026-10-12 (M1, #1337):** COS opening repairs exhausted cross-reference entries and records the skipped row; allocation safely falls back to unused numbers for exhausted /Size hints and high edits. Classic-table and stream regressions reproduce the former panic; ordinary, zero-offset and repaired-range controls preserve opening and allocation. Estimates unchanged.
+- **2026-10-12 (M7, private image crops):** Exclusive image crops resize with their pixels across nested states, intervening operators and content streams; shared clips remain fixed. Synthetic engine/tool regressions and private image save/reopen checks; estimates unchanged.
+
+- **2026-10-12 (M12, accessibility finding locations):** Checker findings for figures, annotations and form widgets carry verified page bounds. Selecting one flashes its location; the headless check returns the same PDF-space rectangle. Malformed annotation rectangles remain page-only findings. Guided review and tagging estimates unchanged.
+
+- **2026-10-12 (M14, gap 13, large-file memory):** Measured on synthetic 1 GiB and 100,000-page files. Edits let go of the previous working file (working bytes, display bytes, renderer) before writing the next, so a 1 GiB file peaks at two copies while editing instead of three (five edits: 3.1 → 2.1 GiB, 16 → 8.5 s). Saving still peaks at three; reading from disk on demand is blocked on the renderer (gap 2). Estimates unchanged.
+- **2026-10-12 (M2, short text redraws):** Same-line redraws that restart a matching three-glyph prefix after more than one glyph-height of progress split before placement, so short doubled words no longer interleave. The existing redraw-position tolerance is reused; controls cover negative TJ movement, combining marks, RTL, CJK, vertical and turned text. Estimates unchanged.
+- **2026-10-11 (M5, #1191):** Quick-bar colour changes now restyle the selected comment when it matches the active comment tool, while continuing to update that tool's default; added an accessible label to the swatch controls and a UI regression proving the saved style and undo step. Estimates unchanged.
+- **2026-10-11 (M10.5, focused follow-up to #599):** Carry the architectural/ANSI/large ISO paper presets, current-page matching at 100%, and previewed PDF scale into the current print dialog and `doc_print`. Retains the #847/#1007 spooler and background discovery. Driver substitution, physical calibration, vector Windows printing and managed-endpoint restrictions remain separate gaps. Overall estimates unchanged.
+
+- **2026-10-11 (contributor fork, M7):** Full matching font import completes source-subset glyphs; installed/file font selection, TrueType/OpenType-CFF mapping, disjoint range styles, marked paragraph boundaries and single-face contextual shaping/bidi added. Private Chinese keyboard edits on all four pages preserve source anchors and save/reopen renders. Curved clips exclude holes from hit tests; shared path scopes are isolated for image transforms without moving neighbouring paint. No font binary or private fixture is published; release font inputs and readiness estimates unchanged.
+
+- **2026-10-11 (M7, cropped image resize follow-up):** Resize from the visible (clipped) frame; an image's own clip moves with it (#1049) and shared clips stay fixed. Selected corner grips keep control over overlapping text; horizontal/vertical-only shrinking responds without freezing; one drag frame is previewed and one edit is applied on release. Synthetic pointer/tool regressions and private grow/shrink/save/reopen/undo rendering checks cover the regression. Shared clipping scopes containing unrelated painted content are refused. Estimates unchanged.
+
+- **2026-10-11 (M7, cropped artwork selection):** Image/Form inventories now expose page/path-clipped visible bounds while retaining full placement geometry for transforms. Edit clicks prioritize text over background artwork; image frames stay within their own page and fixed clips remain fixed during movement. Engine/tool/UI regressions and an opt-in four-page private-file test cover direct access to 73 text regions and five cropped placements. Rectangular clips are exact; curved/complex clips use conservative bounds. Estimates unchanged.
+
+- **2026-10-11 (M7, live text editor follow-up):** Reuse validated embedded sfnt source faces; adapt Mac format-6 subset cmaps through PDF Unicode mappings in memory without changing or installing source fonts. Preserve source baseline positions on entry. Show draft text and a single frame that grows/shrinks as rows are added or removed; single rows can grow toward the page edge. `text_edit_layout` exposes read-only draft bounds through the engine and automation. Licensed synthetic font/frame regressions and an opt-in all-page private-file check cover source font usage, stable positions, typing and deletion. Unsupported source programs, shaping and installed-font selection remain limited; estimates unchanged.
+
+- **2026-10-11 (M7, mixed-style regions follow-up):** Group adjacent source runs into visual rows and aligned rows into regions across subset fonts, colours, weights and text-matrix sizes. One inline TextEdit uses styled spans and source row breaks; rewriting preserves surviving source-run styles, source subset encodings and centered mixed-size title alignment. Added engine, automation and UI regressions for edit/delete, read-only preview, save/reopen and undo; privately verified the supplied real PDF's three-row title and six-row body, including selecting both in one editor without extra rows. `text_paragraphs` exposes `editor_text` and `rows`. Installed-font selection, exact editor glyphs, complex shaping and arbitrary multi-range style edits remain open. Readiness estimates unchanged.
+
+- **2026-10-11 (M7, contributor fork):** Join compatible words across text objects and subset-font spaces; preserve source fonts that lack a space glyph using text positioning; recognize component colour operators. Inline editing uses one editor frame, resets its available width when switching blocks, keeps source line breaks, and renders a COS-clone background without the original glyphs, preserving unselected text advances. `page_render.hide_text_block` exposes the same read-only preview. Mixed-style paragraph grouping, installed-font selection and exact source-font editor rendering remain open.
+
Newest first: the date, what moved, and the new overall estimate.
- **2026-10-17 (M0, cancellation regression):** Replace the parser wait test's yield loop with a blocking channel handshake. The test observes cancellation as false before requesting it and requires the waiter to finish while initialisation remains blocked. Feature readiness was not remeasured.
- **2026-10-15 (M0, dependency audit):** Updated the locked rustls dependency to 0.23.46 for RUSTSEC-2026-0346 through RUSTSEC-2026-0349. This maintenance change does not remeasure feature readiness.
+- **2026-10-12 (M3, GNOME title bar, #553):** On GNOME's Wayland session, whose compositor draws no window frames (it offers no `zxdg_decoration_manager_v1`), PdfCraft no longer shows winit's fallback title bar: it turns the frame off and the tab strip becomes the header bar, as in GNOME's own apps. Minimize, maximize/restore and close are drawn in Adwaita's style, in the order and on the side GNOME's `button-layout` names (Fedora's default shows only close); the window's edges and corners resize it, and a hairline outlines it while it isn't maximized. Preferences ▸ Use system title bar (shown only there) gives the window back winit's frame at once, without a restart (part of #1001), and `PDFCRAFT_TITLEBAR=app|system` overrides the choice. KDE, Sway, Hyprland, COSMIC and X11 keep the frame their desktop draws. Not done: right-clicking the header bar doesn't open GNOME's window menu (egui can't ask for it), the window has no shadow or rounded corners, the resize edges lie just inside the window rather than outside it, and Windows still uses its system frame (the rest of #1001). Estimates unchanged.
+- **2026-10-12 (M0, build label):** A local or patched build can carry a label, set at compile time with `PDFCRAFT_BUILD_LABEL`: `pdfcraft --version`, `pdfcraft-cli --version`, About and the log show `0.7.1 (titlebar)`, and `packaging/linux/package.sh` names the files `pdfcraft-0.7.1-titlebar-…` and makes the .rpm/.deb release `1.titlebar`, which upgrades over the release of the same version (and the next release over it). The version itself is unchanged, so the update check still compares it with published releases. Unlabelled builds are as before. Estimates unchanged.
+- **2026-10-11 (M6, #1208):** Dropdown and list-box Field Properties expose the existing Left/Center/Right alignment picker. Existing alignment stays intact until changed; cancel, undo/redo and save/reopen are covered through the real UI without changing options, values or flags. Estimates unchanged.
+- 2026-10-11: Organize Pages shows an editable, synchronized physical page-range selection (#1092), with bounded validation and UI/operation regression coverage; overall estimate unchanged.
+
+- **2026-10-11 (M5.7, scanned signatures, #1110):** Fill & Sign ▸ Add signature has a Scan tab: a phone photo of a signature on paper is framed automatically (all words; table, sheet edge and dust ignored; a sideways signature turned upright), the frame can be moved, resized or redrawn, the photo turned, and an ink-sensitivity slider picks up faint ink. A morphological paper estimate removes shadows and uneven light, and the trimmed ink is saved and reused like an image signature. Photos and images can also be dropped on the Image and Scan tabs. Photos keep the image-signature limits (#1124: a 4 MiB file, up to 32 megapixels decoded, scaled down to 4 megapixels), so a scan never processes more than 4 megapixels. `fill_sign_add` takes `scan` and `sensitivity`. Synthetic engine, UI and automation tests; checked by hand on real phone photos. Milestone and effort estimates unchanged.
+- **2026-10-12 (M10.5, hosted CI):** Integrated current main, including its date-table formatting and static-storage fixes. The Arabic synthetic drawing regression now checks the original serialized-output golden with and without the optional font face: the face-dependent FontName and FontFamily are checked separately and normalized only in the fixture. The hosted FreeBSD fingerprint is reproduced by those two metadata fields alone. Drawing bytes and all other fields retain the original golden; no printing behavior or readiness estimate changes.
+- **2026-10-11 (M3, animation effects):** PdfCraft follows Windows' Settings ▸ Accessibility ▸ Visual effects ▸ Animation effects, and Preferences has its own Animation effects: Use system setting (the default), On or Off. With animation effects off, a wheel notch scrolls its whole distance, and Ctrl with the wheel zooms its whole step, in the frame it arrives. Both were eased over about a quarter of a second whatever the setting: egui spreads a coarse wheel step over later frames and has no switch for it, so `crates/ui-egui/src/motion.rs` reads each frame's wheel input the way egui does, minus the easing, and hands that to the scroll areas and the views (a test sums what egui eases and compares it with what is read at once, and fails if egui stops easing). egui's own animations (menus, sections, scrolling to a row) take no time, the chrome's hover and press washes are simply there, and the progress card's bar steps without its sweep. The desktop app asks WinRT's `UISettings.AnimationsEnabled` at launch and every two seconds of use, so a change applies without a restart. How far a notch scrolls or zooms is unchanged. The preference set to On or Off decides all of this whatever the system says; it is saved, set as `animation_effects` (`system`, `on`, `off`) on the control channel, and translated in all 20 catalogs. Not done: macOS (Reduce motion), Linux (GNOME's animations switch) and the browser (`prefers-reduced-motion`) aren't asked yet, so Use system setting animates there as before; Off works everywhere. Estimates unchanged.
+- **2026-10-11 (M10, gap 4):** The web build prints. Its Print dialog offers "Browser's print dialog" (the default there), which reaches every printer the operating system knows. PdfCraft draws the print-ready PDF's sheets itself with its own renderer, a sheet a frame because the web build has no threads: 300 dpi up to 100 sheets, 200 up to 300, 150 up to 1,000, at most 64 megapixels a sheet and 1 GiB of pictures a job. It then prints them from a hidden iframe, one sheet per printed page with no margin. A landscape sheet among portrait ones is turned onto the paper, as a driver does, because Chromium prints every page at the default `@page` size. Copies, two-sided and colour are set in the browser's dialog, so the dialog greys them out. If the browser refuses to print (a sandboxed frame, for example), the print-ready PDF downloads instead. Verified in headless Chromium: the right sheets at 300 dpi, the landscape sheet turned, no blank trailing page, and the download fallback. Not yet tested in Firefox or Safari. Gap 4 closed; rank 1 is 65–120 → 50–90 h; other estimates unchanged.
+- **2026-10-11 (M10.5):** Extracted printer discovery, options and PDF submission into craft-libs/craft-print, shared with DesignCraft. Windows preserves composed sheet size and orientation without fitting into default margins; duplex binding edges are corrected. PdfCraft retains permission checks and imposition. Shared transport and local composition, engine, automation and UI coverage validate the boundary; native Windows CI passes, including paused-queue submission and cleanup; physical printer fidelity remains a hardware check. Rust 1.95 is required by the shared crate. No readiness percentage change.
+- **2026-10-11 (M10, #1028):** Recognize Text can read pages that already have text: "Also recognize pages that already have text" in the dialog (remembered with the other choices, and used by Recognize text in multiple files) and `skip_text_pages: false` on `ocr_recognize` and, newly, `ocr_recognize_files`. A picture on such a page becomes searchable, and a recognised word at least half covered by the page's own text (an earlier OCR layer included) is left out, so nothing is found twice; `ocr_recognize` reports how many were left out as `already_on_page`. Before, the option existed only for agents and added the page's text a second time. The default still skips pages with text. Synthetic tests (a picture of a sentence plus real text) cover the engine, the tool and the dialog, and fail with the filter turned off. Still missing: reading only the picture areas (the whole page is read, as for a scan). Separately, `recognize_text_makes_a_scanned_page_searchable` fails on main wherever the models are installed (the model reads "quick" as "auick"). Estimates unchanged.
+- **2026-10-11 (M2, page-label prefixes):** The page-label readers bound the total size of decoded prefixes. Each range decodes its own prefix, and ranges may share one prefix object, so a small file could ask for a copy per range: within the 200,000-entry tree limit, about 200 MiB of copies of one 1,024-byte prefix. Inspection and Organize now refuse a tree whose decoded prefixes pass 4 MiB in total (`MAX_PREFIX_TOTAL_BYTES`), before any label is made, as the other tree limits do; relabelling such a tree changes nothing. Synthetic tests share one 1,000-byte prefix across 5,000 ranges and keep exactly 4 MiB of prefixes readable. Overall estimate unchanged.
+- **2026-10-11 (UI, checkboxes and radio buttons):** Checkboxes no longer look like radio buttons, and on the light theme neither is invisible. With the theme's 6 px widget radius egui drew a checkbox's 14 px box as a circle, so View ▸ Page display's Continuous scrolling and Show cover page read as two more layout choices; on the light theme an unticked box or an unselected radio button was white on white with no edge. Every checkbox (81) and radio button (79) now goes through `widgets::checkbox` / `widgets::radio` / `widgets::radio_value`: a 1 px outline (darker on hover), the plain fill on the light theme as dialogs already had, and for checkboxes a rounded-square box (3 px), keeping what the caller set (dialogs, the search panel). `clippy.toml` disallows `ui.checkbox`, `ui.radio`, `ui.radio_value`, `egui::Checkbox` and `egui::RadioButton` so new ones use them too. Estimates unchanged.
+- **2026-10-11 (M13, #971):** `text_find` now bounds each page's temporary match-range list to the remaining result limit plus one, which is enough to detect and return a continuation without allocating every match on a dense page. Added limited-search coverage; the existing end-to-end continuation test passes. The text cache byte budget and per-page extraction warnings remain open.
+- **2026-10-11 (M7, #594):** Ordinary paragraph body drags now use the existing source-preserving object translation path; edge drags still rewrap. An in-progress drag is discarded if the document generation changes, and added-content gestures keep their own edit handler. Added real-shell source regressions for overlapping and identical labels, history, save/reopen, partial overlap, kerning, rotation/crop/UserUnit and atomic refusal. Linux validation passed: focused UI/engine regressions, exact-base source-loss failures, native drag/undo/redo/save/reopen with independent Poppler renders, and all eight CI gates. Text replacement and resizing over unrelated overlapping content remain outside this repair. Estimates unchanged.
+
+- **2026-10-10 (community, M7, Thai Add Text):** Optional craft-fonts Thai face (Noto Sans Thai) for the UI and shaped Add Text through the engine, CLI and MCP. Stacked marks and Sara Am are kept through Type 3 clusters with ToUnicode; regular style, and wrapping at cluster boundaries (no dictionary word segmentation). The craft-fonts pin for CI and releases moves to the revision with the Thai face. Forms and Fill & Sign are outside this change. Estimates unchanged.
+- **2026-10-11 (#995, #1077, permissions password after opening):** A PDF with only a permissions password opens without asking, restricted, and nothing let the user enter that password afterwards: the notice and the hint pointed at reopening with it. Now the security notice and Properties ▸ Security offer Unlock…, and Change settings / Remove security on a restricted document ask for the permissions password first and then carry on (as Acrobat does). The open password is refused there. `Session::unlock` upgrades the open document in place (owner and user passwords unlock the same file key, so nothing is re-read), unlocks the undo and redo states and reopens saves as owner; it is not an edit and doesn't mark the document unsaved. New command `protect.unlock`; the new strings are in all 15 full catalogs. Tests cover crypt, cos, engine (undo, redo, save, separate open password) and the UI. Still missing: an automation tool for it. Estimates unchanged.
+- **2026-10-11 (M14, #307 Plan 3):** Engine open and full refresh use one page/content traversal to populate marks and added content. The independent public scans remain available; the combined scanner borrows direct objects and holds referenced objects through `Arc