ttf-inter-hinted

LOW
maintainer gaougalos 0 votes scanned 2026-09-25 15:12:17.861096
View on AUR
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>
2pkgname=ttf-inter-hinted
3_interver=4.1
4_nfver=3.5.1
5pkgver="${_interver}"
6pkgrel=1
7pkgdesc='Inter, a typeface designed for UI legibility, re-hinted with ttfautohint for FreeType (optionally Nerd Fonts patched)'
8arch=('any')
9url='https://rsms.me/inter/'
10license=('OFL-1.1')
11makedepends=('python' 'python-fonttools' 'python-skia-pathops' 'fontforge' 'parallel' 'ttfautohint')
12optdepends=('afdko: CFF/OTF hinting via otfautohint (HINT_ENGINE=cff)')
13options=(!strip)
14provides=('inter-font')
15conflicts=('inter-font' 'interui-ttf-hinted')
16replaces=('interui-ttf-hinted')
17source=(
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)
26noextract=("font-patcher-${_nfver}.zip")
27sha256sums=('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
338prepare() {
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
347build() {
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
479package() {
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//&/&amp;}"; _fam="${_fam//</&lt;}"
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>
519EOF
520 done < <(python - "$pkgdir/usr/share/fonts/inter/"*.ttf <<'PY' | sort -u
521import sys
522from fontTools.ttLib import TTFont
523for path in sys.argv[1:]:
524 name = TTFont(path, lazy=True)["name"]
525 print(name.getDebugName(16) or name.getDebugName(1))
526PY
527)
528 echo '</fontconfig>'
529 } > "$_conf"
530 chmod 644 "$_conf"
531 fi
532}
533

Scan history

Scanned at (UTC)SeverityRules
2026-09-25 15:12:17 Low 1

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion