Commit Graph
119 Commits
Author SHA1 Message Date
BFlat adea3a5550 Merge pull request #1053 from Silvertree2010/fix/h1274-title-case-leaves-a-word-lowerca
Capitalise title-case word after an opening apostrophe
2026-10-27 00:13:01 +07:00
bflatastic e6e4e9ab8a Merge main into #1053 2026-10-26 22:57:25 +07:00
bflatastic 372727c571 Merge main into #1378 2026-10-26 22:57:12 +07:00
bflatastic f89f656d16 #1309: the font-manager path test runs on Unix only (its paths aren't absolute on Windows) 2026-10-26 22:19:46 +07:00
Muamer MustaficandCursor 398c5404f5 M4: a truncated last line's char range covers the chars it takes from the next line (#1375)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:27:25 +01:00
Muamer MustaficandCursor b6d3e002df M4: truncated text fills its last line, keeps truncating when resized, and auto height takes max lines (#1375, #1376, #1377)
- The last line shown runs on into the word wrapped after it, so the ellipsis
  fills the line ("Lorem consec…") instead of following the last whole word.
- An explicit height (node.set, transform.resize, a resize handle, fixed
  sizing) on truncating text keeps it truncating (TextData::fix_size).
- Max lines on auto-height text hugs up to that many lines and ends in an
  ellipsis; text.maxLines keeps auto height, Type settings show it as
  truncating, .fig export writes textTruncation and import keeps auto height.
- node.get reports maxLines; text.fit measures every line.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:14:51 +01:00
Denis Gomes 5e32057bdd M7: font manager scan: drain Core Text's autoreleased objects; core-text 22
Review on #1309 pointed out that core-text 20.1's get_descriptors retains
the array it gets under the create rule a second time, so every scan kept
one array of font descriptors alive. Checking that turned up a larger leak:
Core Text autoreleases objects while it builds the collection, and the scan
runs where no autorelease pool is active (the app's background scan
thread, the CLI, the MCP server), so nothing ever drained them.

Measured with `figcraft-cli run` of N `text.rescanFonts` steps on macOS 15
(peak memory footprint):

| | 10 rescans | 200 rescans |
|---|---|---|
| main, without this PR | 221 MB | 220 MB |
| this PR before the fix | 228 MB | 796 MB |
| with the fix | 226 MB | 225 MB |

A standalone Swift loop over the same Core Text calls grows from 9 MB to
759 MB over 200 scans without a pool and stays at 20 MB inside one, so the
pool is what matters; the core-text bump removes the over-retain on top.

- The query runs inside objc2::rc::autoreleasepool. objc2 0.6 is already
  in the lockfile (winit's), and the function is safe, so the workspace's
  unsafe_code = "forbid" still holds.
- core-text goes to =22.0.0, the first release that takes ownership of the
  array correctly. It brings core-foundation 0.10, core-graphics 0.25 and
  core-graphics-types 0.2 beside the older versions other crates use. 22.0
  moved framework linking behind a `link` feature that is on by default,
  so with default features off it is named explicitly.

A rescan takes about 0.2 s instead of 0.08 s on that Mac (266 more font
files are indexed); it only runs when asked for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7f6a3a4e46)
2026-10-26 00:36:38 -04:00
Denis Gomes f1b41ffeaa M7: find fonts that macOS font managers activate outside the font folders
Font managers such as RightFont, FontBase and Typeface keep fonts in their
own library folders and activate them through Core Text, without copying
them into /Library/Fonts or ~/Library/Fonts. Every other Mac app lists
these fonts; FigCraft walks only the font folders, so it didn't, and a
file using one of them drew in a fallback font.

On macOS the scan now also asks Core Text for the file of every available
font and indexes the files that lie outside the walked folders. All three
scans (the first, the on-demand one and text.rescanFonts) share this, so a
font activated while the app runs is found by a rescan like a newly
installed one.

Core Text needs unsafe FFI, which the workspace forbids, so the query goes
through the safe wrappers of the core-text crate, pinned at =20.1.0. That
version builds on the core-foundation 0.9, core-graphics 0.23 and
foreign-types 0.5 the lockfile already has: core-text is the only new
package. The call sits inside catch_unwind, so anything unexpected from
Core Text leaves the scan with the font folders alone. Other platforms are
unchanged.

On a Mac with RightFont, 15 families from its library are now listed
(Geist, JetBrains Mono, Clash Display and others) that weren't before. A
full font listing went from 0.06 s to 0.20 s on that machine.

Tests: the filter that keeps files outside the font folders once, indexing
a font file found outside them, and (macOS only) that Core Text lists the
system's font files. cargo test --workspace, cargo clippy -p figcraft-text
--all-targets -D warnings and cargo fmt --check pass on macOS 15. CI
builds on Linux only, so the macOS path is checked locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5699e7abe6)
2026-10-26 00:36:21 -04:00
bflatastic 573b43d645 #1294: its font test names no PostScript name, a field #1021 added 2026-10-26 11:13:14 +07:00
bflatastic 5ee983ef63 Merge main into #1294
# Conflicts:
#	ROADMAP.md
#	docs/roadmap.md
2026-10-26 11:12:25 +07:00
bflatastic 27d1089847 Merge main into #1021
# Conflicts:
#	ROADMAP.md
#	docs/target-app-parity.md
2026-10-26 10:43:34 +07:00
bflatastic 7177f1c042 Merge main into #1021
# Conflicts:
#	ROADMAP.md
#	docs/roadmap.md
2026-10-26 10:29:24 +07:00
bflatastic f291f89fbd Merge main into #990
# Conflicts:
#	ROADMAP.md
2026-10-26 10:24:45 +07:00
BFlat f93deb965b Merge pull request #661 from AganzeFelicite/fix/adobe-fonts-macos-298
M7: find fonts activated through Adobe Fonts on macOS (#298)
2026-10-26 10:23:17 +07:00
bflatastic 6c4bb00c9e Merge main into #1021
# Conflicts:
#	crates/text/src/fontdb_tests.rs
2026-10-26 10:20:43 +07:00
bflatastic 1aed3d4915 Merge main into #990
# Conflicts:
#	ROADMAP.md
2026-10-26 10:03:33 +07:00
bflatastic 7c25399e4a Merge main into #661
# Conflicts:
#	ROADMAP.md
2026-10-26 10:03:15 +07:00
bflatastic 5cdd41a79f Merge main into #1215 2026-10-26 09:19:37 +07:00
bflatastic ec2ad1094d Merge main into #1294
# Conflicts:
#	ROADMAP.md
2026-10-26 09:16:31 +07:00
bflatastic 7a1b9d8414 #1021: a named style's optical size follows the text size only for .sketch imports
Existing text keeps the named instance's optical size, so documents render as before; the
Sketch import stores the size as the text's opsz value instead.
2026-10-26 09:12:40 +07:00
bflatastic 07a654959a Merge main into #1021
# Conflicts:
#	docs/file-format-parity.md
2026-10-26 09:12:39 +07:00
BFlat b3f06f6eca Merge pull request #1163 from switch87/fix/linux-symbol-fallback
M9: fall back to the Noto symbol and math fonts on Linux (#1156)
2026-10-26 08:33:05 +07:00
Jindřich ŠaršonandClaude Opus 5.5 6258ad2786 M6: Sketch import: merge main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:23:40 +01:00
236f3185d6 Migrate FigCraft to egui 0.37 (#1312)
* E21: require release font coverage and stabilize capture deadline tests

* E21: separate capture, IME and field-save regression phases

* M0: correct the migration qualification reference

* M-egui037: document input lifecycle and UI regression contracts

* M0: correct egui 0.37 status docs and stabilize join-code regression

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 15:04:39 -04:00
Brandon Thomas 31b857433d Merge pull request #1242 from SusieeTheLinuxUser/fix/1220-thai-backspace
Text: Backspace removes Thai and other marks one at a time (#1220)
2026-10-25 12:10:52 -04:00
Brandon Thomas 610fe374c7 Merge pull request #1218 from Salah1St/fix/justify-zwsp
M4: justified text doesn't widen U+200B
2026-10-25 12:10:47 -04:00
midasdf b3242d8eaf Merge origin/main into jp/kinsoku-jis 2026-10-26 00:28:52 +09:00
Jindřich ŠaršonandClaude Opus 5.5 87db9522b4 M6: Sketch import: merge main (Boards M12 and community fixes)
Conflicts resolved keeping both sides: `.sketch` stays in `is_document`
(now via `OsStr::to_str`); ROADMAP and the parity, roadmap and
file-format docs keep main's headers and rows with the `.sketch` notes
and history rows added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 19:13:03 +02:00
AganzeFelicite 86aad2bb6a M7: offer the installed styles of an embedded font family (#1246)
Release builds embed some families with only a few styles (Poppins
Regular, Italic and Bold), and the first font scan dropped every
installed face of such a family, so an installed Poppins SemiBold or
Medium was never offered. The first scan now keeps the embedded faces,
which still win for the styles they cover, and offers the installed
styles they lack beside them, as a rescan already did.

Closes #1246
2026-10-24 18:39:44 +02:00
AganzeFelicite c743f8ec1e Merge remote-tracking branch 'upstream/main' into fix/adobe-fonts-macos-298
# Conflicts:
#	ROADMAP.md
#	crates/text/src/fontdb.rs
#	docs/roadmap.md
2026-10-24 18:20:00 +02:00
Dylan M. TaylorandClaude Sonnet 5.5 3739b2863a fix(security): cap COLR layers, PNG glyph dimensions, and layout cache capacity (#1264)
* chore: explicit test imports in engine, part 1 (Sonar S2208)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(security): cap COLR layers, PNG glyph dimensions, and layout cache capacity

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:41:31 -04:00
Dylan M. Taylor 0cca56984f fix(security): bound decoration steps, text-on-path elements, and rename expansions (#1257) 2026-10-24 04:39:12 -04:00
bflatastic c31f886c05 Merge main into #1215 2026-10-24 12:54:15 +07:00
Salah1StandClaude Opus 5.5 84ca850d5f M4: justified text doesn't widen U+200B
Thai, Lao, Khmer and Burmese are written without spaces between words.
Tools that know the words insert U+200B ZERO WIDTH SPACE so lines can
break between them, and line breaking already treats it as a space. But
justification counted every space-class char as a gap, so a justified
paragraph got extra room at every U+200B: visible gaps between all its
words, which is not how these scripts are justified.

Item::stretches() (a space other than U+200B) is used for the justify
gap count, the trailing width and the pen advance. Line breaking is
unchanged. Test: on a justified line of words joined by U+200B and one
real space, the extra room goes to the real space only; with no real
space the line is laid out as if left-aligned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 12:15:57 +07:00
SusieeTheFemboyandGPT-6 Luna 8989e7b253 Text: Backspace removes Thai and other marks one at a time (#1220)
Co-Authored-By: GPT-6 Luna <noreply@openai.com>
2026-10-24 06:27:49 +02:00
BFlat 3476f4b1e7 Merge pull request #1244 from storytold/batch/r2-1
Community batch r2-1: 63 reviewed PRs
2026-10-24 11:15:53 +07:00
NetterSilverandClaude Sonnet 5.5 8b94da604a fix: use apostrophe-aware title case on the canvas text path
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 05:52:05 +02:00
bflatastic 8af2efd1b9 Batch r2-1 review: U+2007 glues beside ideographs too 2026-10-24 10:31:29 +07:00
a1a842af9a chore: resolve SonarCloud maintainability issues (#1241)
* chore: resolve SonarCloud maintainability issues

- Define SHA256_FMT constant in packaging script to remove duplicated string literal (shelldre:S1192)
- Remove redundant 'static lifetime annotations from const items (rust:S8863)
- Replace closures with method and function pointers (rust:S1612)
- Extract helper functions in synthetic document generation, bezier polyline flattening, and component restoration to reduce cognitive complexity (rust:S3776)

* fix(packaging): use verify_sha256 helper function to avoid shellcheck SC2059

* fix(engine): remove duplicate closing brace in large_document

* fix(engine): take &mut Document in restore_id_map; keep 'static on associated consts

restore_id_map allocates ids, so it needs a mutable document. Elided
lifetimes in associated consts trip elided_lifetimes_in_associated_constant,
so those annotations are restored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Assign positional parameters to locals in sha256 verification

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-23 23:28:13 -04:00
bflatastic 53b8b531ce Merge #1031: Treat U+2007 FIGURE SPACE as non-breaking in line breaking (@Silvertree2010) 2026-10-24 09:23:18 +07:00
Salah1StandClaude Opus 5.5 dd37c1763c M4: the Thai fallback test checks the characters it draws
Review: the test chose its Thai face, and checked each glyph's face, by
U+0E01, which the sample doesn't contain. It now asks for a face that has
every Thai character of the sample, and checks that each glyph's face has
the characters of its cluster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:36:24 +07:00
Salah1StandClaude Opus 5.5 1340e32b16 M4: Thai faces in the text fallback list
Thai typed into a layer whose font has no Thai glyphs (Inter, which new
text starts in) was drawn as missing-glyph boxes, on the desktop and on
the web, even with a Thai face embedded or installed: FALLBACK_FAMILIES
listed Latin, CJK, Hangul, Arabic and symbol families but no Thai one.

Noto Sans Thai, Noto Sans Thai UI, Leelawadee UI, Thonburi and Tahoma go
after Noto Sans Arabic; they are only consulted for characters the
layer's own font lacks. Tests: the list has a Thai face for each
platform, and with one installed or embedded every Thai cluster in a
Latin layer, marks included, is drawn from it (skips without one).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 13:26:37 +07:00
Gert Pellin c7d2a5f019 M9: the symbol test also looks for the Noto Sans Symbols2 spelling (#1156) 2026-10-22 21:46:12 +02:00
Gert Pellin 5a3dddc46f M9: fall back to the Noto symbol and math fonts on Linux (#1156)
Signs such as U+2316 and U+2912 are in no text face. The fallback list
had the macOS and Windows symbol fonts (Apple Symbols, Segoe UI Symbol)
but nothing a Linux install has, so they drew as empty boxes there even
with Noto Sans Symbols 2 or Noto Sans Math installed. Adds Noto Sans
Symbols, Noto Sans Symbols 2 (and the Symbols2 spelling some packages
use) and Noto Sans Math after them.
2026-10-22 21:29:58 +02:00
NetterSilverandClaude Opus 5.5 83b9f74665 Write a final Greek sigma in lower-case text layout
Found while testing crates/text/src/layout.rs:1070 (shape_segment calls TextCase::apply_after one char at a time; crates/doc/src/text.rs:124 apply_after)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 19:04:10 +02:00
NetterSilverandClaude Haiku 5.5 857762e65c Treat U+2007 FIGURE SPACE as non-breaking in line breaking
Found while testing crates/text/src/breaks.rs:42

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 07:36:21 +00:00
Jindřich ŠaršonandClaude Opus 5.5 7cb4168e13 M6: Sketch import: fixes from the PR review
- --no-system-fonts holds for .sketch imports too: the CLI opts the
  process out, so the import's font matching doesn't scan.
- Shared text styles get the installed family and platform tracking
  their linked layers get.
- Each text run writes its letter spacing, line height and font axes,
  neutral when it has none, instead of taking the first run's.
- The unsupported-drop hint and its catalogs list .sketch.
- A test sends damaged .sketch data through file.open and file.import.
- Stack items are matched to their source layers through a map.
- Docs: .sketch is a convert input; the Carbon kit's Sketch 47 edition
  is refused (the 68 and 83 ones open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 09:03:17 +02:00
AganzeFelicite b13e5c4ff3 M7: doc comments on the font scan's folders and scan_dir (#298) 2026-10-22 09:00:37 +02:00
Jindřich ŠaršonandClaude Opus 5.5 f02557e8f9 M6: Sketch import: fonts by PostScript name, Sketch's natural line
The font database knows each face's PostScript name; the Sketch import
finds the installed face a file's font names (CourierNewPSMT is Courier
New Regular) and reads the family from the name only when it isn't
installed. Text without a fixed line height takes the line Sketch draws:
ascent and descent rounded to whole pixels, the line gap left out, a
fifth more for classic Mac fonts, the baseline where Sketch puts it
(measured on sketchtool renders of 80 fonts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00
Jindřich ŠaršonandClaude Opus 5.5 ad78ee94c3 M6: Sketch import: instances, artboards and Apple fonts like Sketch
Compared with Sketch's renders of a Sketch 64 file. Resized instances lay
out their layers the way Sketch does (measured: pins share the change in
proportion, a fixed size keeps its centre's share, and files before format
110 just scale); masters' backgrounds show in instances only when Sketch
includes them; swaps to a missing symbol keep the original; artboards
don't draw a style they carry. Apple's system fonts are found under the
names designs use (SF Pro, SF UI Text and Display, SF Compact), the
optical size follows the text size for named styles too, and imported
text keeps the platform's trak tracking as letter spacing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:20 +02:00