diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f94d7dbe40..ac276f13c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,156 +1,89 @@ 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 # 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 - +# 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 }} - env: - CARGO_PROFILE_DEV_DEBUG: line-tables-only - CARGO_PROFILE_TEST_DEBUG: line-tables-only - 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] + # 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - # 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - repository: storytold/craft-fonts - ref: 3d9ab3a132ed0eff457e424226a435a901da30d3 - path: craft-fonts - - - name: Configure craft-fonts (Linux) - if: runner.os == 'Linux' + persist-credentials: false + - name: Git dependencies come from storytold run: | - echo "CRAFT_FONTS_DIR=$GITHUB_WORKSPACE/craft-fonts" >> "$GITHUB_ENV" - echo "CRAFT_FONTS_REQUIRED=1" >> "$GITHUB_ENV" + 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 - - name: Install Linux system dependencies (egui/winit/rfd) and the oracles - 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 \ - qpdf poppler-utils - - # The independent oracles (crates/oracle) are only worth having when they run. With this - # set, a missing one fails the job instead of printing a skip notice that reads as a pass. - # Only the tools the job actually uses are installed above. - - name: Require the oracles (Linux) - if: runner.os == 'Linux' - run: echo "PDFCRAFT_ORACLES_REQUIRED=1" >> "$GITHUB_ENV" - - - uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable - with: - toolchain: stable - 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@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - - - 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' - run: cargo test --workspace - - - name: Layering - if: runner.os == 'Linux' - 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable - with: - toolchain: stable - targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - with: - key: wasm32 - - name: Check library crates for wasm32 - run: cargo xtask wasm - - deny: - name: dependency licences and advisories - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - 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 + gate: + if: github.event.action != 'labeled' || github.event.label.name == 'full-ci' + # Tracks @main so suite-wide CI fixes reach every app without a PR in each repository. + uses: storytold/craft-common-actions/.github/workflows/gate.yml@main + 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: 3d9ab3a132ed0eff457e424226a435a901da30d3 + # 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.149,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/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/sonarcloud.yml b/.github/workflows/sonarcloud.yml index ecee45a6d8..e78fe1ea3b 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -11,7 +11,8 @@ permissions: concurrency: group: sonarcloud-${{ github.ref }} - cancel-in-progress: true + # 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: diff --git a/AGENTS.md b/AGENTS.md index 0665ad1d3b..2ecfe99a02 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,10 +20,10 @@ 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. 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. @@ -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 diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 3645cc3fda..78e28cc02c 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -2,7 +2,7 @@ -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 (288) @@ -342,4 +342,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; 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 leaves out for size | diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index aad917de98..a1a26e0362 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -7,12 +7,13 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Greek UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "e1e52854ba3c24e27b53a6f814553a45925ec59820e5d4d99fe2a57655aa3339" # 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); @@ -30,7 +31,6 @@ 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 = "4ac6d601e15b7124b9b9086ef64c07c21913b7df6d9c50bc5aa1b6bf7a35518d" [[asset]] path = "crates/ui-egui/src/i18n/zh-hant.tsv" @@ -41,7 +41,6 @@ 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 = "39ba85747f81d3c13a4b9b731653b5846c5dbec62f8e933701f7f53aea75dd7a" [[asset]] path = "crates/ui-egui/src/i18n/cs.tsv" @@ -52,7 +51,6 @@ 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 = "0918af46ebec17793c95db826dd3c5320dfbefc370179e61e82a226286d9b341" [[asset]] path = "crates/ui-egui/src/i18n/pt-br.tsv" @@ -63,7 +61,6 @@ 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 = "9e63cddf19952d069a73015c302855022a82aa630e0f7051e43198b5ae0a0354" [[asset]] path = "crates/ui-egui/src/i18n/es.tsv" @@ -74,7 +71,6 @@ 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 = "77d63f5ab27878b2c2119e05afc6b56b8e81bdee69a498d60d00be3919066637" [[asset]] path = "crates/ui-egui/src/i18n/fr.tsv" @@ -85,7 +81,6 @@ 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 = "4e6071f997faaaafec077ac10ddf88f54a24e18aeabbccedeb04904e2ced1441" [[asset]] path = "crates/ui-egui/src/i18n/de.tsv" @@ -96,7 +91,6 @@ 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 = "5c1d19bdf1624cd3194e50ee7993357fd24c22cd9b846868687db84634a3281f" [[asset]] path = "crates/ui-egui/src/i18n/lo.tsv" @@ -107,7 +101,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Lao UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "626329af32954bc02108187a25b2b0ee6c7b14c046497269d254d93406714561" [[asset]] path = "crates/ui-egui/src/i18n/te.tsv" @@ -118,7 +111,6 @@ 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 = "980d97209f373d842a3c6165c7702bc247d11b9b7ff9d2d9b2657e5849ed2def" [[asset]] path = "crates/ui-egui/src/i18n/it.tsv" @@ -129,7 +121,6 @@ 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 = "116228f89bd0d709a5dbf13b79d08307581544c3f55dea5dbf3a6aa11689c5f9" [[asset]] path = "crates/ui-egui/src/i18n/pl.tsv" @@ -140,7 +131,6 @@ 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 = "c351967f50288b572ab90c943a6c7cd6589aee2b494e2c885a0050354616d907" [[asset]] path = "crates/ui-egui/src/i18n/ru.tsv" @@ -151,7 +141,6 @@ 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 = "f4115c838b0f54aa57bc11b91fc2e9257dba53ea07222dcc8e430091eb0443df" [[asset]] path = "crates/ui-egui/src/i18n/hu.tsv" @@ -162,7 +151,6 @@ 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 = "a1e81d0e01e14d478569dc198749856f434e420a5b55ac2a9b9592e02e4c247a" [[asset]] path = "crates/ui-egui/src/i18n/bg.tsv" @@ -173,7 +161,6 @@ 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 = "c28196c5a47ae9aa29e3edb4e1c8602d40ee86da9d5b7c1913f0fb91fa9eb22f" [[asset]] path = "crates/ui-egui/src/i18n/kk.tsv" @@ -184,7 +171,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Kazakh UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "566e1ff35feb819983dffa31debc57ff766f44dc3f373cfe2b1042b3588bc184" [[asset]] path = "crates/ui-egui/src/i18n/ja.tsv" @@ -195,7 +181,6 @@ 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 = "bb6959b995cf55b3fd0c80508065a06acb5bc38967c4584020a2e19e7e0bf23f" [[asset]] path = "crates/ui-egui/src/i18n/uk.tsv" @@ -206,7 +191,6 @@ 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 = "55b325e50466f13e32655fc5562a5ba40cf9866a3663ba67a8d6510e70214baa" [[asset]] path = "crates/ui-egui/src/i18n/ar.tsv" @@ -217,7 +201,6 @@ 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 = "d2a2d4943d297ab85027f54035fcdf4a7dd06711fad8fb89245d3ac6ad6e0696" [[asset]] path = "crates/ui-egui/src/i18n/ckb.tsv" @@ -228,7 +211,6 @@ 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/mod.rs" -sha256 = "16c1d2ca75cc0848c738cd2b1b05fa822dafae5a16045ba3c8acb053c5e68095" [[asset]] path = "crates/ui-egui/src/i18n/tr.tsv" @@ -239,7 +221,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Turkish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "b86b12bf280bd17cfa91c115a40ac3805424ff03bc36d991aa108a7983d8ec62" [[asset]] path = "crates/ui-egui/src/i18n/lt.tsv" @@ -250,7 +231,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "fda08c4b7c4fd9e86c66b27eb14b5a981cc45aa628c1e960ecfd4433a746f326" [[asset]] path = "crates/ui-egui/src/i18n/hi.tsv" @@ -261,7 +241,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Hindi UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "53910a1edc9fdba3595d96b34d1da2acfea93d645516fb36da45341ae4e93677" [[asset]] path = "crates/ui-egui/src/i18n/id.tsv" title = "Indonesian interface translation catalog" @@ -271,7 +250,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Indonesian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "a65d03e5e27fd19cd7774aaa6971af65ebc11b32c20a3b5a6afa398bb93615b4" [[asset]] path = "crates/ui-egui/src/i18n/ko.tsv" title = "Korean interface translation catalog" @@ -281,7 +259,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Korean UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "288e2e7f30b738450b3d0c25131e6388ca28d1432d1112d85e69f279e93fe356" [[asset]] path = "crates/ui-egui/src/i18n/ro.tsv" @@ -292,7 +269,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Romanian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "e5387fddd56ba9c43e58f1ad92d985e9f6d3f4289336fe701caf679c92260372" [[asset]] @@ -304,7 +280,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Finnish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "24556b6b93d24a42799a01777fc4f902cd500847b0c3083e559fe0e0db3f6f30" [[asset]] path = "assets/icons/accessibility.svg" @@ -3393,7 +3368,7 @@ source = "https://github.com/storytold/craft-fonts (pinned by commit in .github/ 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); 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 leaves out for size" [[asset]] path = "crates/sign/tests/data/x509-rsa-sha1.pdf" @@ -3426,7 +3401,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "66eeb2ea187233ec19892271fbf1097d3698a9795f7f2c40245544eb11394292" [[asset]] path = "crates/ui-egui/src/i18n/sl.tsv" @@ -3437,7 +3411,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Slovene UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "c99143386d939d3219dd541fcde057261a94bc0ffc9516cd952a650543fe5532" [[asset]] @@ -3460,7 +3433,6 @@ 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/mod.rs" -sha256 = "8da2873e513f558c9bb6143498b7fdfdb8fe759c4771bfe3cc2df556fd23bbf3" [[asset]] path = "assets/icons/superscript.svg" @@ -3515,7 +3487,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Albanian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "08cef06c47b76c0cacdf8bea14547fd11938b07ca3adf0ed88370c9ad0164467" [[asset]] path = "crates/ui-egui/src/i18n/th.tsv" @@ -3526,7 +3497,6 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Thai UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "6b16edfad5b67e143127fd2112b30a9a859228f1ea38371c3d21b31c485bb27f" [[asset]] path = "crates/ui-egui/src/i18n/ca.tsv" @@ -3537,4 +3507,3 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Catalan UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "eda976052a1de1683c4d0142f20dbd5970e0e3af3ab5174e9f6c4089be958042" diff --git a/Cargo.lock b/Cargo.lock index 496eeab0a4..93c047eef3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1243,9 +1243,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +checksum = "6bb08299a6046833a879ace115697f12fd2bd6c8d3e93c909ffc9e0738e7cae0" dependencies = [ "cpubits", "ctutils", diff --git a/Cargo.toml b/Cargo.toml index 92f51290d4..2714debb62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,20 +89,20 @@ 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" -debug = "line-tables-only" incremental = false [profile.release] diff --git a/apps/pdfcraft-cli/src/main.rs b/apps/pdfcraft-cli/src/main.rs index 14500a3847..d0f23242d6 100644 --- a/apps/pdfcraft-cli/src/main.rs +++ b/apps/pdfcraft-cli/src/main.rs @@ -644,7 +644,7 @@ fn render(args: &[String]) -> Result<(), CliError> { let dpi = parse_dpi(flag(args, "--dpi").unwrap_or("96"))?; let out = flag(args, "--out").ok_or("render: missing --out (.png, .jpg, .tif or .pam)")?; // The file is what its name says (#248): a `.png` used to get a netpbm PAM stream. - let format = match Path::new(out).extension().and_then(|e| e.to_str()).map(str::to_ascii_lowercase).as_deref() { + let format = match Path::new(out).extension().and_then(std::ffi::OsStr::to_str).map(str::to_ascii_lowercase).as_deref() { Some("png") => Some(ImageFormat::Png), Some("jpg" | "jpeg") => Some(ImageFormat::Jpeg { quality: 90 }), Some("tif" | "tiff") => Some(ImageFormat::Tiff), @@ -779,7 +779,7 @@ fn collect(paths: &[&str]) -> Vec { if let Ok(rd) = std::fs::read_dir(&p) { stack.extend(rd.flatten().map(|e| e.path())); } - } else if p.extension().and_then(|e| e.to_str()).is_some_and(|e| e.eq_ignore_ascii_case("pdf")) { + } else if p.extension().and_then(std::ffi::OsStr::to_str).is_some_and(|e| e.eq_ignore_ascii_case("pdf")) { out.push(p); } } diff --git a/assets/demo/showcase.html b/assets/demo/showcase.html index 22e0619eae..b26f24565a 100644 --- a/assets/demo/showcase.html +++ b/assets/demo/showcase.html @@ -14,27 +14,27 @@ (highlight, sticky note, stamp, ...), so annotation geometry follows the layout. -->