ttf-tiktok-sans-hinted
LOW
maintainer gaougalos
0 votes
scanned 2026-11-03 00:04:01.898975
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-tiktok-sans-hinted
3
_gmver=4.000
4
_gfcommit=2750b521bd22ce141f12617194ab0e04cf5d12d5
5
_nfver=3.5.1
6
pkgver="${_gmver}"
7
pkgrel=1
8
pkgdesc='TikTok Sans (Google Fonts), a four-axis (opsz, slnt, wdth, wght) sans with Greek and Cyrillic, re-hinted with ttfautohint for FreeType (optionally static / Nerd Fonts patched)'
9
arch=('any')
10
url='https://fonts.google.com/specimen/TikTok+Sans'
11
license=('OFL-1.1')
12
makedepends=('python' 'python-fonttools' 'fontforge' 'parallel' 'ttfautohint')
13
options=(!strip)
14
provides=('ttf-tiktok-sans')
15
conflicts=('ttf-tiktok-sans')
16
source=(
17
"TikTokSansVF.ttf::https://raw.githubusercontent.com/google/fonts/${_gfcommit}/ofl/tiktoksans/TikTokSans%5Bopsz%2Cslnt%2Cwdth%2Cwght%5D.ttf"
18
"OFL.txt::https://raw.githubusercontent.com/google/fonts/${_gfcommit}/ofl/tiktoksans/OFL.txt"
19
"font-patcher-${_nfver}.zip::https://github.com/ryanoasis/nerd-fonts/releases/download/v${_nfver}/FontPatcher.zip"
20
"make_statics.py"
21
"make_features.py"
22
"set_gasp.py"
23
"measure.py"
24
"README.md"
25
"FEATURES.md"
26
)
27
noextract=("font-patcher-${_nfver}.zip")
28
sha256sums=('0e7f0a3e924c9a86478fc6fc2946de2e4ab8fc704ed72ee40434ade94bb9b0c6'
29
'99e743f68f5eac487004c73aaca69c5d80d91ddb7b75c04bdf5f39331d9b7158'
30
'42bcb32145499a35732274c7fc48deb434ad0d2e0e118f98527c1479c6fa251a'
31
'b73efb266819480baa63620e992c64d849d776288a99f2cc32ebcb2a4e43026d'
32
'200fc13d7cf288ebd10c2832a0c9e1cf5a8b7c7e4e6283311778a2df7057581e'
33
'0b0464b268525569b5fa28b4735791efb22f22829ad178629776ae3ea82d7f99'
34
'3ad4eb1296ca40b68d32fe5220fe03cb0c8b0d7725b1f179d3df2176430b0ff8'
35
'3e8524eed41351be775a78779d9e7dced5b14b6874ec94874edca5831c7e8d3d'
36
'6500652f01f55c5924d94ac885fabbf4a1cbfb882e9228ebf55d02683a58ff6c')
37
38
# ── What this package does ──────────────────────────────────────────────────
39
#
40
# TikTok Sans (TikTok Inc.; Grilli Type, Contrast Foundry, Type Network) is
41
# shipped as ONE variable font with four axes: opsz 12-36 (default 36), slnt
42
# -6-0 (default 0, the italic), wdth 75-150 (default 100) and wght 300-900
43
# (default 300). Latin (incl. Vietnamese), Cyrillic and modern monotonic Greek
44
# (no polytonic). The source is pinned to the google/fonts commit above.
45
#
46
# UNLIKE most Google fonts this one ships hinted: the Google Fonts pipeline ran
47
# ttfautohint over it (fpgm/cvt/prep, instructions in 999 of 1167 outlines, plus
48
# a cvar). The upstream result is stable (no glued dots) but heavy: dev 18-20 at
49
# wght 300-400 (README.md section 3). So:
50
#
51
# * static fonts: re-hinting with this package's presets is clearly closer to the
52
# outline (Regular: dev 11.8 instead of 17.9) and each static is hinted on its
53
# own weight/width/optical size. HINTING defaults to true.
54
# * the variable font: re-hinting is NOT better than upstream (it hints only the
55
# default master, Light/opsz 36, and the glyphs get no cvar). HINTING defaults to
56
# false, which keeps the upstream bytecode. With HINTING=true the cvar is
57
# removed first (it would point into a cvt that ttfautohint rewrites).
58
#
59
# FreeType only runs TrueType bytecode at hintstyle hintmedium/hintfull. The
60
# package ships (not enabled) /usr/share/fontconfig/conf.avail/80-$pkgname.conf
61
# that turns it on for the installed families, excluding Chromium/Electron by
62
# prgname (at device scale 1 they round every advance at hintmedium).
63
#
64
# ── Build-time options ───────────────────────────────────────────────────────
65
#
66
# Run from a terminal, prepare() asks for NERD_PATCH, TS_VARIANT, FEATURE_DEFAULTS,
67
# HINTING and HINT_PRESET (Enter keeps the default). Anything already set in the
68
# environment is not asked. Without a TTY the environment / defaults apply.
69
# Answers are saved to $srcdir/.build_opts.
70
#
71
# TS_VARIANT variable|static (default: variable)
72
# variable the four-axis variable font (upright + slant)
73
# static one TTF per weight/width (and italic), cut with the
74
# fontTools instancer and hinted on its own
75
# STATIC_WEIGHTS "300 ... 900" wght values to cut (default: all seven)
76
# STATIC_ITALIC true/false also cut the slanted (slnt -6) fonts (default true)
77
# STATIC_WIDTHS "100" wdth values: 75 100 125 150 (default: 100 only;
78
# others get Condensed/Expanded/ExtraExpanded in the name)
79
# STATIC_OPSZ 14 optical size 12-36 (default 14; one per set,
80
# not part of the name)
81
#
82
# NERD_PATCH true/false Patch with Nerd Fonts glyphs (default: false).
83
# font-patcher drops fvar/gvar, so this forces
84
# TS_VARIANT=static. Family "TikTok Sans Nerd Font (Mono|Propo)".
85
#
86
# HINTING true/false Hint with ttfautohint. Default: true for static, false for
87
# variable (keep the upstream bytecode, see above).
88
#
89
# HINT_PRESET natural|balanced|sharp|light|custom (default: natural)
90
# natural stem=nnn range 8-48 x-height 0 (closest to the
91
# outline; default)
92
# balanced stem=qsq range 8-48 x-height 14 (ttfautohint
93
# defaults; opens
94
# a few more dots,
95
# same dev at 400)
96
# sharp stem=sss range 6-48 x-height 14 (higher dev)
97
# light stem=nnn range 12-48 x-height 0 (HiDPI)
98
# custom use the HINT_* variables below verbatim
99
# Individual knobs (override the preset; empty = preset value):
100
# HINT_MODE HINT_RANGE_MIN HINT_RANGE_MAX HINT_LIMIT HINT_XHEIGHT
101
# HINT_XSNAP_EXC HINT_DEFAULT_SCRIPT HINT_FALLBACK_SCRIPT HINT_WINCOMPAT
102
# HINT_TTFA_TABLE HINT_FAMILY_SUFFIX HINT_INTEGER_PPEM (off: it grows text on
103
# Linux, +16-19% ink at small sizes) GASP_MODE keep|sized|smooth|gridfit
104
#
105
# FEATURE_DEFAULTS "tag,tag,..." (default: empty = leave the fonts alone)
106
# Bake these GSUB features into calt so EVERY renderer applies
107
# them (fontconfig fontfeatures only reaches pango). TikTok Sans'
108
# candidates: case, tnum, zero, ss01-ss06 (see FEATURES.md). make_features.py refuses
109
# aalt/ordn/dlig. Only a few are right for running text
110
# (e.g. zero or ss06); frac and sups fire inside ordinary words.
111
# FEATURE_DEFAULTS=fonts.conf takes the features that are ACTIVE
112
# (uncommented) in the <match> for family "TikTok Sans" of
113
# ${TS_FONTS_CONF:-~/.config/fontconfig/fonts.conf}. Dropped with
114
# a note: negated tags (-liga), tags the font lacks in GSUB, tags
115
# HarfBuzz always applies (kern liga ccmp locl mark mkmk calt) and
116
# the ones make_features.py refuses (aalt ordn dlig ...).
117
# FEATURE_FAMILY "Name" Install the result under this family instead.
118
#
119
# Examples:
120
# makepkg -si (asks, when run from a terminal)
121
# makepkg -si </dev/null (never asks: defaults only)
122
# TS_VARIANT=static makepkg -si
123
# HINT_PRESET=balanced makepkg -si
124
# NERD_PATCH=true STATIC_WEIGHTS="400 700" makepkg -si
125
# ────────────────────────────────────────────────────────────────────────────
126
127
_opt_keys=(TS_VARIANT FEATURE_DEFAULTS FEATURE_FAMILY
128
STATIC_WEIGHTS STATIC_ITALIC STATIC_WIDTHS STATIC_OPSZ NERD_PATCH
129
HINTING HINT_PRESET HINT_MODE HINT_RANGE_MIN HINT_RANGE_MAX
130
HINT_LIMIT HINT_XHEIGHT HINT_XSNAP_EXC HINT_DEFAULT_SCRIPT
131
HINT_FALLBACK_SCRIPT HINT_WINCOMPAT HINT_TTFA_TABLE
132
HINT_FAMILY_SUFFIX HINT_INTEGER_PPEM GASP_MODE)
133
134
_ask_yn() {
135
local _ans
136
read -r -p " $1? [$2] " _ans || _ans=""
137
[[ "${_ans:-$2}" =~ ^[yY] ]] && _yn=true || _yn=false
138
}
139
140
# _ask_choice TITLE DEFAULT KEY:description ... -> sets _choice to a KEY.
141
_ask_choice() {
142
local _title="$1" _default="$2"; shift 2
143
local -a _items=("$@")
144
local _i _ans
145
echo " $_title:"
146
for _i in "${!_items[@]}"; do
147
printf " %d) %-12s %s%s\n" "$((_i + 1))" "${_items[$_i]%%:*}" "${_items[$_i]#*:}" \
148
"$([[ "${_items[$_i]%%:*}" == "$_default" ]] && echo " (default)")"
149
done
150
while :; do
151
read -r -p " > " _ans || _ans=""
152
if [[ -z "$_ans" ]]; then _choice="$_default"; return; fi
153
if [[ "$_ans" =~ ^[0-9]+$ ]] && (( _ans >= 1 && _ans <= ${#_items[@]} )); then
154
_choice="${_items[$((_ans - 1))]%%:*}"; return
155
fi
156
echo " Enter 1-${#_items[@]}, or press Enter for $_default."
157
done
158
}
159
160
# Prints the bakeable tags active for family "TikTok Sans" in the user's fonts.conf.
161
_features_from_fontsconf() {
162
local _conf="${TS_FONTS_CONF:-${XDG_CONFIG_HOME:-$HOME/.config}/fontconfig/fonts.conf}"
163
if [[ ! -f "$_conf" ]]; then
164
echo "Error: $_conf not found (set TS_FONTS_CONF)." >&2; return 1
165
fi
166
python - "$_conf" "$srcdir/TikTokSansVF.ttf" <<'PY'
167
import sys
168
import xml.etree.ElementTree as ET
169
from fontTools.ttLib import TTFont
170
conf, font = sys.argv[1:3]
171
always = {"kern", "liga", "ccmp", "locl", "mark", "mkmk", "calt", "clig", "rlig", "rvrn"}
172
refused = {"aalt", "ordn", "dlig", "salt", "hlig", "hist"}
173
gsub = {r.FeatureTag for r in TTFont(font, lazy=True)["GSUB"].table.FeatureList.FeatureRecord}
174
tags = []
175
for m in ET.parse(conf).getroot().iter("match"):
176
if m.get("target") != "font":
177
continue
178
if not any(t.get("name") == "family" and (t.findtext("string") or "").strip() == "TikTok Sans"
179
for t in m.findall("test")):
180
continue
181
for e in m.findall("edit"):
182
if e.get("name") != "fontfeatures":
183
continue
184
for st in e.findall("string"):
185
tag = (st.text or "").strip()
186
why = None
187
if tag.startswith("-"): why = "negated"
188
elif tag in always: why = "already applied by every shaper"
189
elif tag in refused: why = "refused by make_features.py"
190
elif tag not in gsub: why = "not a GSUB feature of the font"
191
if why:
192
print(f" note: fonts.conf: '{tag}' skipped ({why})", file=sys.stderr)
193
elif tag not in tags:
194
tags.append(tag)
195
print(",".join(tags))
196
PY
197
}
198
199
_prompt_options() {
200
if [[ -t 0 ]]; then
201
echo ""
202
echo " $pkgname: build options (Enter = default)"
203
echo ""
204
if [[ -z "${NERD_PATCH:-}" ]]; then
205
_ask_yn "Patch with Nerd Fonts glyphs (forces static fonts)" n; NERD_PATCH=$_yn
206
fi
207
if [[ "$NERD_PATCH" != true && -z "${TS_VARIANT:-}" ]]; then
208
_ask_choice "Font set" variable \
209
"variable:one four-axis font, upright + slant (recommended)" \
210
"static:one file per weight (and italic), hinted per file"
211
TS_VARIANT=$_choice
212
fi
213
if [[ "${FEATURE_DEFAULTS+set}" != set ]]; then
214
echo ""
215
echo " A font cannot declare a feature \"on by default\"; baking moves its lookups"
216
echo " into calt, which every program applies (see the header of this PKGBUILD)."
217
_ask_choice "Bake features into calt" none \
218
"none:leave the fonts as upstream ships them (default)" \
219
"fonts.conf:the features active for \"TikTok Sans\" in ~/.config/fontconfig/fonts.conf" \
220
"custom:type the tag list yourself"
221
case $_choice in
222
none) FEATURE_DEFAULTS="" ;;
223
fonts.conf) FEATURE_DEFAULTS="fonts.conf" ;;
224
custom)
225
echo " Tags, comma or space separated (e.g. \"case,frac\"):"
226
read -r -p " > " _tags || _tags=""
227
_tags="${_tags//[[:space:]]/,}"
228
while [[ "$_tags" == *,,* ]]; do _tags="${_tags//,,/,}"; done
229
_tags="${_tags#,}"; _tags="${_tags%,}"
230
FEATURE_DEFAULTS="$_tags" ;;
231
esac
232
fi
233
if [[ -z "${HINTING:-}" ]]; then
234
# Upstream already ships bytecode. Re-hinting wins for statics, not for the VF.
235
if [[ "$NERD_PATCH" == true || "${TS_VARIANT:-variable}" == static ]]; then
236
_ask_yn "Re-hint with ttfautohint (n = keep upstream's hinting; patched fonts lose it)" y
237
else
238
_ask_yn "Re-hint with ttfautohint (n = keep upstream's hinting, better for the variable font)" n
239
fi
240
HINTING=$_yn
241
fi
242
if [[ "$HINTING" == true && -z "${HINT_PRESET:-}" ]]; then
243
_ask_choice "Hinting preset" natural \
244
"natural:stem n, 8-48px, no x-height boost (closest to the design)" \
245
"balanced:stem q, 8-48px (opens the dots, a few more dots open)" \
246
"sharp:stem s, 6-48px (highest contrast, higher dev)" \
247
"light:stem n, 12-48px, no x-height boost (HiDPI)" \
248
"custom:use the HINT_* environment variables"
249
HINT_PRESET=$_choice
250
fi
251
echo ""
252
else
253
echo "==> Non-interactive build (no TTY): using environment variables / defaults."
254
fi
255
256
if [[ "${FEATURE_DEFAULTS:-}" == fonts.conf ]]; then
257
FEATURE_DEFAULTS="$(_features_from_fontsconf)" || exit 1
258
echo "==> FEATURE_DEFAULTS from fonts.conf: ${FEATURE_DEFAULTS:-<none>}"
259
fi
260
261
local _k
262
: > "$srcdir/.build_opts"
263
for _k in "${_opt_keys[@]}"; do
264
# "set" rather than non-empty: HINT_XSNAP_EXC="" differs from unset.
265
if [[ "${!_k+set}" == set ]]; then
266
printf '%s=%s\n' "$_k" "${!_k}" >> "$srcdir/.build_opts"
267
fi
268
done
269
}
270
271
# makepkg runs build() and package() in separate shells, so both call this.
272
_resolve_options() {
273
local _k _v
274
if [[ ! -f "$srcdir/.build_opts" ]]; then
275
echo "Error: $srcdir/.build_opts missing; run a full makepkg (prepare() writes it)." >&2
276
exit 1
277
fi
278
while IFS='=' read -r _k _v; do
279
if [[ " ${_opt_keys[*]} " == *" $_k "* ]]; then
280
printf -v "$_k" '%s' "$_v"
281
fi
282
done < "$srcdir/.build_opts"
283
284
TS_VARIANT="${TS_VARIANT:-variable}"
285
FEATURE_DEFAULTS="${FEATURE_DEFAULTS:-}"
286
FEATURE_FAMILY="${FEATURE_FAMILY:-}"
287
STATIC_WEIGHTS="${STATIC_WEIGHTS:-300 400 500 600 700 800 900}"
288
STATIC_ITALIC="${STATIC_ITALIC:-true}"
289
STATIC_WIDTHS="${STATIC_WIDTHS:-100}"
290
STATIC_OPSZ="${STATIC_OPSZ:-14}"
291
NERD_PATCH="${NERD_PATCH:-false}"
292
if [[ "$TS_VARIANT" == static || "$NERD_PATCH" == true ]]; then
293
HINTING="${HINTING:-true}"
294
else
295
HINTING="${HINTING:-false}"
296
fi
297
HINT_PRESET="${HINT_PRESET:-natural}"
298
GASP_MODE="${GASP_MODE:-keep}"
299
HINT_WINCOMPAT="${HINT_WINCOMPAT:-false}"
300
HINT_TTFA_TABLE="${HINT_TTFA_TABLE:-false}"
301
HINT_INTEGER_PPEM="${HINT_INTEGER_PPEM:-false}"
302
HINT_DEFAULT_SCRIPT="${HINT_DEFAULT_SCRIPT:-latn}"
303
HINT_FALLBACK_SCRIPT="${HINT_FALLBACK_SCRIPT:-latn}"
304
305
case "$TS_VARIANT" in
306
variable|static) ;;
307
*) echo "Error: TS_VARIANT='$TS_VARIANT' invalid (variable|static)." >&2; exit 1 ;;
308
esac
309
for _v in STATIC_ITALIC NERD_PATCH HINTING HINT_WINCOMPAT HINT_TTFA_TABLE HINT_INTEGER_PPEM; do
310
case "${!_v}" in
311
true|false) ;;
312
*) echo "Error: $_v='${!_v}' must be true or false." >&2; exit 1 ;;
313
esac
314
done
315
# font-patcher drops fvar/gvar, so patching always works on statics.
316
if [[ "$NERD_PATCH" == true && "$TS_VARIANT" == variable ]]; then
317
echo "==> Note: the variable font cannot be Nerd-patched; using TS_VARIANT=static."
318
TS_VARIANT=static
319
fi
320
for _v in ${FEATURE_DEFAULTS//,/ }; do
321
if [[ ! "$_v" =~ ^[A-Za-z0-9]{4}$ ]]; then
322
echo "Error: FEATURE_DEFAULTS: '$_v' is not a feature tag (e.g. case)." >&2
323
exit 1
324
fi
325
done
326
for _v in $STATIC_WEIGHTS; do
327
case "$_v" in
328
300|400|500|600|700|800|900) ;;
329
*) echo "Error: STATIC_WEIGHTS: '$_v' is not 300, 400, ... 900." >&2; exit 1 ;;
330
esac
331
done
332
for _v in $STATIC_WIDTHS; do
333
case "$_v" in
334
75|100|125|150) ;;
335
*) echo "Error: STATIC_WIDTHS: '$_v' is not 75, 100, 125 or 150." >&2; exit 1 ;;
336
esac
337
done
338
if [[ ! "$STATIC_OPSZ" =~ ^[0-9]+(\.[0-9]+)?$ ]] || \
339
(( $(printf '%.0f' "$STATIC_OPSZ") < 12 || $(printf '%.0f' "$STATIC_OPSZ") > 36 )); then
340
echo "Error: STATIC_OPSZ='$STATIC_OPSZ' must be 12-36." >&2; exit 1
341
fi
342
343
local _m _lo _hi _xh
344
case "$HINT_PRESET" in
345
natural) _m=nnn; _lo=8; _hi=48; _xh=0 ;;
346
balanced) _m=qsq; _lo=8; _hi=48; _xh=14 ;;
347
sharp) _m=sss; _lo=6; _hi=48; _xh=14 ;;
348
light) _m=nnn; _lo=12; _hi=48; _xh=0 ;;
349
custom) _m=nnn; _lo=8; _hi=48; _xh=0 ;;
350
*)
351
echo "Error: unknown HINT_PRESET='$HINT_PRESET'." >&2
352
echo " Valid: natural balanced sharp light custom" >&2
353
exit 1 ;;
354
esac
355
HINT_MODE="${HINT_MODE:-$_m}"
356
HINT_RANGE_MIN="${HINT_RANGE_MIN:-$_lo}"
357
HINT_RANGE_MAX="${HINT_RANGE_MAX:-$_hi}"
358
HINT_LIMIT="${HINT_LIMIT:-$HINT_RANGE_MAX}"
359
HINT_XHEIGHT="${HINT_XHEIGHT:-$_xh}"
360
361
if [[ ! "$HINT_MODE" =~ ^[nqs]{3}$ ]]; then
362
echo "Error: HINT_MODE='$HINT_MODE' must be 3 chars from n/q/s (e.g. nnn)." >&2
363
exit 1
364
fi
365
for _v in HINT_RANGE_MIN HINT_RANGE_MAX HINT_LIMIT HINT_XHEIGHT; do
366
if [[ ! "${!_v}" =~ ^[0-9]+$ ]]; then
367
echo "Error: $_v='${!_v}' must be a non-negative integer." >&2; exit 1
368
fi
369
done
370
if (( HINT_RANGE_MIN > HINT_RANGE_MAX )); then
371
echo "Error: HINT_RANGE_MIN ($HINT_RANGE_MIN) > HINT_RANGE_MAX ($HINT_RANGE_MAX)." >&2
372
exit 1
373
fi
374
for _v in HINT_DEFAULT_SCRIPT HINT_FALLBACK_SCRIPT; do
375
if [[ ! "${!_v}" =~ ^[a-z0-9]{3,4}$ ]]; then
376
echo "Error: $_v='${!_v}' must be a script tag (e.g. latn, none)." >&2; exit 1
377
fi
378
done
379
case "$GASP_MODE" in
380
keep|sized|smooth|gridfit) ;;
381
*) echo "Error: GASP_MODE='$GASP_MODE' invalid (keep|sized|smooth|gridfit)." >&2; exit 1 ;;
382
esac
383
}
384
385
prepare() {
386
_prompt_options
387
_resolve_options # validate now, so a typo fails before the long steps
388
389
rm -rf "$srcdir/font-patcher"
390
if [[ "$NERD_PATCH" == true ]]; then
391
mkdir -p "$srcdir/font-patcher"
392
bsdtar xf "$srcdir/font-patcher-${_nfver}.zip" -C "$srcdir/font-patcher"
393
fi
394
}
395
396
# _bake_features SRCDIR: move the lookups of FEATURE_DEFAULTS into calt into
397
# $srcdir/featured. Last step on purpose: ttfautohint never sees them.
398
_bake_features() {
399
local _src="$1" _fam=()
400
[[ -n "$FEATURE_DEFAULTS" ]] || return 0
401
[[ -n "$FEATURE_FAMILY" ]] && _fam=(--family "$FEATURE_FAMILY")
402
echo "==> Baking $FEATURE_DEFAULTS into calt" \
403
"${FEATURE_FAMILY:+(installed as '$FEATURE_FAMILY')}..."
404
python "$srcdir/make_features.py" --features "$FEATURE_DEFAULTS" \
405
"${_fam[@]+"${_fam[@]}"}" -o "$srcdir/featured" "$_src"/*.ttf
406
}
407
408
build() {
409
_resolve_options
410
411
echo "==> Options: variant=$TS_VARIANT nerd=$NERD_PATCH hinting=$HINTING"
412
if [[ "$TS_VARIANT" == static ]]; then
413
echo "==> Statics: weights='$STATIC_WEIGHTS' widths='$STATIC_WIDTHS' opsz=$STATIC_OPSZ italic=$STATIC_ITALIC"
414
fi
415
if [[ "$HINTING" == true ]]; then
416
echo "==> ttfautohint: preset=$HINT_PRESET stem=$HINT_MODE" \
417
"range=$HINT_RANGE_MIN-$HINT_RANGE_MAX limit=$HINT_LIMIT x-height=$HINT_XHEIGHT" \
418
"x-snap-exc='${HINT_XSNAP_EXC-<default>}' gasp=$GASP_MODE integer-ppem=$HINT_INTEGER_PPEM" \
419
"ttfa-table=$HINT_TTFA_TABLE${HINT_FAMILY_SUFFIX:+ suffix='$HINT_FAMILY_SUFFIX'}"
420
fi
421
422
rm -rf "$srcdir/selected" "$srcdir/patched" "$srcdir/hinted" "$srcdir/featured" "$srcdir/nocvar"
423
mkdir -p "$srcdir/selected" "$srcdir/patched" "$srcdir/hinted"
424
425
# ── Step 1: select ──────────────────────────────────────────────────────────
426
if [[ "$TS_VARIANT" == variable ]]; then
427
install -m644 "$srcdir/TikTokSansVF.ttf" "$srcdir/selected/TikTokSansVariable.ttf"
428
else
429
echo "==> Cutting static instances..."
430
local _w _d _it
431
for _d in $STATIC_WIDTHS; do
432
for _w in $STATIC_WEIGHTS; do
433
python "$srcdir/make_statics.py" --wght "$_w" --wdth "$_d" --opsz "$STATIC_OPSZ" \
434
-o "$srcdir/selected" "$srcdir/TikTokSansVF.ttf"
435
if [[ "$STATIC_ITALIC" == true ]]; then
436
python "$srcdir/make_statics.py" --wght "$_w" --wdth "$_d" --opsz "$STATIC_OPSZ" --italic \
437
-o "$srcdir/selected" "$srcdir/TikTokSansVF.ttf"
438
fi
439
done
440
done
441
fi
442
local _count
443
_count=$(find "$srcdir/selected" -name '*.ttf' | wc -l)
444
echo "==> Selected $_count font file(s)."
445
if (( _count == 0 )); then
446
echo "Error: no fonts produced." >&2; exit 1
447
fi
448
449
local _hintsrc="$srcdir/selected"
450
451
# ── Step 2: Nerd Fonts patching ─────────────────────────────────────────────
452
# Patch first, hint afterwards: font-patcher does not keep hint bytecode.
453
if [[ "$NERD_PATCH" == true ]]; then
454
echo "==> Patching with Nerd Fonts glyphs (this takes a while)..."
455
find "$srcdir/selected" -type f | sort | \
456
parallel --will-cite -j"$(nproc)" python "$srcdir/font-patcher/font-patcher" \
457
--variable-width-glyphs -q -c {} -out "$srcdir/patched" '>/dev/null'
458
_count=$(find "$srcdir/patched" -maxdepth 1 -name '*.ttf' | wc -l)
459
if (( _count == 0 )); then
460
echo "Error: font-patcher produced no output. See messages above." >&2; exit 1
461
fi
462
echo "==> Patched $_count font(s)."
463
_hintsrc="$srcdir/patched"
464
fi
465
466
if [[ "$HINTING" != true ]]; then
467
_bake_features "$_hintsrc"
468
return 0
469
fi
470
471
# ── Step 3: ttfautohint ─────────────────────────────────────────────────────
472
local -a _ta_opts=(
473
--hinting-range-min="$HINT_RANGE_MIN"
474
--hinting-range-max="$HINT_RANGE_MAX"
475
--hinting-limit="$HINT_LIMIT"
476
--increase-x-height="$HINT_XHEIGHT"
477
--stem-width-mode="$HINT_MODE"
478
--default-script="$HINT_DEFAULT_SCRIPT"
479
--ignore-restrictions
480
)
481
if [[ "$NERD_PATCH" == true ]]; then
482
_ta_opts+=(--fallback-script=none --fallback-scaling)
483
else
484
_ta_opts+=(--fallback-script="$HINT_FALLBACK_SCRIPT")
485
fi
486
if [[ "${HINT_XSNAP_EXC+set}" == set ]]; then
487
_ta_opts+=(--x-height-snapping-exceptions="$HINT_XSNAP_EXC")
488
fi
489
if [[ "$HINT_WINCOMPAT" == true ]]; then _ta_opts+=(--windows-compatibility); fi
490
if [[ -n "${HINT_FAMILY_SUFFIX:-}" ]]; then _ta_opts+=(--family-suffix="$HINT_FAMILY_SUFFIX"); fi
491
if [[ "$HINT_TTFA_TABLE" == true ]]; then _ta_opts+=(--ttfa-table); else _ta_opts+=(--no-info); fi
492
493
# Upstream's cvar points into the cvt that ttfautohint rewrites: drop it from
494
# variable fonts first (a copy; $srcdir/selected stays as cut).
495
if [[ "$TS_VARIANT" == variable ]]; then
496
mkdir -p "$srcdir/nocvar"
497
python - "$_hintsrc" "$srcdir/nocvar" <<'PY'
498
import glob, os, sys
499
from fontTools.ttLib import TTFont
500
for path in glob.glob(os.path.join(sys.argv[1], "*.ttf")):
501
font = TTFont(path)
502
if "cvar" in font:
503
del font["cvar"]
504
font.save(os.path.join(sys.argv[2], os.path.basename(path)))
505
PY
506
_hintsrc="$srcdir/nocvar"
507
fi
508
509
# Serial on purpose: GNU parallel splits arguments that contain spaces.
510
echo "==> Hinting with ttfautohint..."
511
local _f
512
for _f in "$_hintsrc"/*.ttf; do
513
ttfautohint "${_ta_opts[@]}" "$_f" "$srcdir/hinted/${_f##*/}"
514
done
515
516
if [[ "$HINT_INTEGER_PPEM" == true ]]; then
517
echo "==> Setting head.flags bit 3 (integer ppem)..."
518
python - "$srcdir/hinted/"*.ttf <<'PY'
519
import sys
520
from fontTools.ttLib import TTFont
521
for path in sys.argv[1:]:
522
font = TTFont(path)
523
font["head"].flags |= 1 << 3
524
font.save(path)
525
PY
526
fi
527
528
if [[ "$GASP_MODE" != keep ]]; then
529
echo "==> Applying gasp mode '$GASP_MODE'..."
530
python "$srcdir/set_gasp.py" "$GASP_MODE" "$srcdir/hinted/"*.ttf
531
fi
532
533
_bake_features "$srcdir/hinted"
534
}
535
536
package() {
537
_resolve_options
538
539
local _out="$srcdir/selected"
540
if [[ "$HINTING" == true ]]; then
541
_out="$srcdir/hinted"
542
elif [[ "$NERD_PATCH" == true ]]; then
543
_out="$srcdir/patched"
544
fi
545
if [[ -n "$FEATURE_DEFAULTS" ]]; then _out="$srcdir/featured"; fi
546
if ! compgen -G "$_out/*.ttf" >/dev/null; then
547
echo "Error: no fonts to install in $_out." >&2; exit 1
548
fi
549
local _fontdir="$pkgdir/usr/share/fonts/tiktok-sans"
550
install -Dm644 -t "$_fontdir" "$_out/"*.ttf
551
install -Dm644 "$srcdir/OFL.txt" "$pkgdir/usr/share/licenses/$pkgname/OFL.txt"
552
553
# Opt-in rendering tweak: bytecode hinting for the families this build
554
# installed. Shipped in conf.avail and deliberately not enabled. Skipped
555
# only for Nerd-patched fonts left unhinted (font-patcher drops the bytecode).
556
if [[ "$HINTING" == true || "$NERD_PATCH" != true ]]; then
557
local _avail="$pkgdir/usr/share/fontconfig/conf.avail"
558
install -d "$_avail"
559
local _fam _conf="$_avail/80-$pkgname.conf"
560
local _chromium_prgnames=(chrome chromium brave helium electron code slack signal-desktop vesktop)
561
local _prg _prgtests=""
562
for _prg in "${_chromium_prgnames[@]}"; do
563
_prgtests+=" <test qual=\"all\" name=\"prgname\" compare=\"not_eq\"><string>$_prg</string></test>"$'\n'
564
done
565
{
566
echo '<?xml version="1.0" encoding="UTF-8"?>'
567
echo '<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">'
568
echo "<!-- Installed by $pkgname. NOT enabled by default. Enable with:"
569
echo ""
570
echo " sudo ln -s /usr/share/fontconfig/conf.avail/80-$pkgname.conf /etc/fonts/conf.d/"
571
echo ""
572
echo " Use the ttfautohint bytecode hints in these fonts rather than"
573
echo " FreeType's light autohinter. hintmedium, not hintfull: same rendering"
574
echo " in cairo/pango, and Blink keeps subpixel positioning at hintmedium."
575
echo " Chromium and Electron apps are excluded: at device scale 1 they use"
576
echo " linear advances only for hintslight/none, so hintmedium would round"
577
echo " every glyph advance to a whole pixel (uneven letter gaps)."
578
echo " Firefox also rounds advances at hintmedium unless"
579
echo " gfx.text.subpixel-position.force-enabled is true. See README.md. -->"
580
echo '<fontconfig>'
581
while IFS= read -r _fam; do
582
_fam="${_fam//&/&}"; _fam="${_fam//</<}"
583
cat <<EOF
584
<match target="font">
585
<test name="family" compare="eq"><string>$_fam</string></test>
586
${_prgtests%$'\n'}
587
<edit name="hinting" mode="assign"><bool>true</bool></edit>
588
<edit name="autohint" mode="assign"><bool>false</bool></edit>
589
<edit name="hintstyle" mode="assign"><const>hintmedium</const></edit>
590
</match>
591
EOF
592
done < <(python - "$_fontdir/"*.ttf <<'PY' | sort -u
593
import sys
594
from fontTools.ttLib import TTFont
595
for path in sys.argv[1:]:
596
name = TTFont(path, lazy=True)["name"]
597
print(name.getDebugName(16) or name.getDebugName(1))
598
PY
599
)
600
echo '</fontconfig>'
601
} > "$_conf"
602
chmod 644 "$_conf"
603
fi
604
605
install -Dm644 -t "$pkgdir/usr/share/doc/$pkgname" "$srcdir/README.md" "$srcdir/FEATURES.md"
606
}
607
Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-11-03 00:04:01 | Low | 1 |