Commit Graph
73 Commits
Author SHA1 Message Date
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
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
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
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
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
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
BFlat 1abb9083c7 Merge pull request #821 from attisvalentin/fix/rescan-and-load-fonts
M4: fonts installed while the app runs: text.rescanFonts, text.loadFont, text.refit
2026-10-20 03:04:29 +07:00
bflatastic f2ede63dd9 #867: comments describe the line separator without naming another product 2026-10-20 00:00:09 +07:00
bflatastic 203ec13e03 #821: text.loadFont reads at most MAX_FONT_FILE (the font scan's 256 MiB cap) 2026-10-19 23:44:08 +07:00
AganzeFelicite 710c95e527 test(text): a selection across a line separator shows the break (#852) 2026-10-19 12:52:09 +02:00
AganzeFelicite b930ea5871 test(text): the caret's line on either side of a line separator (#852) 2026-10-19 12:13:12 +02:00
AganzeFelicite 1b66fec3ec fix(text): the caret after a line break sits on the next line
`caret` put the index right after a line break (a newline, or a line
separator) at the end of the line above, so after Enter the caret showed
on the previous line until something was typed, and Up/Down counted
lines from there. The index before the break stays at the end of its
line; the one after it is now on the next line, as after a wrap.
Selection highlights already started such lines at their own start
(#665); their comment no longer describes the old caret.
2026-10-19 12:12:54 +02:00
AganzeFelicite 9e4dcc9204 test(text): line separators in layout, lists and carets (#852) 2026-10-19 11:34:58 +02:00
AganzeFelicite 692f45123c fix(text): a line separator breaks the line inside its paragraph (#852)
Figma stores Shift+Enter as U+2028. `.fig` imports keep it, but layout
only broke lines at a newline, so imported text ran soft-broken lines
together ("Option 1SL: …"), lost the empty line of a separator followed
by a newline, and put glyph bullets on one line.

A line separator now ends its line without ending the paragraph: no
paragraph spacing and no new list marker after it, the next line keeps
the item's indent, and it draws no glyph. A trailing one leaves an empty
last line, and a line it cuts short isn't stretched when justified.
2026-10-19 11:34:47 +02:00
AganzeFelicite 855bbb328f refactor(text): Line::break_after for carets and selections
Carets, clicks and selections asked `para_end && !last_line` to mean
"the line ends with a break char". Record that on the line instead, so a
break that doesn't end the paragraph can use the same rules. No
behaviour change: today only a newline ends a line early.
2026-10-19 11:34:34 +02:00
AganzeFelicite fd02772d22 refactor(text): one helper for the chars that end a line 2026-10-19 11:34:21 +02:00
Attila Valentin NémethandClaude Opus 5.5 33c0f94cc8 M4: font review fixes: new styles of loaded families, ids checks, repeat loads
- text.rescanFonts offers a loaded family the files it hasn't read (styles
  installed since) and refits every family that gained faces; `added` still
  lists only the families that were unknown
- text.refit refuses an `ids` that isn't a list instead of refitting the
  whole document
- text.loadFont with a file already loaded returns its families without
  keeping its bytes or adding its faces again
- doc comments on the functions this change touches

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 18:46:20 +02:00
Attila Valentin NémethandClaude Opus 5.5 972e228f41 M4: text.rescanFonts and text.loadFont: fonts installed while the app runs
The system fonts are indexed once per process, so a font installed while
FigCraft (or `figcraft-cli mcp`) runs stayed missing until a restart.

- text.rescanFonts walks the font folders again and offers the families
  installed since (loaded families keep their faces) → {added}
- text.loadFont {path | data} adds a font file without installing it → {families}
- both clear the layout cache so text lays out again in the new face

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:13:49 +02:00
bflatastic 401af64bba Merge fix/758 into batch 16 2026-10-18 11:16:43 +07:00
bflatastic 91c80a19cc M7: find macOS's downloadable CJK system fonts (#406)
Current macOS keeps PingFang and other on-demand fonts in its asset
store, which the font scan never walked, so Chinese text showed as
boxes. The scan now also walks the com_apple_MobileAsset_Font* folders
of /System/Library/AssetsV2 (and the older /System/Library/Assets) with
the same depth, size and file checks, and Hiragino Sans GB and Heiti SC
(preinstalled) join the Chinese UI faces and the text fallbacks.
Tested with a folder laid out the same way; not run on a Mac.
2026-10-17 22:53:54 +07:00
RealtaNuaandClaude Opus 5.5 a3c5025186 M7: missing fonts window only after a file opens; wait for the font scan (#752)
From review:
- The check ran after any file.open/openRecent/import result, so a
  pasted or dropped image, reopening a file that was already open, or
  Clear recent brought the window back. It now runs only for results
  with a `summary` (a file opened, or pages imported), and never in the
  browser.
- Text > Missing fonts... before the startup scan finished listed
  installed fonts as missing. It now says it is checking the installed
  fonts and lists them once that is done
  (`figcraft_text::installed_fonts_known`, also true when system fonts
  are opted out, where checks used to wait forever).
- ROADMAP progress log and file-format-parity status line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 22:06:03 +07:00
RealtaNuaandClaude Opus 5.5 825cb1e7af M7: list the fonts a file uses that aren't installed (#752)
Text in a family that isn't installed was drawn in a fallback font
without a word. Now:

- `text.missingFonts` lists the families a document names that no
  installed or built-in font provides: text layers and their styled
  ranges, text styles, and string variables bound to a font family
  (every mode, through aliases), with the number of text layers.
- The desktop app shows a Missing fonts window after the user opens a
  file that has any: once installed fonts are indexed (before that every
  one of them would count as missing) and after any import report is
  closed. Files named on the command line count. Programmatic opens and
  the browser build never open it by themselves. Text > Missing fonts...
  shows it for the file in front; Escape closes it.
- `figcraft-cli info` prints `missing font` lines (`missingFonts` with
  --json).
- file-format-parity: the row claimed REST import warnings that no code
  produced.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 21:49:32 +07:00
bflatastic feeb9f71db Merge fix/671 into batch 13 2026-10-17 17:19:52 +07:00
RealtaNuaandClaude Opus 5.5 d27f45e063 fix(format): write a list's start on every line; report it in get_node (#686)
The .fig export now writes a numbered list's start on each of its lines,
so a reader that takes it per line or per list counts the same. Bullets
no longer keep a start. The field is named start_offset (it holds the
offset: 1 shows "2."). get_node reports listStartOffsets. The parity doc
lists what's still not read from .fig lists.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 00:58:20 +07:00
RealtaNuaandClaude Opus 5.5 60fa813eb2 fix(format): numbered lists from .fig files keep their start number (#686)
Figma stores where a numbered list starts counting on each text line
(listStartOffset; a list shown as "2." has offset 1). The import dropped
it, so every list counted from 1.

A paragraph's list settings now carry a start number (written only when
set, so older files open and save unchanged). Numbering counts on from
it where a list starts; items that go on counting ignore it. The .fig
import reads it, the .fig export writes it on a list's first line, and
plain paragraphs drop it. Toggling a list off ignores differing starts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 00:27:34 +07:00
Marco Arnulfo 7d7a724764 Text: selection highlights after a line break start at the line's start, and the empty last line shows (fixes #665) 2026-10-16 13:27:01 +02:00
bflatastic 9f935718fe Merge branch 'rb-578' into batch/t6
# Conflicts:
#	crates/text/src/fontdb_tests.rs
2026-10-16 02:37:43 +07:00
bflatastic 0a84dee777 Merge remote-tracking branch 'origin/main' into rb-578
# Conflicts:
#	crates/text/src/fontdb.rs
#	crates/text/src/fontdb_tests.rs
2026-10-16 02:27:50 +07:00
bflatastic 46316c9895 Merge remote-tracking branch 'origin/main' into rb-568
# Conflicts:
#	ROADMAP.md
#	crates/text/src/fontdb_tests.rs
2026-10-16 02:26:29 +07:00
bkimandClaude Opus 5.5 e9e2d87405 M1: Hangul falls back to a Korean system font, at the run's weight
Text in the default Inter (or any Latin font) drew the missing-glyph box for every Hangul
syllable on macOS and Windows: no Korean family was on the fallback list, so the Korean
fonts those systems ship were never tried, and there is no default-font setting to work
around it. Apple SD Gothic Neo (macOS), Malgun Gothic (Windows) and Noto Sans CJK KR /
Noto Sans KR (Linux) now come after the Chinese and Japanese entries, so Han characters
resolve as before.

Fallback faces also follow the run's style: each fallback family gives its face nearest the
run's style instead of always its Regular, so Hangul (or kana) in a bold run comes out bold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015MAPjgJo17KasfbzMTbV65
2026-10-16 01:23:06 +09:00
IanHollow 5454bdc244 M7: skip special files when scanning system fonts
Require resolved font entries to be regular files before indexing them. Preserve normal font symlinks and cover named pipes in a bounded child-process regression.

Assisted-by: OpenAI Codex (GPT-6)
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-15 08:29:11 -07:00
bflatastic 3ce80b25ab Merge #300 fix: colour emoji on Linux 2026-10-15 19:59:45 +07:00
bflatastic ff3981de73 #300: emoji take a colour face before a style face without colour glyphs (DejaVu Sans on Linux drew them in one colour); the scale test allows faces wider than the em 2026-10-15 19:59:24 +07:00
bflatastic 2a3309902a Merge #474: M7: find Unix user fonts under XDG_DATA_HOME (@IanHollow) 2026-10-15 19:33:06 +07:00
bflatastic a89031eab2 #300: emoji take a colour face before the symbol fonts, which drew them in one colour on Windows 2026-10-15 19:21:37 +07:00
bflatastic a51b8d2271 Merge main and the community batch into #474
# Conflicts:
#	ROADMAP.md
2026-10-15 18:57:06 +07:00
bflatastic 3d112c4b8c #300: a colour PNG strike's size is checked before its pixels are allocated 2026-10-15 18:47:52 +07:00
bflatastic 18d4715cd9 Merge main and the community batch into #300
# Conflicts:
#	ROADMAP.md
#	docs/ui-parity.md
2026-10-15 18:45:15 +07:00
bflatastic f518d87b71 Merge #471: M4: hanging punctuation test holds for fonts that kern with x offsets (@rcoenen) 2026-10-15 17:53:10 +07:00
IanHollow 611fb324b9 M7: find Unix user fonts under XDG_DATA_HOME
Assisted-by: GPT-6
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-14 22:59:17 -07:00
Rob CoenenandClaude Opus 5.5 996852d15c M4: hanging punctuation test holds for fonts that kern with x offsets
On macOS without craft-fonts the default face is Helvetica Neue, whose
kerning comes out of the shaper partly as an x offset (e.g. on the "e" of
"here."), so a glyph's x + advance is not its pen end. The layout was
right (the full stop's pen sits exactly on the edge); the test assumed no
offsets. Each hanging line is now compared with the same line set flush:
every glyph must move by exactly the hanging mark's advance, and the flush
right line must end on the edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 00:55:43 -04:00