fix(web): bundel Roboto Mono voor consistente selectie-metrics in Bron-weergave (#1784) #1786

Merged
brenno merged 5 commits from fix/web-monospace-font-1784 into main 2026-08-25 07:32:12 +00:00
Owner

Samenvatting

Op de webversie (CanvasKit) had geselecteerde tekst in de Bron-weergave een afwijkend fontgrootte en ijlte het selectieblok voor op de cursor. De oorzaak: fontFamily: 'monospace' is een generieke CSS-familie waarvoor Flutter op web geen font-bestand heeft — het valt terug op een proportioneel default-font met andere metrics, waardoor tekst en selectierechthoek niet meer aligneren.

De fix: bundel Roboto Mono (OFL-1.1, 184 KB) en registreer het in pubspec.yaml onder zowel de naam monospace als Roboto Mono. Elke fontFamily: 'monospace'-referentie in de codebase (38 plekken) resolvet nu naar dit gebundelde bestand. Nul codewijzigingen in de editors nodig — de fix is volledig in pubspec.yaml + font-bestand.

Dit aligneert met de bestaande aanpak: alle UI-fonts zijn al gebundled om de web-build self-contained te houden onder de strikte connect-src 'self' CSP. Monospace was het enige gat.

Oorsprong

Overgebracht vanuit GitHub-mirror issue #1 (gerapporteerd door @sikkepitje, 2026-08-16). Forgejo-issue: #1784.

Bewaker

De wijziging voegt een gebundelde afhankelijkheid toe (font-bestand), maar aligneert met alle kernwaarden:

  • Soevereiniteit (3): de web-build is nu volledig self-contained voor monospace — geen afhankelijkheid van systeem-font op web.
  • Vrijheid/openheid (2): OFL-1.1 is open, de font is inspecteerbaar, bron op GitHub.
  • Geen bestandsformaat-wijziging: het .md-bestand verandert niet.
  • Geen nieuwe partij: Roboto Mono is dezelfde familie als de al gebundelde Roboto.

Geen botsing. Deze stap is expliciet meegelopen omdat er een afhankelijkheid bijkomt.

Wijzigingen

  • assets/fonts/RobotoMono-Variable.ttf + RobotoMono-OFL.txt — gebundelde font + licentie
  • pubspec.yamlmonospace en Roboto Mono families geregistreerd, OFL-tekst als asset
  • lib/services/bundled_licenses.dart — licentie-entry voor Roboto Mono + monospace-alias
  • THIRD_PARTY_NOTICES.md — vermelding toegevoegd
  • tool/sbom_build.dart — dedup font-assets bij alias-families (zelfde bestand = één component)
  • sbom/ — geregenereerd (7 font-componenten)
  • lib/l10n/translations/*.dart (31 talen) — "vier" → "vijf" lettertypefamilies
  • test/bundled_licenses_test.dart — regressietest dat monospace gebundeld is

Testplan

  • make check groen: 10570 tests, 87.1% coverage
  • make check-secrets schoon (gitleaks + trufflehog, 0 leaks)
  • make sast schoon (semgrep, 0 findings)
  • Nieuwe regressietest: monospace font family is bundled (web selection metrics, #1784)
  • SBOM-test groen na dedup-fix
  • Beeldkeuring: visueel verifiëren op web-build dat selectie aligneert (na merge)

Generated with Devin

## Samenvatting Op de webversie (CanvasKit) had geselecteerde tekst in de Bron-weergave een afwijkend fontgrootte en ijlte het selectieblok voor op de cursor. De oorzaak: `fontFamily: 'monospace'` is een generieke CSS-familie waarvoor Flutter op web geen font-bestand heeft — het valt terug op een proportioneel default-font met andere metrics, waardoor tekst en selectierechthoek niet meer aligneren. De fix: bundel Roboto Mono (OFL-1.1, 184 KB) en registreer het in `pubspec.yaml` onder zowel de naam `monospace` als `Roboto Mono`. Elke `fontFamily: 'monospace'`-referentie in de codebase (38 plekken) resolvet nu naar dit gebundelde bestand. Nul codewijzigingen in de editors nodig — de fix is volledig in `pubspec.yaml` + font-bestand. Dit aligneert met de bestaande aanpak: alle UI-fonts zijn al gebundled om de web-build self-contained te houden onder de strikte `connect-src 'self'` CSP. Monospace was het enige gat. ## Oorsprong Overgebracht vanuit GitHub-mirror issue #1 (gerapporteerd door @sikkepitje, 2026-08-16). Forgejo-issue: #1784. ## Bewaker De wijziging voegt een gebundelde afhankelijkheid toe (font-bestand), maar aligneert met alle kernwaarden: - **Soevereiniteit (3):** de web-build is nu volledig self-contained voor monospace — geen afhankelijkheid van systeem-font op web. - **Vrijheid/openheid (2):** OFL-1.1 is open, de font is inspecteerbaar, bron op GitHub. - **Geen bestandsformaat-wijziging:** het `.md`-bestand verandert niet. - **Geen nieuwe partij:** Roboto Mono is dezelfde familie als de al gebundelde Roboto. Geen botsing. Deze stap is expliciet meegelopen omdat er een afhankelijkheid bijkomt. ## Wijzigingen - `assets/fonts/RobotoMono-Variable.ttf` + `RobotoMono-OFL.txt` — gebundelde font + licentie - `pubspec.yaml` — `monospace` en `Roboto Mono` families geregistreerd, OFL-tekst als asset - `lib/services/bundled_licenses.dart` — licentie-entry voor Roboto Mono + monospace-alias - `THIRD_PARTY_NOTICES.md` — vermelding toegevoegd - `tool/sbom_build.dart` — dedup font-assets bij alias-families (zelfde bestand = één component) - `sbom/` — geregenereerd (7 font-componenten) - `lib/l10n/translations/*.dart` (31 talen) — "vier" → "vijf" lettertypefamilies - `test/bundled_licenses_test.dart` — regressietest dat `monospace` gebundeld is ## Testplan - [x] `make check` groen: 10570 tests, 87.1% coverage - [x] `make check-secrets` schoon (gitleaks + trufflehog, 0 leaks) - [x] `make sast` schoon (semgrep, 0 findings) - [x] Nieuwe regressietest: `monospace font family is bundled (web selection metrics, #1784)` - [x] SBOM-test groen na dedup-fix - [ ] Beeldkeuring: visueel verifiëren op web-build dat selectie aligneert (na merge) Generated with [Devin](https://devin.ai)
Op de CanvasKit-webengine heeft een generieke CSS-familie zoals `monospace`
geen downloadbaar font-bestand. Flutter valt terug op een proportioneel
default-font, en de selectierechthoeken — berekend met de metrics van die
fallback — lijnen niet meer uit met de tekst op het scherm: geselecteerde
tekst krijgt een andere fontgrootte en het selectieblok ijlt voor op de
cursor (#1784).

De oplossing: bundel Roboto Mono (OFL-1.1, zelfde familie als de al
gebundelde Roboto) en registreer het onder zowel de naam `monospace` als
`Roboto Mono`. Elke `fontFamily: 'monospace'`-referentie in de codebase
resolvet nu naar dit gebundelde bestand, met consistente metrics op elk
platform. De `Roboto Mono`-alias maakt de optie in de code-font-instellingen
resolven naar hetzelfde bestand. Nul codewijzigingen in de editors nodig.

Dit aligneert met de bestaande aanpak: alle UI-fonts zijn al gebundled om de
web-build self-contained te houden onder de strikte `connect-src 'self'` CSP.
Monospace was het enige gat.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
De `monospace`-alias en `Roboto Mono` wijzen naar hetzelfde .ttf-bestand.
De SBOM-generator maakte één component per family+asset, wat een dubbele
bom-ref opleverde (`font:assets/fonts/RobotoMono-Variable.ttf`) en de
uniqueness-test liet falen. Sla dubbele assets over: één SBOM-component per
fysiek bestand, niet per alias.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Roboto Mono is de vijfde gebundelde font-familie. De licentiebeschrijving
in de about-dialoog noemde nog "vier" — in alle 31 talen, want de Nederlandse
bronstring is de sleutel in elke vertaalmap.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
test: regressie dat monospace gebundeld is (web selectie-metrics, #1784)
Some checks failed
scans / scans (pull_request) Successful in 5m16s
static-gate / static-gate (pull_request) Failing after 8m4s
35fdf0f806
Zonder de `monospace`-declaratie in pubspec.yaml valt de CanvasKit-webengine
terug op een proportioneel default-font en lijnen selectierechthoeken niet uit
met de tekst. Deze test houdt de fix op zijn plaats: verwijder de declaratie
en de test faalt.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
fix(sbom): copyright-holder match op <family> Project, niet bare <family>
All checks were successful
scans / scans (pull_request) Successful in 3m9s
static-gate / static-gate (pull_request) Successful in 6m50s
14dd877e24
De `_fontCopyrightHolder`-functie gebruikte `holder.contains(family)` — een
substring-match die 'Roboto' laat matchen op zowel "The Roboto Project Authors"
als "The Roboto Mono Project Authors". Welke als eerste wordt gevonden hangt
af van de volgorde waarin `Directory.listSync()` de .txt-bestanden retourneert,
en die verschilt tussen macOS (HFS/APFS, alfabetisch) en Linux (ext4, hash-volgorde).
Op CI (Linux) kreeg de Roboto-font daardoor "The Roboto Mono Project Authors"
als supplier, terwijl de committed SBOM "The Roboto Project Authors" had —
de freshness-test faalde.

Fix: match op `'$family Project'` (case-insensitive) in plaats van bare
`family`. Dat is specifiek genoeg: "The Roboto Project Authors" bevat
"Roboto Project" maar niet "Roboto Mono Project", en vice versa.

Daarnaast is `Roboto Mono` in pubspec.yaml vóór de `monospace`-alias geplaatst,
zodat het SBOM-component de echte font-naam draagt (de generator pakt de
eerste family die naar een bestand wijzen).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
brenno merged commit d60eae6b49 into main 2026-08-25 07:32:12 +00:00
Sign in to join this conversation.
No description provided.