diff --git a/AGENTS.md b/AGENTS.md index 039cd6a8..2ac90cfd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,7 +25,7 @@ An **asset** is any non-code material that the project includes, ships, embeds, - 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: - 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.rs` (approved by the owner, 2026-10-08), which is what generated appearances measure with and what survives hayro being retired. Adding anything to this list needs the user's explicit approval. diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index b7e25455..be77e718 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -4,7 +4,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). -## In this repository (269) +## In this repository (270) | Asset | Title | Author | Licence | Source | Used for | |---|---|---|---|---|---| @@ -222,6 +222,7 @@ 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) | +| `crates/fonts/src/std14.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. | 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. | | `docs/brand/artcraft-logo-white.png` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | | `docs/brand/artcraft-logo-white.svg` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | | `docs/brand/artcraft-logo.png` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. | diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index a4154d5a..3b08e844 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -2364,6 +2364,18 @@ kind = "data" usage = "Default CMYK colour conversion (vendored hayro-interpret)" sha256 = "73e1ba37d2bad5bab2a964f40a9eed96209666efc067c3322626214bbef234a0" +[[asset]] +path = "crates/fonts/src/std14.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." +licence = "MIT OR Apache-2.0" +licence_file = "LICENSE-MIT" +kind = "data" +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 = "4ce47db7e65467d4ea1d1642ff76dfcaeb9669c1811a93819d7e00e63fa9fcf8" + [[bundled]] crate = "epaint_default_fonts" version = "0.36.2" diff --git a/xtask/src/assets.rs b/xtask/src/assets.rs index 870d9b95..fc95a6ff 100644 --- a/xtask/src/assets.rs +++ b/xtask/src/assets.rs @@ -43,6 +43,12 @@ pub const BRAND_LICENCE: &str = "LicenseRef-Storyteller-Trademark"; pub const ADOBE_DATA_ALLOWED: &[(&str, &str)] = &[("hayro-cmap", "assets/cmaps.brotli"), ("hayro-interpret", "src/font/generated/metrics.rs")]; +/// First-party files on that same closed list: generated tables of Adobe-authored non-visual +/// technical data we hold ourselves rather than through a dependency. Each still needs an +/// `[[asset]]` entry with `adobe_data = true`, so its SHA-256 is checked and any change to the +/// table has to be re-attested deliberately. +pub const ADOBE_DATA_FILES: &[&str] = &["crates/fonts/src/std14.rs"]; + /// File extensions that count as assets wherever they appear in the repository. const ASSET_EXTENSIONS: &[&str] = &[ "png", "jpg", "jpeg", "gif", "svg", "ico", "icns", "webp", "bmp", "tif", "tiff", "avif", "heic", "ttf", "otf", "ttc", "woff", "woff2", "pfb", @@ -245,7 +251,7 @@ pub fn check(root: &Path, m: &Manifest, repo_files: &[String], lock: &BTreeSet<( if visual(&a.kind) && (mentions_adobe(&a.author) || mentions_adobe(&a.source) || mentions_adobe(&a.title)) { problems.push(format!("{}: {} from Adobe is forbidden (AGENTS.md §1.1)", a.path, a.kind)); } - if a.adobe_data { + if a.adobe_data && !(ADOBE_DATA_FILES.contains(&a.path.as_str()) && a.kind == "data") { problems.push(format!("{}: adobe_data is only allowed for the closed list in AGENTS.md §1.1", a.path)); } match std::fs::read(root.join(&a.path)) { @@ -570,6 +576,28 @@ mod tests { assert!(check(&root(), &font, &[], &l).iter().any(|p| p.contains("forbidden"))); } + #[test] + fn first_party_adobe_data_only_on_the_closed_list() { + let l = lock(&[]); + // The generated standard-14 table is on the list, as `kind = "data"`. + let mut ok = asset("crates/fonts/src/std14.rs", "Adobe (Core14 AFM metrics); tables by the PdfCraft contributors", "data", "MIT"); + ok.adobe_data = true; + let m = Manifest { asset: vec![ok], ..Default::default() }; + assert!(check(&root(), &m, &[], &l).is_empty(), "{:?}", check(&root(), &m, &[], &l)); + + // Any other first-party file claiming it is refused. + let mut sneaky = asset("Cargo.toml", "Adobe", "data", "MIT"); + sneaky.adobe_data = true; + let m = Manifest { asset: vec![sneaky], ..Default::default() }; + assert!(check(&root(), &m, &[], &l).iter().any(|p| p.contains("closed list"))); + + // Even on the list, it may only be data — never a typeface. + let mut wrong_kind = asset("crates/fonts/src/std14.rs", "Adobe", "font", "MIT"); + wrong_kind.adobe_data = true; + let m = Manifest { asset: vec![wrong_kind], ..Default::default() }; + assert!(!check(&root(), &m, &[], &l).is_empty()); + } + #[test] fn dependency_upgrade_forces_reaudit() { let m = Manifest { bundled: vec![bundled("other", "a.ttf", "Someone", "font", false)], ..Default::default() };