ttf-inter-hinted
LOW
maintainer gaougalos
0 votes
scanned 2026-09-25 15:12:17.861096
Why flagged
Uploaded within the last 14 days with 2 or fewer community votes — little peer review so far.
Triggered rules
Low
Few votes, recently uploaded
zero_votes_recent
Uploaded within the last 14 days with 2 or fewer community votes — little peer review so far.
PKGBUILD
1
# Maintainer: gaou-piou <i.am.piou@gmail.com>
2
pkgname=ttf-inter-hinted
3
_interver=4.1
4
_nfver=3.5.1
5
pkgver="${_interver}"
6
pkgrel=1
7
pkgdesc='Inter, a typeface designed for UI legibility, re-hinted with ttfautohint for FreeType (optionally Nerd Fonts patched)'
8
arch=('any')
9
url='https://rsms.me/inter/'
10
license=('OFL-1.1')
11
makedepends=('python' 'python-fonttools' 'python-skia-pathops' 'fontforge' 'parallel' 'ttfautohint')
12
optdepends=('afdko: CFF/OTF hinting via otfautohint (HINT_ENGINE=cff)')
13
options=(!strip)
14
provides=('inter-font')
15
conflicts=('inter-font' 'interui-ttf-hinted')
16
replaces=('interui-ttf-hinted')
17
source=(
18
"Inter-${_interver}.zip::https://github.com/rsms/inter/releases/download/v${_interver}/Inter-${_interver}.zip"
19
"font-patcher-${_nfver}.zip::https://github.com/ryanoasis/nerd-fonts/releases/download/v${_nfver}/FontPatcher.zip"
20
"LICENSE-${_interver}.txt::https://raw.githubusercontent.com/rsms/inter/v${_interver}/LICENSE.txt"
21
"otf2ttf.py"
22
"set_gasp.py"
23
"cff_hint.py"
24
"dedup_blues.py"
25
)
26
noextract=("font-patcher-${_nfver}.zip")
27
sha256sums=('9883fdd4a49d4fb66bd8177ba6625ef9a64aa45899767dde3d36aa425756b11e'
28
'42bcb32145499a35732274c7fc48deb434ad0d2e0e118f98527c1479c6fa251a'
29
'262481e844521b326f5ecd053e59b98c8b2da78c8ee1bdbb6e8174305e54935a'
30
'151f00af692183a62146453b709f04240dfe72fdc7a1b98a833f664177eacd21'
31
'0b0464b268525569b5fa28b4735791efb22f22829ad178629776ae3ea82d7f99'
32
'77dd6b9d0b43f261ef68f46bf8d5b4bb8d142969e2c305e7cd2feb1ccecf61fc'
33
'980f8ce4e3e9b3738ee47d30068d9f9d6f69dfae035363e36b769919122bf194')
34
35
# ── What this package does ──────────────────────────────────────────────────
36
#
37
# Takes Inter from the upstream release zip and, depending on the options
38
# below, installs the static TTF, static OTF or variable fonts, optionally
39
# patched with Nerd Fonts glyphs, re-hinted with ttfautohint and with an
40
# opt-in fontconfig snippet.
41
#
42
# rsms already ships the static TTFs hinted (ttfautohint, stem mode qqq). The
43
# point of re-hinting is the stem mode. Measured on FreeType 2.14.3 (v40
44
# interpreter, grayscale) with pango/cairo, Inter Regular…ExtraBold plus
45
# Italic/Bold Italic at 9-20px:
46
#
47
# * Only the THIRD letter of --stem-width-mode matters on Linux: v40 reports
48
# itself to the bytecode as DirectWrite ClearType. Upstream's qqq renders
49
# like qsq, and qss like sss.
50
# * x-height, cap height and baseline agree between flat and round letters in
51
# every variant, upstream included, so there is nothing to fix there.
52
# * The i/j dots and diaereses (ï ä ö ü ϊ) are what differs. With q or n
53
# stems (upstream included) the gap under them closes in 72 of 490
54
# weight/size/glyph cases, from SemiBold up at 10-13px. With s stems only 7
55
# do. Hence the default preset is "sharp".
56
# * --increase-x-height, --x-height-snapping-exceptions, --hinting-limit,
57
# gasp and --windows-compatibility made no visible difference.
58
# * The variable font ships unhinted. It can be hinted (ttfautohint keeps the
59
# fvar/gvar axes, blue zones come from the default master); Inter keeps
60
# the same x-height in every weight, so the instances measure as well as
61
# the statics.
62
#
63
# FreeType only runs TrueType bytecode at hintstyle hintmedium/hintfull. With
64
# the common hintslight setting it uses its own light autohinter instead and
65
# ignores these hints. The package therefore ships (but does not enable)
66
# /usr/share/fontconfig/conf.avail/80-ttf-inter-hinted.conf, which turns on
67
# bytecode hinting for the installed families only. It uses hintmedium, not
68
# hintfull: cairo/pango render the two identically, but Chrome turns off
69
# subpixel positioning (whole-pixel advances, uneven gaps) only at hintfull.
70
# Enable it with:
71
#
72
# sudo ln -s /usr/share/fontconfig/conf.avail/80-ttf-inter-hinted.conf \
73
# /etc/fonts/conf.d/
74
#
75
# ── Build-time options ───────────────────────────────────────────────────────
76
#
77
# Run from a terminal, prepare() asks for INTER_VARIANT, WANT_INTER/
78
# WANT_DISPLAY, NERD_PATCH, HINTING, HINT_ENGINE and HINT_PRESET (Enter keeps
79
# the default). Any of them already set in the environment is not asked.
80
# Without a TTY (chroot, CI, piped stdin) nothing is asked and the environment
81
# variables / defaults below apply. The answers are saved to
82
# $srcdir/.build_opts for build() and package().
83
#
84
# INTER_VARIANT ttf|otf|variable Which font set to install (default: ttf)
85
# ttf static TrueType (extras/ttf)
86
# otf static OpenType/CFF (extras/otf)
87
# variable InterVariable.ttf + InterVariable-Italic.ttf
88
#
89
# WANT_INTER true/false The "Inter" text cut (default: true)
90
# WANT_DISPLAY true/false The "Inter Display" optical size (default: false)
91
# At least one must be true; ignored for variable,
92
# whose single file carries both via the opsz axis.
93
#
94
# NERD_PATCH true/false Patch with Nerd Fonts glyphs (default: false).
95
# font-patcher cannot keep variable axes, so
96
# INTER_VARIANT=variable switches to ttf when patching.
97
#
98
# HINTING true/false Re-hint (default: true). false installs the fonts as
99
# rsms ships them: static TTFs with his qqq ttfautohint
100
# hints, the variable fonts unhinted.
101
#
102
# HINT_ENGINE ttfautohint|cff (default: ttfautohint). cff keeps OTF outlines
103
# (otfautohint, or FontForge as a fallback) and only
104
# applies to INTER_VARIANT=otf without patching.
105
# ttfautohint converts OTF input to TTF first.
106
#
107
# HINT_PRESET name Named bundle of ttfautohint flags (default: sharp)
108
# ("Linux" = the stem letter FreeType v40 actually uses)
109
# sharp stem=sss (Linux: s) range 6-48 x-height 14 (clear i/j dots)
110
# balanced stem=qsq (Linux: q) range 8-48 x-height 14 (ttfautohint defaults;
111
# renders like upstream)
112
# natural stem=nnn (Linux: n) range 8-48 x-height 0 (least distortion)
113
# light stem=nnn (Linux: n) range 12-48 x-height 0 (HiDPI; <12px left alone)
114
# custom use the individual HINT_* vars below verbatim
115
#
116
# Individual ttfautohint knobs (override the preset; empty = use preset value):
117
# HINT_MODE nnn|qqq|qsq|sss 3-char --stem-width-mode (grayscale/GDI/DW)
118
# On Linux only the 3rd letter has an effect.
119
# HINT_RANGE_MIN N --hinting-range-min
120
# HINT_RANGE_MAX N --hinting-range-max
121
# HINT_LIMIT N --hinting-limit (default: same as HINT_RANGE_MAX, so
122
# hinting really stops above the range; 0 = no limit)
123
# HINT_XHEIGHT N --increase-x-height (0 = disable)
124
# HINT_XSNAP_EXC STR --x-height-snapping-exceptions (e.g. "13-17"; unset = none)
125
# HINT_DEFAULT_SCRIPT STR --default-script (default: latn)
126
# HINT_FALLBACK_SCRIPT STR --fallback-script for glyphs outside any script
127
# (default: latn; Nerd-patched builds always use none
128
# plus --fallback-scaling so icons are not hinted as Latin)
129
# HINT_WINCOMPAT true/false --windows-compatibility (Windows/Wine only)
130
# HINT_TTFA_TABLE true/false --ttfa-table: embed the parameters used, readable
131
# with `ttfautohint --ttfa-info` (default: false)
132
# HINT_FAMILY_SUFFIX STR -F/--family-suffix, e.g. " Hinted"
133
#
134
# GASP_MODE keep|sized|smooth|gridfit (default: keep; Windows/Wine only,
135
# FreeType 2.14 ignores gasp)
136
# keep leave the gasp table as ttfautohint wrote it
137
# sized MS strategy: <=8 grayscale, 9-16 gridfit, 17+ both
138
# smooth all sizes anti-aliased ({0xFFFF: 15})
139
# gridfit all sizes gridfit+grayscale ({0xFFFF: 3})
140
#
141
# Examples:
142
# makepkg -si (asks, when run from a terminal)
143
# makepkg -si </dev/null (never asks: defaults only)
144
# INTER_VARIANT=variable makepkg -si (asks everything else)
145
# WANT_DISPLAY=true HINT_PRESET=balanced makepkg -si
146
# NERD_PATCH=true HINT_FAMILY_SUFFIX=" Hinted" makepkg -si
147
# ────────────────────────────────────────────────────────────────────────────
148
149
# Every option _resolve_options() understands, and so the only keys
150
# .build_opts may set.
151
_opt_keys=(INTER_VARIANT WANT_INTER WANT_DISPLAY NERD_PATCH HINTING HINT_ENGINE
152
HINT_PRESET HINT_MODE HINT_RANGE_MIN HINT_RANGE_MAX HINT_LIMIT
153
HINT_XHEIGHT HINT_XSNAP_EXC HINT_DEFAULT_SCRIPT HINT_FALLBACK_SCRIPT
154
HINT_WINCOMPAT HINT_TTFA_TABLE HINT_FAMILY_SUFFIX GASP_MODE)
155
156
# _ask_yn QUESTION DEFAULT(y|n) -> sets _yn to true/false
157
_ask_yn() {
158
local _ans
159
read -r -p " $1? [$2] " _ans || _ans=""
160
[[ "${_ans:-$2}" =~ ^[yY] ]] && _yn=true || _yn=false
161
}
162
163
# _ask_choice TITLE DEFAULT KEY:description ... -> sets _choice to a KEY.
164
# Enter (or EOF) keeps DEFAULT; anything else must be a listed number.
165
_ask_choice() {
166
local _title="$1" _default="$2"; shift 2
167
local -a _items=("$@")
168
local _i _ans
169
echo " $_title:"
170
for _i in "${!_items[@]}"; do
171
printf " %d) %-12s %s%s\n" "$((_i + 1))" "${_items[$_i]%%:*}" "${_items[$_i]#*:}" \
172
"$([[ "${_items[$_i]%%:*}" == "$_default" ]] && echo " (default)")"
173
done
174
while :; do
175
read -r -p " > " _ans || _ans=""
176
if [[ -z "$_ans" ]]; then _choice="$_default"; return; fi
177
if [[ "$_ans" =~ ^[0-9]+$ ]] && (( _ans >= 1 && _ans <= ${#_items[@]} )); then
178
_choice="${_items[$((_ans - 1))]%%:*}"; return
179
fi
180
echo " Enter 1-${#_items[@]}, or press Enter for $_default."
181
done
182
}
183
184
# Called once, from prepare(): ask for whatever the environment has not set,
185
# but only on a terminal, then save every set option to .build_opts.
186
_prompt_options() {
187
if [[ -t 0 ]]; then
188
echo ""
189
echo " ttf-inter-hinted: build options (Enter = default)"
190
echo ""
191
if [[ -z "${INTER_VARIANT:-}" ]]; then
192
_ask_choice "Font set" ttf \
193
"ttf:static TrueType" \
194
"otf:static OpenType/CFF" \
195
"variable:InterVariable (all weights and opsz in one file)"
196
INTER_VARIANT=$_choice
197
fi
198
if [[ "$INTER_VARIANT" != variable && -z "${WANT_INTER:-}${WANT_DISPLAY:-}" ]]; then
199
_ask_yn "Include Inter (text cut)" y; WANT_INTER=$_yn
200
_ask_yn "Include Inter Display" n; WANT_DISPLAY=$_yn
201
fi
202
if [[ -z "${NERD_PATCH:-}" ]]; then
203
_ask_yn "Patch with Nerd Fonts glyphs" n; NERD_PATCH=$_yn
204
fi
205
if [[ -z "${HINTING:-}" ]]; then
206
_ask_yn "Re-hint with ttfautohint (n = keep upstream hints)" y; HINTING=$_yn
207
fi
208
if [[ "$HINTING" == true && "$INTER_VARIANT" == otf && "${NERD_PATCH:-false}" != true && \
209
-z "${HINT_ENGINE:-}" ]]; then
210
_ask_choice "Hinting engine" ttfautohint \
211
"ttfautohint:TrueType bytecode, converts OTF to TTF" \
212
"cff:PostScript/CFF hints, keeps OTF"
213
HINT_ENGINE=$_choice
214
fi
215
if [[ "$HINTING" == true && "${HINT_ENGINE:-ttfautohint}" == ttfautohint && \
216
-z "${HINT_PRESET:-}" ]]; then
217
_ask_choice "Hinting preset" sharp \
218
"sharp:stem s, 6-48px (measured: keeps i/j dots clear)" \
219
"balanced:stem q, 8-48px (ttfautohint defaults, like upstream)" \
220
"natural:stem n, 8-48px, no x-height boost (least distortion)" \
221
"light:stem n, 12-48px, no x-height boost (HiDPI)" \
222
"custom:use the HINT_* environment variables"
223
HINT_PRESET=$_choice
224
fi
225
echo ""
226
else
227
echo "==> Non-interactive build (no TTY): using environment variables / defaults."
228
fi
229
230
local _k
231
: > "$srcdir/.build_opts"
232
for _k in "${_opt_keys[@]}"; do
233
# "set" rather than non-empty: HINT_XSNAP_EXC="" (no exceptions) differs
234
# from HINT_XSNAP_EXC unset (ttfautohint's default).
235
if [[ "${!_k+set}" == set ]]; then
236
printf '%s=%s\n' "$_k" "${!_k}" >> "$srcdir/.build_opts"
237
fi
238
done
239
}
240
241
# Load .build_opts (whitelisted keys only), then apply defaults and validate.
242
# makepkg runs build() and package() in separate shells, so both call this.
243
_resolve_options() {
244
local _k _v
245
if [[ ! -f "$srcdir/.build_opts" ]]; then
246
echo "Error: $srcdir/.build_opts missing; run a full makepkg (prepare() writes it)." >&2
247
exit 1
248
fi
249
while IFS='=' read -r _k _v; do
250
if [[ " ${_opt_keys[*]} " == *" $_k "* ]]; then
251
printf -v "$_k" '%s' "$_v"
252
fi
253
done < "$srcdir/.build_opts"
254
255
INTER_VARIANT="${INTER_VARIANT:-ttf}"
256
WANT_INTER="${WANT_INTER:-true}"
257
WANT_DISPLAY="${WANT_DISPLAY:-false}"
258
NERD_PATCH="${NERD_PATCH:-false}"
259
HINTING="${HINTING:-true}"
260
HINT_ENGINE="${HINT_ENGINE:-ttfautohint}"
261
HINT_PRESET="${HINT_PRESET:-sharp}"
262
GASP_MODE="${GASP_MODE:-keep}"
263
HINT_WINCOMPAT="${HINT_WINCOMPAT:-false}"
264
HINT_TTFA_TABLE="${HINT_TTFA_TABLE:-false}"
265
HINT_DEFAULT_SCRIPT="${HINT_DEFAULT_SCRIPT:-latn}"
266
HINT_FALLBACK_SCRIPT="${HINT_FALLBACK_SCRIPT:-latn}"
267
268
case "$INTER_VARIANT" in
269
ttf|otf|variable) ;;
270
*) echo "Error: INTER_VARIANT='$INTER_VARIANT' invalid (ttf|otf|variable)." >&2; exit 1 ;;
271
esac
272
for _v in WANT_INTER WANT_DISPLAY NERD_PATCH HINTING HINT_WINCOMPAT HINT_TTFA_TABLE; do
273
case "${!_v}" in
274
true|false) ;;
275
*) echo "Error: $_v='${!_v}' must be true or false." >&2; exit 1 ;;
276
esac
277
done
278
# font-patcher drops fvar/gvar, so patching always works on static TTFs.
279
if [[ "$NERD_PATCH" == true && "$INTER_VARIANT" == variable ]]; then
280
echo "==> Note: variable fonts cannot be Nerd-patched; using INTER_VARIANT=ttf."
281
INTER_VARIANT=ttf
282
fi
283
if [[ "$INTER_VARIANT" != variable && "$WANT_INTER" != true && "$WANT_DISPLAY" != true ]]; then
284
echo "Error: select at least one of WANT_INTER / WANT_DISPLAY." >&2; exit 1
285
fi
286
case "$HINT_ENGINE" in
287
ttfautohint|cff) ;;
288
*) echo "Error: HINT_ENGINE='$HINT_ENGINE' invalid (ttfautohint|cff)." >&2; exit 1 ;;
289
esac
290
if [[ "$HINT_ENGINE" == cff && ( "$INTER_VARIANT" != otf || "$NERD_PATCH" == true ) ]]; then
291
echo "==> Note: the cff engine needs INTER_VARIANT=otf without patching; using ttfautohint."
292
HINT_ENGINE=ttfautohint
293
fi
294
295
local _m _lo _hi _xh
296
case "$HINT_PRESET" in
297
sharp) _m=sss; _lo=6; _hi=48; _xh=14 ;;
298
balanced) _m=qsq; _lo=8; _hi=48; _xh=14 ;;
299
natural) _m=nnn; _lo=8; _hi=48; _xh=0 ;;
300
light) _m=nnn; _lo=12; _hi=48; _xh=0 ;;
301
custom) _m=sss; _lo=6; _hi=48; _xh=14 ;;
302
*)
303
echo "Error: unknown HINT_PRESET='$HINT_PRESET'." >&2
304
echo " Valid: sharp balanced natural light custom" >&2
305
exit 1 ;;
306
esac
307
# A preset never overrides a value the user set explicitly.
308
HINT_MODE="${HINT_MODE:-$_m}"
309
HINT_RANGE_MIN="${HINT_RANGE_MIN:-$_lo}"
310
HINT_RANGE_MAX="${HINT_RANGE_MAX:-$_hi}"
311
HINT_LIMIT="${HINT_LIMIT:-$HINT_RANGE_MAX}"
312
HINT_XHEIGHT="${HINT_XHEIGHT:-$_xh}"
313
314
if [[ ! "$HINT_MODE" =~ ^[nqs]{3}$ ]]; then
315
echo "Error: HINT_MODE='$HINT_MODE' must be 3 chars from n/q/s (e.g. sss)." >&2
316
exit 1
317
fi
318
for _v in HINT_RANGE_MIN HINT_RANGE_MAX HINT_LIMIT HINT_XHEIGHT; do
319
if [[ ! "${!_v}" =~ ^[0-9]+$ ]]; then
320
echo "Error: $_v='${!_v}' must be a non-negative integer." >&2; exit 1
321
fi
322
done
323
if (( HINT_RANGE_MIN > HINT_RANGE_MAX )); then
324
echo "Error: HINT_RANGE_MIN ($HINT_RANGE_MIN) > HINT_RANGE_MAX ($HINT_RANGE_MAX)." >&2
325
exit 1
326
fi
327
for _v in HINT_DEFAULT_SCRIPT HINT_FALLBACK_SCRIPT; do
328
if [[ ! "${!_v}" =~ ^[a-z0-9]{3,4}$ ]]; then
329
echo "Error: $_v='${!_v}' must be a script tag (e.g. latn, none)." >&2; exit 1
330
fi
331
done
332
case "$GASP_MODE" in
333
keep|sized|smooth|gridfit) ;;
334
*) echo "Error: GASP_MODE='$GASP_MODE' invalid (keep|sized|smooth|gridfit)." >&2; exit 1 ;;
335
esac
336
}
337
338
prepare() {
339
_prompt_options
340
_resolve_options # validate now, so a typo fails before the long steps
341
342
rm -rf "$srcdir/font-patcher"
343
mkdir -p "$srcdir/font-patcher"
344
bsdtar xf "$srcdir/font-patcher-${_nfver}.zip" -C "$srcdir/font-patcher"
345
}
346
347
build() {
348
_resolve_options
349
350
echo "==> Options: variant=$INTER_VARIANT inter=$WANT_INTER display=$WANT_DISPLAY" \
351
"nerd=$NERD_PATCH hinting=$HINTING engine=$HINT_ENGINE"
352
if [[ "$HINTING" == true && "$HINT_ENGINE" == ttfautohint ]]; then
353
echo "==> ttfautohint: preset=$HINT_PRESET stem=$HINT_MODE" \
354
"range=$HINT_RANGE_MIN-$HINT_RANGE_MAX limit=$HINT_LIMIT x-height=$HINT_XHEIGHT" \
355
"x-snap-exc='${HINT_XSNAP_EXC-<default>}' gasp=$GASP_MODE" \
356
"ttfa-table=$HINT_TTFA_TABLE${HINT_FAMILY_SUFFIX:+ suffix='$HINT_FAMILY_SUFFIX'}"
357
fi
358
359
rm -rf "$srcdir/selected" "$srcdir/converted" "$srcdir/patched" "$srcdir/hinted"
360
mkdir -p "$srcdir/selected" "$srcdir/converted" "$srcdir/patched" "$srcdir/hinted"
361
362
# ── Step 1: select ──────────────────────────────────────────────────────────
363
# Inter-4.1.zip layout:
364
# InterVariable.ttf, InterVariable-Italic.ttf (variable)
365
# extras/ttf/{Inter,InterDisplay}-*.ttf (static TrueType, hinted)
366
# extras/otf/{Inter,InterDisplay}-*.otf (static OpenType/CFF)
367
if [[ "$INTER_VARIANT" == variable ]]; then
368
cp "$srcdir"/InterVariable*.ttf "$srcdir/selected/"
369
else
370
local _ext="$INTER_VARIANT"
371
if [[ "$WANT_INTER" == true ]]; then
372
find "$srcdir/extras/$_ext" -maxdepth 1 -name "Inter-*.$_ext" -exec cp {} "$srcdir/selected/" \;
373
fi
374
if [[ "$WANT_DISPLAY" == true ]]; then
375
find "$srcdir/extras/$_ext" -maxdepth 1 -name "InterDisplay-*.$_ext" -exec cp {} "$srcdir/selected/" \;
376
fi
377
fi
378
local _count
379
_count=$(find "$srcdir/selected" -type f | wc -l)
380
echo "==> Selected $_count font file(s)."
381
if (( _count == 0 )); then
382
echo "Error: no fonts matched the selection. Has the zip layout changed?" >&2; exit 1
383
fi
384
385
local _hintsrc="$srcdir/selected"
386
387
# ── Step 2: Nerd Fonts patching ─────────────────────────────────────────────
388
# Patch first, hint afterwards: font-patcher does not keep hint bytecode, and
389
# ttfautohint then sees the final glyph set including the icons.
390
if [[ "$NERD_PATCH" == true ]]; then
391
echo "==> Patching with Nerd Fonts glyphs (this takes a while)..."
392
find "$srcdir/selected" -type f | sort | \
393
parallel --will-cite -j"$(nproc)" python "$srcdir/font-patcher/font-patcher" \
394
--variable-width-glyphs -q -c {} -out "$srcdir/patched" '>/dev/null'
395
_count=$(find "$srcdir/patched" -maxdepth 1 \( -name '*.ttf' -o -name '*.otf' \) | wc -l)
396
if (( _count == 0 )); then
397
echo "Error: font-patcher produced no output. See messages above." >&2; exit 1
398
fi
399
echo "==> Patched $_count font(s)."
400
_hintsrc="$srcdir/patched"
401
fi
402
403
if [[ "$HINTING" != true ]]; then
404
return 0
405
fi
406
407
# ── Step 3a: CFF hinting (otf, unpatched) ───────────────────────────────────
408
if [[ "$HINT_ENGINE" == cff ]]; then
409
local _f _out
410
if command -v otfautohint >/dev/null 2>&1; then
411
echo "==> CFF hinting with otfautohint..."
412
else
413
echo "==> CFF hinting with FontForge AutoHint (install afdko for otfautohint)..."
414
fi
415
for _f in "$_hintsrc"/*.otf; do
416
_out="$srcdir/hinted/${_f##*/}"
417
if command -v otfautohint >/dev/null 2>&1; then
418
python "$srcdir/dedup_blues.py" "$_f"
419
if ! otfautohint --force-overlap -o "$_out" "$_f" 2>/dev/null; then
420
echo "==> WARNING: otfautohint failed on ${_f##*/}; using FontForge AutoHint."
421
rm -f "$_out"
422
python "$srcdir/cff_hint.py" "$_f" "$_out"
423
fi
424
else
425
python "$srcdir/cff_hint.py" "$_f" "$_out"
426
fi
427
done
428
return 0
429
fi
430
431
# ── Step 3b: ttfautohint ────────────────────────────────────────────────────
432
# ttfautohint needs TrueType outlines: convert any OTF (the otf variant, or
433
# patched OTFs) with cu2qu first.
434
if compgen -G "$_hintsrc/*.otf" >/dev/null; then
435
echo "==> Converting OTF to TTF for ttfautohint..."
436
find "$_hintsrc" -maxdepth 1 -name '*.otf' | sort | \
437
parallel --will-cite -j"$(nproc)" \
438
python "$srcdir/otf2ttf.py" --post-format 2.0 --max-error 1.0 \
439
-o "$srcdir/converted/{/.}.ttf" {}
440
find "$_hintsrc" -maxdepth 1 -name '*.ttf' -exec cp {} "$srcdir/converted/" \;
441
_hintsrc="$srcdir/converted"
442
fi
443
444
local -a _ta_opts=(
445
--hinting-range-min="$HINT_RANGE_MIN"
446
--hinting-range-max="$HINT_RANGE_MAX"
447
--hinting-limit="$HINT_LIMIT"
448
--increase-x-height="$HINT_XHEIGHT"
449
--stem-width-mode="$HINT_MODE"
450
--default-script="$HINT_DEFAULT_SCRIPT"
451
--ignore-restrictions
452
)
453
if [[ "$NERD_PATCH" == true ]]; then
454
# Icons would otherwise get Latin blue zones: scale them instead.
455
_ta_opts+=(--fallback-script=none --fallback-scaling)
456
else
457
_ta_opts+=(--fallback-script="$HINT_FALLBACK_SCRIPT")
458
fi
459
# Honour an explicit empty HINT_XSNAP_EXC (= no exceptions); omit if unset.
460
if [[ "${HINT_XSNAP_EXC+set}" == set ]]; then
461
_ta_opts+=(--x-height-snapping-exceptions="$HINT_XSNAP_EXC")
462
fi
463
if [[ "$HINT_WINCOMPAT" == true ]]; then _ta_opts+=(--windows-compatibility); fi
464
if [[ -n "${HINT_FAMILY_SUFFIX:-}" ]]; then _ta_opts+=(--family-suffix="$HINT_FAMILY_SUFFIX"); fi
465
if [[ "$HINT_TTFA_TABLE" == true ]]; then _ta_opts+=(--ttfa-table); else _ta_opts+=(--no-info); fi
466
467
echo "==> Hinting with ttfautohint..."
468
local _f
469
for _f in "$_hintsrc"/*.ttf; do
470
ttfautohint "${_ta_opts[@]}" "$_f" "$srcdir/hinted/${_f##*/}"
471
done
472
473
if [[ "$GASP_MODE" != keep ]]; then
474
echo "==> Applying gasp mode '$GASP_MODE'..."
475
python "$srcdir/set_gasp.py" "$GASP_MODE" "$srcdir/hinted/"*.ttf
476
fi
477
}
478
479
package() {
480
_resolve_options
481
482
local _out="$srcdir/selected"
483
if [[ "$HINTING" == true ]]; then
484
_out="$srcdir/hinted"
485
elif [[ "$NERD_PATCH" == true ]]; then
486
_out="$srcdir/patched"
487
fi
488
if ! compgen -G "$_out/*.[ot]tf" >/dev/null; then
489
echo "Error: no fonts to install in $_out." >&2; exit 1
490
fi
491
install -Dm644 -t "$pkgdir/usr/share/fonts/inter" "$_out/"*.[ot]tf
492
install -Dm644 "$srcdir/LICENSE-${_interver}.txt" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
493
494
# Opt-in rendering tweak (see the header): bytecode hinting for the families
495
# this build installed as ttfautohinted TTFs. Shipped in conf.avail and
496
# deliberately not enabled. The family list is read from the fonts, so Nerd
497
# Fonts names and family suffixes are covered.
498
if [[ "$HINTING" == true && "$HINT_ENGINE" == ttfautohint ]]; then
499
local _fam _conf="$pkgdir/usr/share/fontconfig/conf.avail/80-$pkgname.conf"
500
install -d "${_conf%/*}"
501
{
502
echo '<?xml version="1.0" encoding="UTF-8"?>'
503
echo '<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">'
504
echo "<!-- Installed by $pkgname. Use the ttfautohint bytecode hints in these"
505
echo " fonts rather than FreeType's light autohinter. hintmedium, not"
506
echo " hintfull: same rendering in cairo/pango, but Chrome keeps subpixel"
507
echo " positioning at hintmedium. -->"
508
echo '<fontconfig>'
509
# One <match> per family: several <test>s in one <match> are ANDed.
510
while IFS= read -r _fam; do
511
_fam="${_fam//&/&}"; _fam="${_fam//</<}"
512
cat <<EOF
513
<match target="font">
514
<test name="family" compare="eq"><string>$_fam</string></test>
515
<edit name="hinting" mode="assign"><bool>true</bool></edit>
516
<edit name="autohint" mode="assign"><bool>false</bool></edit>
517
<edit name="hintstyle" mode="assign"><const>hintmedium</const></edit>
518
</match>
519
EOF
520
done < <(python - "$pkgdir/usr/share/fonts/inter/"*.ttf <<'PY' | sort -u
521
import sys
522
from fontTools.ttLib import TTFont
523
for path in sys.argv[1:]:
524
name = TTFont(path, lazy=True)["name"]
525
print(name.getDebugName(16) or name.getDebugName(1))
526
PY
527
)
528
echo '</fontconfig>'
529
} > "$_conf"
530
chmod 644 "$_conf"
531
fi
532
}
533
Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-09-25 15:12:17 | Low | 1 |