Files
wadamesh/scripts/build/gen-touch-fonts.sh
T
Kaj SchittecatandClaude Opus 5 a2e18c1811 fix: the arrow glyph was never in the fonts (#261)
pisti87 found "Settings → Quick replies" drawing a tofu box, in English as well
as Hungarian. It is not a language bug and it is not the beta_62 fallback-chain
fix falling short — the glyph simply was not in any font we ship.

gen-touch-fonts.sh asked $noto_sans for the symbol set, and Noto Sans does not
contain U+2190-2193 or U+2260/2264/2265 (verified directly against the release
the script pins). lv_font_conv omits a glyph its source font lacks rather than
failing, so those seven characters silently never made it into extras_font_*,
in every language, since the fonts were first generated this way.

Scope is much wider than the one line reported: 137 uses of → in the touch UI
plus arrows in all 13 .lang files. pisti87 happened to open one of them.

Fixed by cutting the seven from Montserrat, which has all of them, is already
the primary UI face and already the first --font in this script — so no new
dependency, no new licence line, and the arrow matches the text beside it. They
had to be REMOVED from the Noto Sans symbol list as well: with the codepoint
claimed by a later font that cannot supply it, the Montserrat pass produced
nothing and the regenerated files came back byte-identical apart from a comment.

Noto Sans Symbols 2 was the obvious candidate and does NOT have them either —
it errors outright when asked, which is how that was ruled out.

Not visually confirmed: I have no way to see the glyph render from here. The
regenerated fonts grew ~390 lines per size and lv_font_conv accepted the request
(it hard-errors when the source font has none of the symbols, as Symbols 2 did),
so the glyphs are in. Worth a look on a device before the beta ships.

Reported by pisti87.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:20:35 +02:00

256 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "usage: $0 [--check]" >&2
}
mode=write
if [[ ${1:-} == "--check" ]]; then
mode=check
shift
fi
if [[ $# -ne 0 ]]; then
usage
exit 2
fi
repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
work_dir=$(mktemp -d "${TMPDIR:-/tmp}/wadamesh-touch-fonts.XXXXXX")
trap 'rm -rf "$work_dir"' EXIT
download() {
local url=$1
local output=$2
local expected=$3
curl -fsSL --retry 3 "$url" -o "$output"
verify_sha256 "$output" "$expected"
}
verify_sha256() {
local path=$1
local expected=$2
local actual
if command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "$path" | awk '{print $1}')
else
actual=$(sha256sum "$path" | awk '{print $1}')
fi
if [[ $actual != "$expected" ]]; then
echo "SHA-256 mismatch for $path" >&2
echo "expected: $expected" >&2
echo "actual: $actual" >&2
exit 1
fi
}
montserrat="$work_dir/Montserrat-Medium.ttf"
noto_sans_zip="$work_dir/NotoSans-v2.015.zip"
noto_sans="$work_dir/NotoSans-Regular.ttf"
noto_arabic_zip="$work_dir/NotoSansArabicUI-v2.011.zip"
noto_arabic="$work_dir/NotoSansArabicUI-Regular.ttf"
noto_symbols_zip="$work_dir/NotoSansSymbols2-v2.008.zip"
noto_symbols="$work_dir/NotoSansSymbols2-Regular.ttf"
download \
"https://raw.githubusercontent.com/lvgl/lvgl/v8.4.0/scripts/built_in_font/Montserrat-Medium.ttf" \
"$montserrat" \
"421f26b23e2be6b98373d32acd3cb2897b154d4bf0a77d26534ce476e4cbed53"
download \
"https://github.com/notofonts/latin-greek-cyrillic/releases/download/NotoSans-v2.015/NotoSans-v2.015.zip" \
"$noto_sans_zip" \
"0c34df072a3fa7efbb7cbf34950e1f971a4447cffe365d3a359e2d4089b958f5"
download \
"https://github.com/notofonts/arabic/releases/download/NotoSansArabicUI-v2.011/NotoSansArabicUI-v2.011.zip" \
"$noto_arabic_zip" \
"f775ee259557195721466e99ec0316bbcd897f0429e25955f5d9582ca1202ce7"
download \
"https://github.com/notofonts/symbols/releases/download/NotoSansSymbols2-v2.008/NotoSansSymbols2-v2.008.zip" \
"$noto_symbols_zip" \
"346c930bbe8eb946701a05c54e9c11a2094dee1d93c387bf1771c0a3e335688f"
unzip -p "$noto_sans_zip" \
"NotoSans/hinted/ttf/NotoSans-Regular.ttf" > "$noto_sans"
unzip -p "$noto_arabic_zip" \
"NotoSansArabicUI/hinted/ttf/NotoSansArabicUI-Regular.ttf" > "$noto_arabic"
unzip -p "$noto_symbols_zip" \
"NotoSansSymbols2/hinted/ttf/NotoSansSymbols2-Regular.ttf" > "$noto_symbols"
verify_sha256 "$noto_sans" \
"478c558ea716033cd60c03438f628dfa75694dcf6b5f6d505a2f05fd2b4f3823"
verify_sha256 "$noto_arabic" \
"c56275c744ded6ff6df13de04963e6174632f0405a54a83f44d0fe5395f45ae6"
verify_sha256 "$noto_symbols" \
"c4a0a80f0041ce4be81e2478faad22776d23edb98ae3f0d19bd37044820ecf9d"
font_conv=(npx --yes lv_font_conv@1.5.3)
if [[ $("${font_conv[@]}" --version) != "1.5.3" ]]; then
echo "lv_font_conv 1.5.3 is required" >&2
exit 1
fi
symbols='•·–—‘’“”…°±×÷€£¥§©®™½¼¾℃℉'
# Arrows (U+2190-2193) and the comparison operators (U+2260/2264/2265) are NOT in
# Noto Sans. Asking $noto_sans for them, as this script did until #261, silently
# produced nothing — lv_font_conv omits a glyph the source font lacks instead of
# failing — so "Settings → Quick replies" drew a tofu box in EVERY language, at
# 137 sites in the UI and in all 13 .lang files. (Noto Sans Symbols 2 does not
# have them either; verified, it errors outright when asked.)
#
# Montserrat DOES have all seven, and is already the primary UI face and the first
# --font here, so cutting them from it costs no new dependency or licence line and
# makes the arrow match the text around it. lv_font_conv takes the FIRST font that
# supplies a codepoint, so listing these on Montserrat wins while every other
# symbol still comes from Noto Sans below, unchanged.
symbols_fallback='→←↑↓≠≤≥'
stage="$work_dir/stage"
mkdir -p "$stage/src/ui-touch"
normalise() {
local raw=$1
local output=$2
local sources=$3
local guard=${4:-}
awk -v sources="$sources" -v guard="$guard" '
BEGIN {
if (guard != "") {
print "#include \"device_caps.h\""
print "#if defined(" guard ")"
print ""
}
}
/^ \* Opts:/ {
print " * Generated by scripts/build/gen-touch-fonts.sh with lv_font_conv 1.5.3"
print " * Sources: " sources
next
}
/^#ifdef LV_LVGL_H_INCLUDE_SIMPLE$/ {
print "#if 1"
next
}
{ print }
END {
if (guard != "") {
print ""
print "#endif /* " guard " */"
}
}
' "$raw" > "$output"
perl -0pi -e 's/\s+\z/\n/' "$output"
}
generate_extras() {
local size=$1
local guard=${2:-}
local raw="$work_dir/extras_font_${size}.c"
local output="$stage/src/ui-touch/extras_font_${size}.c"
"${font_conv[@]}" \
--size "$size" \
--bpp 4 \
--format lvgl \
--font "$montserrat" \
-r 0x00C0-0x00FF \
-r 0x0100-0x017F \
-r 0x0400-0x04FF \
--symbols "$symbols_fallback" \
--font "$noto_sans" \
-r 0x0370-0x03FF \
--symbols "$symbols" \
--font "$noto_arabic" \
-r 0x0600-0x06FF \
-r 0xFE70-0xFEFF \
--lv-font-name "extras_${size}" \
-o "$raw"
normalise "$raw" "$output" \
"Montserrat Medium (LVGL v8.4.0), Noto Sans 2.015, Noto Sans Symbols 2.008, Noto Sans Arabic UI 2.011" \
"$guard"
}
generate_latin_extras() {
local size=$1
local raw="$work_dir/extras_lat_${size}.c"
local output="$stage/src/ui-touch/extras_lat_${size}.c"
"${font_conv[@]}" \
--size "$size" \
--bpp 4 \
--format lvgl \
--font "$montserrat" \
-r 0x00C0-0x00FF \
-r 0x0100-0x017F \
--lv-font-name "extras_lat_${size}" \
-o "$raw"
normalise "$raw" "$output" \
"Montserrat Medium (LVGL v8.4.0)" \
"HAS_TANMATSU"
}
generate_star() {
local size=$1
local raw="$work_dir/star_font_${size}.c"
local output="$stage/src/ui-touch/star_font_${size}.c"
"${font_conv[@]}" \
--size "$size" \
--bpp 4 \
--no-compress \
--format lvgl \
--font "$noto_symbols" \
-r 0x2605 \
--lv-font-name "star_font_${size}" \
-o "$raw"
normalise "$raw" "$output" \
"Noto Sans Symbols 2.008"
}
for size in 12 14 16; do
generate_extras "$size"
done
for size in 20 24; do
generate_extras "$size" "TLORA_PAGER"
done
for size in 20 24 28; do
generate_latin_extras "$size"
done
for size in 14 28; do
generate_star "$size"
done
files=(
src/ui-touch/extras_font_12.c
src/ui-touch/extras_font_14.c
src/ui-touch/extras_font_16.c
src/ui-touch/extras_font_20.c
src/ui-touch/extras_font_24.c
src/ui-touch/extras_lat_20.c
src/ui-touch/extras_lat_24.c
src/ui-touch/extras_lat_28.c
src/ui-touch/star_font_14.c
src/ui-touch/star_font_28.c
)
if [[ $mode == check ]]; then
stale=0
for file in "${files[@]}"; do
if ! cmp -s "$stage/$file" "$repo_root/$file"; then
echo "stale generated font: $file" >&2
stale=1
fi
done
exit "$stale"
fi
for file in "${files[@]}"; do
cp "$stage/$file" "$repo_root/$file"
done
echo "Regenerated ${#files[@]} touch font assets."