From d562040fc73821e19ea327687cf09ec9831db7bb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 31 Jul 2026 10:54:29 -0400 Subject: [PATCH] Fix boxed glyphs: base logical fonts on DejaVu, add symbol fallbacks MegaMek draws armor pips, heat markers, wind and pressure indicators with symbol codepoints. The generated fontconfig mapped the logical fonts to Noto Sans, which covers exactly ONE of the 18 codepoints MegaMek uses (U+00B0). Everything else rendered as boxes. Measured coverage with a GlyphCoverage probe (Font.canDisplay) rather than guessing, then: base DejaVu Serif / Sans / Sans Mono - broad symbol coverage fallback Noto Sans Symbols2 U+2B1D armor pips, U+2744, U+2B71/73 Material Symbols Rounded MegaMek's bundled Private Use icons Verified in gameplay, not in the lobby: a deploy-phase screenshot now shows armor pips, heat pips, the wind flag, direction arrow, atmospheric pressure and light indicators all rendering, with punctuation unaffected. Residue, documented in TODO: the temperature and gravity indicators still box. U+1F321 and U+1F525 are supplementary-plane emoji that the legacy fontconfig fallback does not appear to reach, and U+23AF exists only in Noto Sans Math / Noto Sans Symbols here. Recorded as "do not retry": adding "Noto Sans Symbols" (no 2) to cover U+23AF. Its family name is a prefix of "Noto Sans Symbols2" and the legacy parser mis-resolves between them - basic punctuation turns to boxes and the armor pips vanish entirely. Caught by screenshot and reverted. Co-Authored-By: Claude Opus 5 --- TODO.md | 22 +++++--- scripts/gen-fontconfig.sh | 103 ++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/TODO.md b/TODO.md index a18ef56..e5acef8 100644 --- a/TODO.md +++ b/TODO.md @@ -5,12 +5,22 @@ via Webswing Lite rendering the stock MegaMek client. ## Playability -**Glyphs render as boxes (□)** — symbols in the unit display, heat scale and -conditions overlay. Cause is `spike-webswing/fontconfig.properties` (generated by -`scripts/gen-fontconfig.sh`), which maps logical fonts to faces lacking symbol -coverage. *Already ruled out:* trusting MegaMek's `data/fonts` removed all font -rejections but did not fix the boxes. Next: fall back to MegaMek's bundled -`Noto Symbols 2` / `Icons`. Verify on the unit display, not the lobby. +**Glyphs — mostly fixed, small residue.** `scripts/gen-fontconfig.sh` now bases +the logical fonts on DejaVu (Noto Sans covered exactly 1 of the 18 codepoints +MegaMek uses) and adds a fallback chain of Noto Sans Symbols2 + MegaMek's bundled +Material Symbols. Armor pips, heat pips, wind flag, direction arrow, pressure and +light indicators all render now; verified in a deploy-phase screenshot. + +Still boxed: the temperature and gravity indicators, and a few trailing status +icons. Two causes — U+1F321/U+1F525 are supplementary-plane emoji, which the +legacy fontconfig fallback does not appear to reach, and U+23AF exists only in +Noto Sans Math / Noto Sans Symbols on this system. + +*Ruled out, do not retry:* adding "Noto Sans Symbols" (no 2) for U+23AF. Its +family name is a prefix of "Noto Sans Symbols2" and the parser mis-resolves +between them — basic punctuation (`/ : ,` parens) turns to boxes and the armor +pips disappear. Also ruled out earlier: trusting MegaMek's `data/fonts` alone, +which removed all font-load rejections but fixed nothing. **Open fullscreen** — the frame opens small inside a large viewport. Webswing already passes `webswing.screenWidth`/`screenHeight` to the app JVM. diff --git a/scripts/gen-fontconfig.sh b/scripts/gen-fontconfig.sh index 30770fd..2427b93 100755 --- a/scripts/gen-fontconfig.sh +++ b/scripts/gen-fontconfig.sh @@ -1,30 +1,46 @@ #!/usr/bin/env bash # Generate a legacy-format fontconfig.properties for Webswing's app JVM. # -# Why this is needed: OpenJDK 9+ stopped shipping lib/fontconfig.bfc and instead -# queries libfontconfig at runtime via FcFontConfiguration. Webswing's -# WebFontConfiguration still extends the legacy sun.awt.FontConfiguration, which -# reads the old properties file. With no such file present the app JVM dies at -# startup with "Fontconfig head is null, check your fonts or fonts configuration". +# Why this exists: OpenJDK 9+ stopped shipping lib/fontconfig.bfc and queries +# libfontconfig at runtime instead. Webswing's WebFontConfiguration still extends +# the legacy sun.awt.FontConfiguration, which reads the old properties file. With +# no such file the app JVM dies at startup with "Fontconfig head is null". The JVM +# honours -Dsun.awt.fontconfig=, so we generate one. # -# The JVM honours -Dsun.awt.fontconfig=, so we generate a file rather than -# writing into the JDK. +# Font choice matters as much as existence. MegaMek draws armor pips, heat +# markers and status icons with symbol codepoints, and Noto Sans covers almost +# none of them (of the 18 codepoints MegaMek uses, Noto Sans has exactly one: +# U+00B0). Those render as boxes. So: +# +# base DejaVu - broad symbol coverage on top of normal text +# fallback Noto Sans Symbols2 U+2B1D armor pips, U+2744, U+2B71/73 +# Material Symbols Rounded MegaMek's bundled Private Use icons +# +# Do NOT add "Noto Sans Symbols" (no 2) as a further fallback for U+23AF. Its +# family name is a prefix of "Noto Sans Symbols2" and the legacy parser +# mis-resolves between them: basic punctuation (/ : , parens) starts rendering as +# boxes and the armor pips disappear. Verified by screenshot, and reverted. +# +# Verify coverage changes with the GlyphCoverage probe rather than by eye. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" OUT="${1:-$ROOT/spike-webswing/fontconfig.properties}" +MM_HOME="${MM_HOME:-$ROOT/MegaMek-0.51.00}" mkdir -p "$(dirname "$OUT")" command -v fc-match >/dev/null || { echo "ERROR: fc-match not found (install fontconfig)" >&2; exit 1; } -# logical Java font -> a family we ask fontconfig to resolve -resolve() { fc-match -f '%{file}' "$1" || true; } +resolve() { fc-match -f '%{file}' "$1" 2>/dev/null || true; } +xlfd() { printf -- '-*-%s-%s-%s-normal--*-%%d-*-*-p-*-%s' "$1" "$2" "$3" "$4"; } +key() { printf 'filename.%s' "$(printf '%s' "$1" | tr ' ' '_')"; } +# DejaVu rather than Noto: it carries the symbol coverage MegaMek needs. declare -A FAMILY=( - [serif]="Noto Serif" - [sansserif]="Noto Sans" + [serif]="DejaVu Serif" + [sansserif]="DejaVu Sans" [monospaced]="DejaVu Sans Mono" - [dialog]="Noto Sans" + [dialog]="DejaVu Sans" [dialoginput]="DejaVu Sans Mono" ) @@ -33,48 +49,73 @@ declare -A FAMILY=( echo "version=1" echo echo "sequence.allfonts=latin-1" + echo "sequence.fallback=symbols2,micons" echo } > "$OUT" -# Component font mappings: .