mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #2111 from IanHollow/codex/vectorcraft-document-fonts
Text: make every supplied font family available to documents
This commit is contained in:
+4
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (PDF.R1: shared PDF reader with windowed content scanning and explicit incomplete-content errors; scores and estimates unchanged; PDF.W1: guarded shared PDF writer; output behavior, scores and estimates unchanged; later 2026-10-14 merges: per-corner radius, #1682; Width Point Edit from the Width tool, #1814, #1630; guides, #1782, #1836; anchor X/Y/W/H, #1824; Snap to Grid over Snap to Pixel, #1816; toolbar and All Tools, #1751; Actions panel selection, #1629 in part; macOS save sheets, #1855, the Format menu withdrawn; rendering caches, #1667–#1792; untrusted files, #1852, #1862–#1873; failed-save dialog, #1685; Dim Images, #1683; headline numbers unchanged; Image Trace: Shapes, stroke caps, enhanced presets, gradients over noise, #1845 to #1848, headline numbers unchanged; verified PngSuite downloads, #1729; synthetic control-input budgets, #1709; merges of 2026-10-14: anchor Align and Distribute, #1636; Direct Selection fixes, #1674, #1666, #1743; Escape while typing, #1686; Pen clicks and a Precise Cursors command, #1663; Expand on repeats, #1756; Roughen and Scribble, #1643, #1648; file and input hardening, #1776–#1783, #1786, #1807; MCP limits and envelope, #1727, #1728; Image Trace levelling and Flat Logo on scans, #1647, #1657; a guide's position in the Transform panel is a convenience, not a parity claim, #1659; headline numbers unchanged; later merges of 2026-10-13: SVG import of CSS transforms, percentage lengths in symbols, Inkscape flowed text and pages, #1565, #1596, #1568, #1601; Warp Arc, #1578; Pathfinder Trim, Merge and Crop strokes, #1570; saves to folders that refuse the temporary file, #1620 in part; OpenType stylistic sets, #1607; intersect Smart Guides, #1602 in part; headline numbers unchanged; control transport deadlines, #1726; Image Trace edges, strokes, memory and three new options, measured in `docs/image-trace-quality.md`, headline numbers unchanged; community PRs and fixes of 2026-10-13: Polish interface, #1498; compact native saves, #1492; PDF and EPS paste as vector art, #1499; `.ai`, PDF, EPS and SVG import fixes, #1528, #1530, #1531, #1544, #1551, #1553; guide objects, #1534; Join after Average, #1533; Keyboard Shortcuts lists commands outside the menus, #1539; headline numbers unchanged; community PRs and fixes of late 2026-10-12: type that does not fit its frame is reported, #1471; Tabs panel drags, #1458; template layers in Outline view, #1486; dialog slider rails, #1483; Direct Selection anchor precedence, #1508; print-size images, #1517; French catalog complete again, #1511; headline numbers unchanged; Image Trace colour and photo presets, measured in `docs/image-trace-quality.md`, headline numbers unchanged; community PRs and fixes of 2026-10-12: Split Into Grid options, #1462; Transform Objects and Reflect across an angle, #1448 and #1460; Pathfinder on a group, #1450; unknown parameter keys refused, #1442; grayscale TIFFs with alpha, #1466 in part; many-object edits, #1429 in part; headline numbers unchanged; Image Trace places edges to a fraction of a pixel, measured in `docs/image-trace-quality.md`, headline numbers unchanged; Transform dialogs preview and the transform tools act on direct-selected anchors, #1412 and #1408; `.ai` compound path paint, #1410, overprint, #1388, and text-only PDF parts, #1387; community PRs: strokes wider than their shape, corner drags without the bounding box, pasted pictures, compound paths in `document.inspect`, MCP guide; headline numbers unchanged; community PRs: `.ai` editing-data follow-ups (gradient stops, type of objects with an appearance, short area-type frames), PDF bleed with editing data, dialog keyboard focus, art flush with an artboard, font rescan, symbol instance redraw, `--control` port check; headline numbers unchanged; Rectangular Grid and Polar Grid tool options, #1377 in part; `.ai` files with placed (linked) pictures open from their editing data, #1264; community PRs: `.ai` and PDF bleed and editing-data import, gradient shapes imported as paths, ruler origin, Align To, Live Corners corner selection; headline numbers unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; community PRs: graph designs, Graph Data worksheet and Graph Type options; Align both centres; Pen endpoint fixes; earlier: Effect › Brush Strokes landed: Photoshop-style filters 28 of 57, raster effects 40% → 48%; `.ai` gradients, meshes and artboard names from the editing data; headline numbers unchanged; `.ai` art styles and clipping fills from the editing data; headline numbers unchanged; `editingData: "always"`; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (all explicitly supplied document-font families registered; PDF.R1: shared PDF reader with windowed content scanning and explicit incomplete-content errors; scores and estimates unchanged; PDF.W1: guarded shared PDF writer; output behavior, scores and estimates unchanged; later 2026-10-14 merges: per-corner radius, #1682; Width Point Edit from the Width tool, #1814, #1630; guides, #1782, #1836; anchor X/Y/W/H, #1824; Snap to Grid over Snap to Pixel, #1816; toolbar and All Tools, #1751; Actions panel selection, #1629 in part; macOS save sheets, #1855, the Format menu withdrawn; rendering caches, #1667–#1792; untrusted files, #1852, #1862–#1873; failed-save dialog, #1685; Dim Images, #1683; headline numbers unchanged; Image Trace: Shapes, stroke caps, enhanced presets, gradients over noise, #1845 to #1848, headline numbers unchanged; verified PngSuite downloads, #1729; synthetic control-input budgets, #1709; merges of 2026-10-14: anchor Align and Distribute, #1636; Direct Selection fixes, #1674, #1666, #1743; Escape while typing, #1686; Pen clicks and a Precise Cursors command, #1663; Expand on repeats, #1756; Roughen and Scribble, #1643, #1648; file and input hardening, #1776–#1783, #1786, #1807; MCP limits and envelope, #1727, #1728; Image Trace levelling and Flat Logo on scans, #1647, #1657; a guide's position in the Transform panel is a convenience, not a parity claim, #1659; headline numbers unchanged; later merges of 2026-10-13: SVG import of CSS transforms, percentage lengths in symbols, Inkscape flowed text and pages, #1565, #1596, #1568, #1601; Warp Arc, #1578; Pathfinder Trim, Merge and Crop strokes, #1570; saves to folders that refuse the temporary file, #1620 in part; OpenType stylistic sets, #1607; intersect Smart Guides, #1602 in part; headline numbers unchanged; control transport deadlines, #1726; Image Trace edges, strokes, memory and three new options, measured in `docs/image-trace-quality.md`, headline numbers unchanged; community PRs and fixes of 2026-10-13: Polish interface, #1498; compact native saves, #1492; PDF and EPS paste as vector art, #1499; `.ai`, PDF, EPS and SVG import fixes, #1528, #1530, #1531, #1544, #1551, #1553; guide objects, #1534; Join after Average, #1533; Keyboard Shortcuts lists commands outside the menus, #1539; headline numbers unchanged; community PRs and fixes of late 2026-10-12: type that does not fit its frame is reported, #1471; Tabs panel drags, #1458; template layers in Outline view, #1486; dialog slider rails, #1483; Direct Selection anchor precedence, #1508; print-size images, #1517; French catalog complete again, #1511; headline numbers unchanged; Image Trace colour and photo presets, measured in `docs/image-trace-quality.md`, headline numbers unchanged; community PRs and fixes of 2026-10-12: Split Into Grid options, #1462; Transform Objects and Reflect across an angle, #1448 and #1460; Pathfinder on a group, #1450; unknown parameter keys refused, #1442; grayscale TIFFs with alpha, #1466 in part; many-object edits, #1429 in part; headline numbers unchanged; Image Trace places edges to a fraction of a pixel, measured in `docs/image-trace-quality.md`, headline numbers unchanged; Transform dialogs preview and the transform tools act on direct-selected anchors, #1412 and #1408; `.ai` compound path paint, #1410, overprint, #1388, and text-only PDF parts, #1387; community PRs: strokes wider than their shape, corner drags without the bounding box, pasted pictures, compound paths in `document.inspect`, MCP guide; headline numbers unchanged; community PRs: `.ai` editing-data follow-ups (gradient stops, type of objects with an appearance, short area-type frames), PDF bleed with editing data, dialog keyboard focus, art flush with an artboard, font rescan, symbol instance redraw, `--control` port check; headline numbers unchanged; Rectangular Grid and Polar Grid tool options, #1377 in part; `.ai` files with placed (linked) pictures open from their editing data, #1264; community PRs: `.ai` and PDF bleed and editing-data import, gradient shapes imported as paths, ruler origin, Align To, Live Corners corner selection; headline numbers unchanged; G2: Film Grain added; Photoshop effects 29/57; 28 filters remain; community PRs: graph designs, Graph Data worksheet and Graph Type options; Align both centres; Pen endpoint fixes; earlier: Effect › Brush Strokes landed: Photoshop-style filters 28 of 57, raster effects 40% → 48%; `.ai` gradients, meshes and artboard names from the editing data; headline numbers unchanged; `.ai` art styles and clipping fills from the editing data; headline numbers unchanged; `editingData: "always"`; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs
|
||||
on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON
|
||||
@@ -128,6 +128,8 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
||||
|
||||
## Progress log
|
||||
|
||||
- 2026-10-14: Document fonts register every explicitly supplied craft-fonts family after the existing Japanese, Arabic and Thai prefix; optional empty input remains supported. Headline scores and estimates are unchanged.
|
||||
|
||||
- 2026-10-13: PngSuite downloads use pinned HTTPS files and a SHA-256 manifest; no archive extraction (#1729).
|
||||
|
||||
| Date | What landed |
|
||||
@@ -171,6 +173,7 @@ The full pre-standard record of what landed is kept in [docs/roadmap.md](docs/ro
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | minor | Document fonts register every explicitly supplied craft-fonts family after the existing Japanese, Arabic and Thai prefix; optional empty input remains supported. Headline scores and estimates are unchanged. |
|
||||
| 2026-10-14 | minor | Progress log rows for the later merges of 2026-10-14 (#1630–#1875 as listed there); headline numbers unchanged. |
|
||||
| 2026-10-13 | minor | Pinned PngSuite HTTPS files verified by SHA-256 before publication; bounded downloads replace archive extraction (#1729). Scores and hours unchanged. |
|
||||
| 2026-10-13 | minor | Bounded synthetic control input (#1709): counts and queued events validated before mutation; control-channel bursts yield between frames. Scores and hours unchanged. |
|
||||
|
||||
@@ -60,7 +60,11 @@ impl CraftFont {
|
||||
/// The craft-fonts faces for Japanese text, best for document text first: Mincho (serif) families,
|
||||
/// then the others, regular weights before bold. Empty when built without craft-fonts.
|
||||
pub fn japanese_document_fonts() -> Vec<&'static CraftFont> {
|
||||
let mut v: Vec<&'static CraftFont> = CRAFT_FONTS.iter().filter(|f| f.is_japanese()).collect();
|
||||
japanese_document_fonts_from(CRAFT_FONTS)
|
||||
}
|
||||
|
||||
fn japanese_document_fonts_from(fonts: &[CraftFont]) -> Vec<&CraftFont> {
|
||||
let mut v: Vec<_> = fonts.iter().filter(|f| f.is_japanese()).collect();
|
||||
v.sort_by_key(|f| (!f.is_mincho(), f.is_bold()));
|
||||
v
|
||||
}
|
||||
@@ -69,11 +73,17 @@ pub fn japanese_document_fonts() -> Vec<&'static CraftFont> {
|
||||
/// [`japanese_document_fonts`] order, then the Arabic ones in manifest order (Noto Sans Arabic
|
||||
/// first: the fallback for Arabic text; the other families are picked by name), then the Thai ones
|
||||
/// (Noto Sans Thai: the fallback for Thai text where no Thai font is installed, and on the web).
|
||||
/// Remaining faces follow in manifest order, so every explicitly supplied family can be selected.
|
||||
/// Empty when built without craft-fonts.
|
||||
pub fn document_fonts() -> Vec<&'static CraftFont> {
|
||||
let mut v = japanese_document_fonts();
|
||||
v.extend(CRAFT_FONTS.iter().filter(|f| f.is_arabic() && !f.is_japanese()));
|
||||
v.extend(CRAFT_FONTS.iter().filter(|f| f.is_thai() && !f.is_japanese() && !f.is_arabic()));
|
||||
document_fonts_from(CRAFT_FONTS)
|
||||
}
|
||||
|
||||
fn document_fonts_from(fonts: &[CraftFont]) -> Vec<&CraftFont> {
|
||||
let mut v = japanese_document_fonts_from(fonts);
|
||||
v.extend(fonts.iter().filter(|f| f.is_arabic() && !f.is_japanese()));
|
||||
v.extend(fonts.iter().filter(|f| f.is_thai() && !f.is_japanese() && !f.is_arabic()));
|
||||
v.extend(fonts.iter().filter(|f| !f.is_japanese() && !f.is_arabic() && !f.is_thai()));
|
||||
v
|
||||
}
|
||||
|
||||
@@ -89,6 +99,36 @@ pub fn japanese_ui_fonts(bold: bool) -> Vec<&'static CraftFont> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn document_fonts_keep_script_priority_and_include_every_face_once() {
|
||||
let font = |family, style, scripts| CraftFont { family, style, scripts, bytes: &[] };
|
||||
let fonts = [
|
||||
font("Chinese", "Regular", &["Hans"]),
|
||||
font("Thai", "Regular", &["Thai", "Arab"]),
|
||||
font("Gothic", "Regular", &["Jpan"]),
|
||||
font("Mincho", "Bold", &["Jpan"]),
|
||||
font("Arabic", "Regular", &["Arab"]),
|
||||
font("Mincho", "Regular", &["Jpan", "Hans"]),
|
||||
font("Thai only", "Regular", &["Thai"]),
|
||||
font("Latin", "Regular", &["Latn"]),
|
||||
];
|
||||
let ordered: Vec<_> = document_fonts_from(&fonts).into_iter().map(|f| (f.family, f.style)).collect();
|
||||
assert_eq!(
|
||||
ordered,
|
||||
[
|
||||
("Mincho", "Regular"),
|
||||
("Mincho", "Bold"),
|
||||
("Gothic", "Regular"),
|
||||
("Thai", "Regular"),
|
||||
("Arabic", "Regular"),
|
||||
("Thai only", "Regular"),
|
||||
("Chinese", "Regular"),
|
||||
("Latin", "Regular"),
|
||||
]
|
||||
);
|
||||
assert!(document_fonts_from(&[]).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_fonts_follow_the_list() {
|
||||
if CRAFT_FONTS.is_empty() {
|
||||
|
||||
@@ -1492,9 +1492,9 @@ impl FontDb {
|
||||
|
||||
fn new(font_paths: FontPaths) -> Self {
|
||||
let mut faces = Vec::new();
|
||||
// The bundled fonts, then the craft-fonts faces (when built with them): Japanese, Mincho
|
||||
// first, then Arabic with Noto Sans Arabic first. They are fallbacks for those scripts
|
||||
// after the requested and bundled fonts, and families users can pick by name.
|
||||
// Bundled fonts first, then explicitly supplied craft-fonts faces: Japanese (Mincho
|
||||
// first), Arabic, Thai, then remaining faces in manifest order. Existing script fallback
|
||||
// priorities stay ahead of the additional families users can now pick by name.
|
||||
let craft = crate::craft_fonts::document_fonts().into_iter().map(|f| f.bytes);
|
||||
for data in BUNDLED.iter().copied().chain(craft) {
|
||||
for (i, spec) in enumerate_faces(data) {
|
||||
|
||||
@@ -518,6 +518,19 @@ fn japanese_text_uses_the_craft_fonts_mincho_after_the_bundled_fonts() {
|
||||
assert_eq!(db().face_covering('a').unwrap().family, FALLBACK_FAMILY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_supplied_craft_font_families_are_registered_without_system_fonts() {
|
||||
if CRAFT_FONTS.is_empty() {
|
||||
eprintln!("skipped: built without craft-fonts (set CRAFT_FONTS_DIR to a checkout)");
|
||||
return;
|
||||
}
|
||||
let db = FontDb::with_font_dirs(vec![]);
|
||||
for font in CRAFT_FONTS {
|
||||
let face = db.face(font.family, font.style).unwrap();
|
||||
assert_eq!(face.family, font.family, "{} {}", font.family, font.style);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn japanese_text_lays_out_without_the_craft_fonts() {
|
||||
// Built either way, Japanese text lays out (as missing glyphs when no font has them).
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
# Development
|
||||
|
||||
> **Last updated:** 2026-10-13 · **Change:** verified PngSuite downloads (#1729).
|
||||
> **Last updated:** 2026-10-14 · **Change:** document-font registration for all explicitly supplied faces.
|
||||
|
||||
## Web build
|
||||
|
||||
@@ -139,6 +139,9 @@ CRAFT_FONTS_DIR="$PWD/../craft-fonts" cargo xtask ci # also runs the Japanese-
|
||||
so they are the fallback for Japanese after the requested font; installed system fonts come after.
|
||||
Noto Sans Thai (when the checkout has it) is the fallback for Thai where no Thai font is
|
||||
installed, and the web build fetches it before the app starts (`crates/text/web-fonts.txt`).
|
||||
All other supplied faces follow those existing document fallbacks in manifest order, so they
|
||||
can also be selected by family name. This does not change which faces the web build embeds
|
||||
or fetches, and no craft-fonts faces are registered when the optional input is absent.
|
||||
- UI: `theme::install_fonts` adds them at the end of every egui family (BIZ UDPGothic first), after
|
||||
the UI fonts and before the installed fonts `ui_fonts.rs` discovers for other scripts.
|
||||
- Tests that need Japanese glyphs skip with a message when built without craft-fonts. The FreeBSD
|
||||
@@ -343,4 +346,5 @@ do not replace expected hashes automatically in response to a download mismatch.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | minor | Document registration of every explicitly supplied craft-fonts face after the existing script-specific prefix; empty input and web selection remain unchanged. |
|
||||
| 2026-10-13 | minor | Document pinned PngSuite files, integrity checks and download budgets (#1729). |
|
||||
|
||||
Reference in New Issue
Block a user