Commit Graph
46 Commits
Author SHA1 Message Date
bflatastic 3a88ad0855 Fix #1529: Linux reads the font folders fontconfig is set up with
The font scan read /usr/share/fonts, /usr/local/share/fonts, ~/.fonts and the
XDG data folders. Packages add folders outside those to fontconfig's
configuration (TeX Gyre under /usr/share/texmf/fonts), so fc-list and other
apps showed fonts VectorCraft didn't have. The scan now also reads the <dir>
folders of /etc/fonts/fonts.conf and the files it includes (conf.d, the user's
own), as the fontconfig documentation describes them. The files are read as
they are: no library is linked and no program is run.
2026-10-13 06:56:37 +07:00
bflatasticandsanyamsingh001 4251e337c1 Fonts: a character no font covered is looked for again after a font rescan (#992)
A character missing from every installed font was remembered as missing for the whole
session, so installing a font that has it didn't help until a restart. A rescan of the
font folders now forgets those misses, and a search a rescan overtook doesn't record one.

Taken from #992 by sanyamsingh001, without its font file probe.

Co-authored-by: sanyamsingh001 <314051937+sanyamsingh001@users.noreply.github.com>
2026-10-12 16:43:41 +07:00
Ikki Nishihara ce38eef890 fix: フォントのフルネームを正しい書体へ解決する #1258 2026-10-12 07:25:51 +07:00
bflatasticandClaude Opus 5.5 cc2f45b129 Font menu: a Thai script filter
The font menu's script filter offered Japanese and Latin only, so Thai
fonts had to be found by name among every installed family. It now has
Thai too: the families whose character map has Thai. Latin lists the
families with neither Japanese nor Thai.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:51:32 +07:00
bflatasticandClaude Opus 5.5 fba3702103 Type: Thai falls back to a font made for Thai
Thai typed in a font without Thai glyphs (Source Sans 3, a Latin font)
took the first loaded face that had them, or the first installed file
that did, in path order: on one Windows machine a display face (Kanit)
rather than Leelawadee UI. Characters of Thai, Lao, Khmer and Myanmar
now try fonts made for their script first, installed ones loaded on
demand (Leelawadee UI, Tahoma, Thonburi, Sukhumvit Set, Noto Sans Thai,
the TLWG fonts for Thai), then the fallback as before. Latin beside
them keeps the font chosen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:42:31 +07:00
Fabio William Conceição 89812275d7 Part of #394: Show Font Names in English labels the font menus. 2026-10-10 14:10:31 +07:00
dotCooCoo 7b7e10e82e Fonts: a folder search skips suitcase fonts whose resource fork is over 8 MB
A folder search reads at most 8 MB of each font file. The suitcase
reader reads a suitcase font's resource fork whole, up to 256 MB.
Before this change, the search applied its limit to each font only
after that read. One search thread could read 256 MB from a single
suitcase and hold a copy of its fonts as well. The search now reads a
suitcase font only when its resource fork is 8 MB or less. The font
scan still reads each suitcase font's resource fork whole, up to
256 MB.

Docs: docs/mcp.md.
2026-10-10 08:42:32 +07:00
dotCooCoo 5709e636a5 Fonts: missing fonts are listed when a document opens, with Find Fonts and a folder search
When a document opens with fonts that aren't available, fonts used
only in its symbols included, VectorCraft lists them in a Missing
Fonts dialog after the missing linked file questions, one document at
a time, with Find Fonts and Close. Find Fonts opens Type › Find Font
on the first missing font of the layers' type, to replace it. After
Find Fonts or Close the dialog doesn't open again for that open; when
another dialog replaces it, it opens again once that dialog closes.

Search Fonts Folder (the Fonts folder File › Package writes next to
the document) and Find in Folder… search a folder and its subfolders
for the fonts' files, and Add Fonts copies the files the user chooses
into a Fonts folder next to the preferences. The desktop app and
vectorcraft-cli read that folder with the system's font folders. Type
› Find Font has a Find in Folder… button too when fonts the document
uses are missing. The web app shows no dialog; a status message says
how many fonts aren't available.

- text.missingFonts lists each missing family and style once,
  whatever version the document's type names, and leaves out CSS
  generic families such as sans-serif. text.findFontFiles searches a
  folder on up to 8 threads and returns at once; text.findFontFiles {}
  reports the search, and {stop: true} stops it. A search reads only
  what the font scan reads of font files (their table directories and
  name, fvar and OS/2 tables) and, on macOS, of suitcase fonts, and
  lists a file for a font only when the file makes the font resolve
  exactly. It does not enter app packages, the Program Files and
  ProgramData folders, the system's folders at the root of a volume,
  the Shared and Public folders in Users, a home folder's Library,
  AppData, Applications, snap and dot folders, a Library folder's app
  data folders or the folders the environment names for apps, and it
  skips other hidden folders and does not follow links below the
  picked folder. It ends after 60 s by default, after 10,000,000
  entries listed, with more than 1,000,000 folders waiting, after
  10,000 font files read or 1,000 kept, or once every font has a file;
  Stop and Close end it too.
- text.addFontFiles copies only files the last search found. Of
  those, it copies only regular .ttf, .otf, .ttc, .otc, .woff and
  .woff2 files and suitcase fonts with their resource fork, at most
  256 MB a file and 1 GB in all. It never replaces a file: a file with
  the same contents is kept, and when another file has that name, the
  copy gets a number (Name 2.otf). The fonts are then scanned again,
  and type set in them redraws.
- ui.missingFontsDialog and ui.findFontsInFolder open the dialog for
  agents; docs/control-protocol.md lists its fields.
- File › Package gives a font file whose name has no font extension
  the extension that matches its data (.ttf, .otf or .ttc).
- vectorcraft-text adds set_app_font_dir, which system_font_dirs
  reads, WantedFonts, which reads a font file's names as the font scan
  does, is_font_file and is_suitcase. #762 split its face reader, which
  now takes read budgets: file_face_names_within tries the suitcase
  reader first, and reader_face_names_within applies the budgets to
  each font. vectorcraft-format adds write_new_with.

Docs: docs/mcp.md, docs/control-protocol.md, ROADMAP.
2026-10-10 08:42:32 +07:00
bflatasticandClaude Opus 5.5 72c9cec0e0 Fix #847: draw Underline and Strikethrough
The styles were stored on the text and written to SVG's text-decoration,
but the type was drawn without the lines. vectorcraft_text::decorations
now gives each underlined or struck-through stretch of a run on a line
its bar, placed and sized from the font's own underline and strikeout
metrics (with fallbacks for fonts that have none). The canvas, Create
Outlines, PDF export (outlined and real text) and SVG's outlined text
draw them in the run's paint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:03:04 +07:00
Juan Manuel Verges SolanasandClaude Opus 5.5 562e09707a Fix #813: type can name an installed version of its font
A font library can hold two versions of one family and style (a new
Montserrat-Bold.ttf beside an old montserrat.ttf). The font database kept
only the first one loaded, so type set in the other couldn't be matched
when a PDF or .ai was opened: it came in as outlines. Now every version
loads (the first stays the one family and style resolve to), PDF import
tries the other versions when the glyphs differ, and type set in a version
the family and style alone wouldn't pick names it in CharStyle::font_version
(left out when None, so documents without it are unchanged). Layout,
shaping, the substituted-glyph highlight, Find Font, Package and Document
Info follow it; changing the font clears it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:26:51 +00:00
bflatastic 8c1be41e08 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	ROADMAP.md
2026-10-10 01:56:46 +07:00
BFlat 116573ba86 Merge pull request #782 from dotCooCoo/feat/package-font-resolution
Package: fonts found by any of their names are copied, and skipped fonts are named
2026-10-10 01:43:01 +07:00
dotCooCoo 75f2145b92 Package: fonts found by any of their names are copied, and skipped fonts are named
File › Package and Document Info › Font Details looked fonts up with
FontDb::face and compared the face's family with the name the document
stores. A font a document named by another of its names (a PostScript
or localized name, as SVG and PDF files do) was reported as not
available and left out of the package, although the canvas drew it and
exports embedded it.

- Package and Font Details resolve fonts with FontDb::resolve, as
  text.fonts and the renderer do. A style the family lacks is still
  copied as its closest style; the report now names the style it
  copies, and Font Details lists the font as substituted, with that
  style's file and permission.
- FontFace::embeddable reads fsType as exports do (Embedding), so fonts
  that allow bitmap embedding only (bit 9), or that set the restricted
  bit together with reserved bit 0 (0x0003), are no longer copied.
  Document Info's permission labels follow the same rule: when a font
  sets more than one usage bit, the label names the most permissive
  one.
- The Package dialog and its status line name the fonts it didn't copy.
2026-10-09 08:35:16 -07:00
dotCooCoo 4b00c2d968 Part of #579: macOS fonts registered from other folders are listed too
The font scan read only the macOS font folders and the Additional
Fonts Folder, so fonts that apps and font managers register with
CoreText from their own folders were missing from the font menus, and
exports set such type in the fallback font. CoreText's font manager
lists them with the installed fonts.

- `mac_fonts.rs` lists the files of the fonts the font manager has
  available (`CTFontManagerCopyAvailableFontURLs`, through
  objc2-core-text), keeping only file URLs as `open_documents.rs` does
  (#433). The desktop app and `vectorcraft-cli` install it as they
  install the DirectWrite lister on Windows, and the scan reads the
  files outside the font folders in place.
- The scan leaves out faces with no outlines the font engine draws (no
  glyf, CFF, CFF2 or VARC table), on every platform. CoreText lists
  Apple's PingFang UI interface font (macOS 27), whose outlines are in
  an hvgl table; if the scan cataloged it, PingFang SC would count as
  installed, and Chinese characters in fallback text, Japanese kanji
  included, would draw blank.
- Tests: the list holds the installed fonts by full path, a font
  registered from another folder is listed while it is registered, and
  a face without outlines the engine draws isn't cataloged.
2026-10-09 08:16:33 -07:00
Matthew FarrowandClaude Sonnet 5.5 e1d35131d3 Fonts: find suitcase fonts, whose font data is in the resource fork
macOS lists fonts such as the ones Microsoft Office installs in
/Library/Fonts/Microsoft (Bookman Old Style, Impact, Georgia, Tahoma, ...) but
their files have nothing in the data fork and no font extension: the fonts are
`sfnt` resources in the resource fork. The font scan only read data forks of
.ttf/.otf/.ttc/.otc files, so those families were never cataloged and a file
using one (an EPS naming BookmanOldStyle-Bold) showed the font as missing.

The scan now catalogs a file with an empty data fork and a resource fork by
the fonts in that fork, and loading reads them the same way. The fork reader
(crates/text/src/suitcase.rs) follows Apple's published resource file format,
caps what a damaged fork can make it read and never panics. macOS only.

Tests: the fork reader on a synthetic fork built around a bundled font,
including truncated and garbage forks; a macOS scan of a suitcase file.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 10:05:18 -04:00
Ahmed Moussa 3c85f3f9e3 feat(text): load craft-fonts' Arabic families, fetch them on web
Desktop builds made with CRAFT_FONTS_DIR now load craft-fonts' 12 Arabic families into the document font database. Noto Sans Arabic comes first and is the fallback for Arabic text. Cairo, Tajawal, Almarai, IBM Plex Sans Arabic, Noto Kufi Arabic, Amiri, Alexandria, Fustat, Reem Kufi, Aref Ruqaa and Gulzar can be picked by name from the font menus.

The web build doesn't embed these fonts because they would make the wasm too large. It fetches them from beside the wasm instead:
- crates/text/web-fonts.txt lists each face as startup or background.
- build.rs turns that list into vectorcraft_text::WEB_FONTS, with each face's URL (fonts/<sha16>/<file>) and SRI hash taken from the craft-fonts manifest.
- packaging/web/copy-fonts.sh, a Trunk post_build hook, copies the font files and their OFL licences there.
- apps/vectorcraft-web/src/fonts.rs fetches Noto Sans Arabic before the app starts, so Arabic text never shows as boxes. It loads the other faces in the background and logs `web font …` for any that fail.

Because fonts can now arrive after startup, the Type tool's layout cache also checks the font database's generation, so text lays out again when new fonts arrive.

_headers and .htaccess serve fonts/* as font/ttf and cache it as immutable. packaging/web/README.md and docs/development.md explain the fonts folder, and ROADMAP.md lists the Arabic typefaces under Type. Also adds Ahmed Moussa to contributors/people.toml.

Signed-off-by: Ahmed Moussa <moussa.ahmed95@gmail.com>
2026-10-09 16:09:34 +03:00
bflatasticandClaude Opus 5.5 e92bbdbdac Fix #683: Preferences > Type > Additional Fonts Folder
VectorCraft found fonts only in the system's font folders (and, on Windows,
those font services activate). A new preference names one more folder, read
with its subfolders after the platform's: its fonts are listed in the font
menus and used as if installed, without installing them.

- vectorcraft_text::set_user_font_dirs / user_font_dirs: folders
  system_font_dirs adds to every scan (none on wasm).
- prefs fontsFolder (Type > Options > Additional Fonts Folder), trimmed; when
  it changes after the first scan, the fonts are scanned again at once, so the
  folder's fonts appear (or go) and type in them lays out again.
- The label is translated where Additional Plug-ins Folder is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:05:16 +07:00
imachusandClaude Opus 5.5 4411688b3d Type: Character Alignment on the ICF top and bottom (ideographic character face)
Character panel menu › Character Alignment gains ICF Top/Right and ICF Bottom/Left, and
`charAlign` takes `icfTop` / `icfBottom`: a character smaller than the largest on its line lines
up its ideographic character face's top (right, vertical) or bottom (left) with the big one's.

`FontFace::icf_margins` places the ICF inside the em box as the OpenType baseline tags define it
(https://learn.microsoft.com/en-us/typography/opentype/spec/baselinetags): `icfb` / `icft` of the
BASE table's horizontal and vertical axes against `ideo` / `idtp` (else the OS/2 typographic
descender and one em), for Han ideographs (else kana, else the first script). Without them, as that
page allows, the average ink box of some ideographs and kana; a face without ideographs uses its
em box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:14:17 +09:00
bflatasticandClaude Opus 5.5 5854346053 Fix #579: fonts activated by font services such as Adobe Fonts are listed on Windows
Font services load their fonts with GDI at run time, from files in their
own folders, without installing them: neither the font folders nor the
registry list them, so the font scan never saw them. DirectWrite's system
font collection holds them since Windows 10 1607.

- vectorcraft-text: `set_platform_font_files` lets the app name font files
  the platform knows; each scan and each check for installed fonts asks
  again and reads those outside the font folders. A file named by itself
  is read whatever its extension (font services keep fonts in files
  without one).
- The desktop app lists the local files of DirectWrite's system font
  collection on Windows (`system_fonts.rs`, through the windows crate
  already in the build), read in place.
- The check for fonts installed while the app was in the background runs
  on a thread: DirectWrite's check for updates takes about 50 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 04:16:14 +07:00
bflatasticandClaude Opus 5.5 64cbee2a96 Fix #443: installed fonts outside the font folders and fonts installed while the app runs reach the font menus
The scan read only the platform's font folders, once per session (or on
Character panel menu > Refresh Font List). Fonts Windows registers outside
its font folders (installed as shortcuts, or by programs into their own
folders) never listed, nor did fonts installed while the app was open.

- Windows: the font files registered under the local machine's and the
  user's Fonts registry keys outside the scanned folders are scanned too
  (windows-registry, the windows-rs project's safe registry API).
- Linux/BSD: the XDG data folders' fonts (XDG_DATA_HOME, XDG_DATA_DIRS:
  Flatpak, Snap, NixOS, Guix) and a Flatpak sandbox's host fonts
  (/run/host/fonts, local-fonts, user-fonts); macOS: /Network/Library/Fonts.
- The global database looks the platform's paths up again at each scan,
  and a scan's roots may be font files as well as folders.
- FontDb::installed_fonts_changed compares the folders the last scan read
  (their modification times, and the paths it started from); the app
  checks it when its window comes back to the front and rescans
  (text.rescanFonts) only when fonts were installed or removed meanwhile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:03:53 +07:00
bflatasticandClaude Opus 5.5 5865e4cb51 Type: Top-to-Top Leading follow-ups (review of #385)
- The em box top that Top-to-Top Leading asks of every glyph's line metrics parsed the font's
  cmap and vertical metrics per glyph on every layout: each face now reads it once.
- The Paragraph panel menu shows Top-to-Top / Bottom-to-Bottom Leading with the East Asian
  options (Preferences › Type), as the Mojikumi Set does, and Reset Panel goes back to
  Bottom-to-Bottom Leading, the default.
- Saved as `leading_model`, like the other paragraph attributes in files.
- Simplified Chinese (landed since) translates the two menu items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:25:18 +07:00
bflatasticandClaude Opus 5.5 cea2ee6a54 Type: font menu previews end safely, rows and samples cost less per frame (review of #339)
- A preview whose menu has gone (the panel isn't drawn: text deselected,
  panel closed) or is closing (Escape, a press outside the menu) is undone
  at the start of the frame, before the canvas sees the input: a canvas
  drag no longer runs inside the preview's interaction and gets rolled
  back with it. The menu also ends the preview in the frame it closes.
- The list fits the popup (it was taller than the popup, which then
  scrolled too), so the current family is centred in view on opening;
  ↑/↓ scroll only as far as needed.
- Type › Font (in-window menu bar): each item keeps room for its sample
  after the name, so long family names no longer run under it.
- Rows are listed again only when the query, filters, expanded families,
  favourites or font list change, not every frame.
- Samples: one budget per frame across every menu (Type › Font gave each
  item its own), at most 8 rendering at once, the worker asks for a
  repaint when it is done instead of polling, the cache holds 512, and
  one function draws a sample for both menus.
- Font menus use menu_family_list (the hidden-family rule lives there);
  FontClass::label is gone (the menu's translated labels are the only
  ones).
- Tests: a preview left by a menu that is gone is undone; a press
  outside the open menu ends the preview in that frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:24:44 +07:00
bflatasticandClaude Opus 5.5 e792d2a964 Type: vertical_glyph's doc names the two values it returns (review of #343)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:23:48 +07:00
Brandon Thomas b33e964aec Merge pull request #339 from imachus/pr/ja-font-menu
Type: a font menu with samples, live preview, script and kind filters, styles and favourites

# Conflicts:
#	crates/ui-egui/src/i18n/ja.tsv
2026-10-07 17:03:08 -04:00
imachusandClaude Opus 5.5 681d18a08f Type: vertical type takes upright glyphs' cells from the font's vertical metrics
Upright glyphs in vertical type advanced one em (or their horizontal
advance, if wider) and turned about a fixed point 0.38 em above the
baseline. Fonts that carry vertical metrics now place them as they ask:

- `FontFace::vertical_glyph`: a glyph's advance down the column (`vmtx`)
  and the height of its vertical origin (`VORG`, else the glyph's top
  plus its top side bearing, as in TrueType fonts); `None` without
  `vhea`/`vmtx` or with values outside a few ems.
  `FontFace::ideographic_centre`: the em box centre from an ideograph's
  cell, else 0.38.
- The layout advances an upright glyph by its vertical advance and hangs
  it from its vertical origin; tate-chu-yoko blocks and point type's
  anchor use the font's em box centre. Fonts without vertical metrics
  are laid out exactly as before.
- Hiragino's tables give the values the layout assumed (one em, origin
  0.88 em), so Japanese vertical type in it renders pixel for pixel the
  same; this is the base for proportional vertical metrics (`vpal`) and
  for fonts whose em box sits elsewhere.
- `test_fonts::vertical_font`: Source Sans 3 with `vhea`/`vmtx` (and
  optionally `VORG`) built in code, one glyph 1.4 em tall hanging from
  1.1 em; tested with and without `VORG`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:12:44 +09:00
imachusandClaude Opus 5.5 52e1c0eca0 Type: a font menu with samples, live preview, script and kind filters, styles and favourites
The Character and Properties panels' font menu was a plain searchable
list of names. With hundreds of installed families (and Japanese names
that say little to someone who can't read them) a name isn't enough.

- Each row shows the family's name and a sample of the selected text set
  in it (a generic sample when the font lacks its characters). Samples
  are rendered off the UI thread, a few per frame, and only for the rows
  in view (the list is virtualised).
- The row under the pointer or reached with ↑/↓ previews its font on the
  selected text, as one live interaction with nothing in the history; a
  click or Enter applies it as one step, Escape or closing the menu puts
  the text back. The current family is highlighted and scrolled into
  view, also when the document names it in another language.
- Filters by script (Japanese, Latin) and kind (serif/Mincho, sans
  serif/Gothic, rounded, script/brush, monospaced, decorative), from the
  font's OS/2 classification and, for CJK fonts whose tables seldom say,
  its names. `FontTraits`/`FontClass` in the text crate; installed
  families get them from the same scan as their names.
- ▸ (or →/←) lists a family's styles; a style row previews and applies
  that style.
- ☆ stars a family; the ★ filter shows only the favourites (kept with
  the UI state).
- Preferences › Type › Enable in-menu font previews and Font Preview
  Size now turn the samples off and size the rows; the in-window Type ›
  Font menu (Windows, Linux) shows a sample beside each name.
- Families whose name starts with a dot (the system's own) are hidden.
- Catalog rows for the new labels in zh-hant (complete) and ja.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:51:33 +09:00
BFlatandClaude Opus 5.5 079f9a8b9a Fix #296: variable fonts list and draw every named style
The font database made one style per font file, so a variable font
such as Figtree[wght].ttf listed only its default instance (Light).
Faces now also yield their fvar named instances, each a style of the
family named by its subfamily name (the default instance is the face
itself; unnamed or duplicate instances are left out; axes and
instances read are capped). The system font scan reads the fvar table
beside the name table, so installed instances are listed before the
file is loaded and found by name and by PostScript name.

An instance face carries its axis settings: skrifa draws its outlines
and reads its metrics and advances at that location, harfrust shapes
with a ShaperInstance, so layout, the canvas, Create Outlines and hit
testing all use the instance. PDF export embeds it through krilla's
Font::new_variable, SVG @font-face through subsetter's
subset_with_variations: both write a static font of that instance.

Tests build a small variable font in code (test_fonts, via
write-fonts; no font file is committed) and check listing, resolving,
glyphs and advances, PDF and SVG export and damaged fvar/gvar tables;
Bahnschrift and Segoe UI Variable are checked where installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:01:26 +07:00
Brandon Thomas aafd565b99 Merge pull request #228 from EthanSuquet/fix/hide-dot-system-fonts
Fonts: the font menus leave out macOS's hidden "." families
2026-10-06 15:57:48 -04:00
Brandon ThomasandClaude Opus 5.5 68352dab02 fmt: the font fallback path list fits on one line
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:37:22 -04:00
Brandon ThomasandClaude Opus 5.5 51a9b899c1 Merge main into #209; leave other apps' private font folders alone
Conflicts with #214 (fonts by PostScript name): this branch's name index (FaceKeys,
aliases) stays, and #214's `by_postscript_name` (used by PDF import) reads a PostScript
map filled from it, keyed by the same normalized names.

Removed: scanning ~/Library/Application Support/Adobe (CoreSync/plugins/livetype and
Fonts), and the preference that switched it (Type › Include Fonts of Other Design Apps'
Folders). Fonts activated through another vendor's subscription are licensed for use
through that vendor's own sync; reading their files from VectorCraft would go around that
licence, and the project's clean-room rules keep VectorCraft out of other vendors' files.
Fonts the user has installed in the system or user font folders are still found by every
name, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:36:09 -04:00
EthanSuquetandClaude Opus 5.5 fcc9414480 Fonts: the font menus leave out macOS's hidden "." families
macOS keeps faces for its own interface under family names that start with
"." (".SF NS", ".LastResort", ".Aqua Kana"…); Mac apps don't list them. Since
the font menus list every installed family (#36), they showed 74 of them on a
stock macOS, at the top of every list.

- FontDb::menu_family_list: family_list without names that start with ".",
  cached like it. Only a leading dot hides a family.
- Type › Font, the family dropdowns (Character, Properties), text.fontList and
  Refresh Font List's count use it.
- Lookups by name still see every family: documents and fallbacks that name
  a hidden family still find it (face, has_family, find_family, families,
  text.fontList {family}, Fonts in Document's missing check).
- Test: tests_sysfonts::font_lists_leave_out_hidden_system_families_which_still_resolve
  (a temporary font folder); the engine and UI font-list tests compare with
  the listed families.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:33:21 -04:00
Brandon Thomas 0306d51592 Merge pull request #214 from p0lyg0n/fix/pdf-font-postscript-names
PDF/.ai import: fonts are found by their PostScript name, whatever hyphens the family holds
2026-10-06 15:30:14 -04:00
Brandon ThomasandClaude Opus 5.5 546a65f77a Fonts: use craft-fonts as an optional build input; move the Japanese fonts out
Shippori Mincho (assets/fonts, from #145) moves to storytold/craft-fonts. crates/text/build.rs
embeds the fonts of a craft-fonts checkout when CRAFT_FONTS_DIR is set (web: BIZ UDPGothic
Regular only) as vectorcraft_text::CRAFT_FONTS; unset, it is empty and Japanese falls back to the
installed fonts. Document text gets the Japanese faces after the bundled fonts (Mincho first); the
UI adds them at the end of every egui family (BIZ UDPGothic first), before ui_fonts' system-font
discovery. Release and FreeBSD CI builds check craft-fonts out at a pinned commit; packages carry
the fonts' OFL texts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:42:21 -04:00
imachusandClaude Opus 5.5 8dc2fd077f Type: find fonts by any of their names; say how each one resolved
Documents made elsewhere often name a font differently from the family
name VectorCraft lists: a localized family name (ヒラギノ角ゴシック), a
legacy family/style pair (Hiragino Sans + W3) or a PostScript name
(HiraginoSans-W3). FontDb now indexes every name in a face's name table
and resolves a request to the right face, telling the caller whether it
matched exactly, by another name, by substitution or not at all
(FontMatch).

- text: FaceKeys/aliases, FontDb::resolve, canonical, find_postscript;
  fix a race where a face loaded by another thread was reported missing.
- engine: text.fonts reports status, the resolved face and missing
  glyphs; Replace Font resolves the same way.
- render: substituted-font highlighting uses resolve, so a font found
  by another name is no longer shown as missing.
- Find Font notes how each font was found.
- Preferences › Type › Include Fonts of Other Design Apps' Folders
  (macOS, on by default).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 21:45:10 +09:00
Hiroshi InukaiandClaude Opus 5.5 caba979b01 PDF/.ai import: fonts are found by their PostScript name, whatever hyphens the family holds
A document names its fonts by PostScript name, which the importer split at the
first hyphen into family and style. A family with hyphens in its name was never
found: "Rounded-X-Mplus-1c-black" became family "rounded", style
"x-mplus-1c-black", and the text fell back to another font. Common Japanese
families have hyphens in their names.

The system font scan now also indexes each installed face's PostScript name
(read from the same name table it already reads). The importer asks for the face
with that exact name first (`FontDb::by_postscript_name`) and splits the name only
when no installed face has it.

Test: installed faces are found by PostScript name, in any case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:18:53 +09:00
midasdf 44b2b984ed i18n: add Japanese menus and initial vertical type tools 2026-10-06 16:55:47 +09:00
theironchefandClaude Opus 5.5 a4d93b1462 Lint: as_chunks in the font scan too
The system font scan reads collection offsets and table records with
chunks_exact; clippy 1.99 asks for as_chunks there as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U9TrG4w49oSRYbP3cqxA3D
2026-10-05 12:17:22 -07:00
bflatasticandClaude Opus 5.5 c4b87e36b2 Fix #81: Chinese, Japanese and Korean names show in the UI, not boxes
Layer and object names, document tabs and any other UI text in scripts the
UI fonts lack now draw in an installed font that covers them, as the canvas
already did.

Root cause: egui only had the bundled UI fonts (Source Sans 3, JetBrains
Mono) and its defaults, none with CJK glyphs. After each frame the UI now
looks at the text it painted; the first time a character the UI fonts lack
appears, a thread finds an installed font covering it through the font
database (the canvas's fallback search, so a font the canvas loaded is
reused, its bytes shared rather than copied) and adds it to every egui
family as the last fallback. Nothing is bundled, Latin-only UIs load no
extra font, and on the web, without system fonts, the boxes remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:49:22 +07:00
bflatasticandClaude Opus 5.5 49e8413ebe Fix #130: installed fonts are found by name whatever ran before
Opening, placing, pasting or importing a file, the font menus and MCP now find
the installed system fonts (Arial, Times New Roman...) in a fresh session, so a
file renders the same whatever happened earlier, and PDF import keeps the real
family names (Microsoft YaHei, not "Microsoft Ya Hei").

Root cause: FontDb only consulted the system font catalog, which stayed empty
until a CJK fallback or Character panel > Show System Fonts happened to scan
the font folders. Every lookup by family name (face, families, styles,
has_family) now waits for one cataloging scan per session: the app starts it
in the background, other processes run it on first use. The scan reads only
each file's table directory and name table (about 70 ms for 780 faces here,
instead of reading every font file whole), the catalog is indexed by family,
the family list is cached, and an installed style of a loaded family (a
bundled family also installed with more weights) loads when asked for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:49:06 +07:00
bflatasticandClaude Opus 5.5 a5367b0846 M4.74: real text with embedded subset fonts in PDF
With Convert Text to Outlines off (advanced.outlineText: false), type is
written as selectable, searchable text: each glyph in its font, embedded
as a subset with a ToUnicode map, where its outline would be (rotated,
scaled, skewed and on-path type too; gradients keep their place). Fonts
whose licence forbids embedding, or allows only whole fonts, fall back to
outlines with a warning; a subset threshold below 100% is accepted with a
warning. Laid-out glyphs now carry their glyph id and transform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:25:21 +07:00
bflatasticandClaude Opus 5.5 fa3dcab411 M4.97: SVG Options choose the encoding, SVG Tiny 1.2 and embedded font subsets
SVG export writes UTF-8, UTF-16 (big-endian with a byte order mark) or
ISO 8859-1 (other characters as character references) and SVG/SVGZ
open in any of them. The Tiny 1.2 profile (simplified) writes
presentation attributes only and leaves out filters, masks, blend
modes and symbols with warnings. embedFonts embeds the fonts type uses
as @font-face subsets of the characters used, honouring the fonts'
fsType (whole when subsetting is forbidden, left out when embedding
is). New options: encoding, profile, embedFonts (SVG Options dialog,
document.formats); document.serialize also returns dataBase64 for
non-UTF-8 files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:25:15 +07:00
bflatasticandClaude Opus 5.5 8d8ca11e50 M4.64: File > Package collects the document, its linked files and fonts with a report; Document Info categories and Save
File > Package (saved documents; unsaved changes are saved first) writes
<folder>/<name>/<document>.vectorcraft, the linked files in Links/ (relinked in the
packaged copy), the fonts its type uses in Fonts/ (leaving out fonts whose licence
doesn't allow embedding) and <document> Report.txt, then offers Show Package. Without a
folder (the web, agents) the same files come back as a zip.

Document Info's flyout picks one category (document, objects, styles, spot colours,
patterns, gradients, symbols, fonts, font details, linked and embedded images) and Save…
writes the text report Package shares.

Engine: file.package {folder?, name?, copyLinks?, linksFolder?, relink?, copyFonts?,
report?}; document.info gains category, format: text and sections. Text: FontFace
path, fs_type and embeddable. UI: ui.packageDialog (dialog `package`), file.showPackage,
docInfo.save.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:40:05 +07:00
Brandon ThomasandClaude Opus 5.5 3e323bfa2a Robustness: VectorCraft never crashes — no panics in shipped code
Shipped code no longer unwraps, expects or panics: every one of the 124
unwrap()/expect()/panic!/unreachable! sites outside tests now handles the
failure (Result/Option, ?, let-else, defaults) and reports errors to the user.

- Lints: workspace clippy denies unwrap_used, expect_used, panic, todo,
  unimplemented and unreachable; clippy.toml allows them in tests, and
  integration tests, examples and testkit opt out explicitly.
- Safety net (vectorcraft_engine::guard): a panic in a top-level command rolls
  the document back and returns EngineError::Internal; a panicking tool is
  reset; the MCP server answers with an internal error and keeps serving; the
  UI frame and each control request are guarded.
- APIs that hid failures now return them: Rendered::to_png/to_jpeg/to_webp
  return Result (JPEG/WebP errors used to write empty files),
  FontDb::face returns Option, Region::top returns Option.
- Fuzzing: engine/tests/import_fuzz.rs feeds garbage, hostile and mutated SVG
  and PDF through import → render → export (30k cases locally, no panics).
- Docs: AGENTS.md/CLAUDE.md rule, docs/development.md "Robustness" section,
  README pointer and a PR template checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 06:28:59 +07:00
Brandon ThomasandClaude Opus 5.5 f8136f1e35 Live Blends/Envelopes/Gradient Mesh, Shape Builder, Live Paint, Image Trace (drawcraft-trace), Recolor Artwork, Export for Screens, Actions panel, prefs persistence, real layer thumbnails; menus bound
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:02:16 -04:00
Brandon Thomas a7e49bfa72 continued work 2026-09-30 09:43:24 -04:00
Brandon ThomasandClaude Opus 5.5 bfee80a22c M0: workspace skeleton — geom, color, doc, render, text, pathops, svg, tools, engine
Engine-first Cargo workspace for DrawCraft (clean-room Illustrator):
- geom: anchor-based path model, shapes, hit testing, snapping
- color: colours, paints, gradients, swatches, blend modes, harmonies
- doc: persistent Arc document tree, appearance stacks, text model, selection
- render: vello_cpu renderer (appearance, gradients, clip groups, blend modes)
- text: font DB, harfrust shaping, point/area/path layout
- pathops: curve booleans (linesweeper), Pathfinder, offset, simplify
- svg: import (usvg) and export
- tools: selection/direct/pen/shape tools emitting commands
- engine: Session, history with interactions, ~110 commands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 05:53:29 -04:00