ttf-misans-latin-hinted
MEDIUM
maintainer gaougalos
0 votes
scanned 2026-09-25 11:11:47.608437
Why flagged
One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).
Triggered rules
Medium
source=() URL on a non-standard host
source_untrusted_domain
One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).
-
PKGBUILD:17
source=("MiSans_Latin-${pkgver}.zip::https://hyperos.mi.com/font-download/MiSans_Latin.zip"
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 offending line(s) highlighted
1
# Maintainer: gaou-piou <i.am.piou@gmail.com>
2
pkgname=ttf-misans-latin-hinted
3
pkgver=4.007
4
pkgrel=1
5
pkgdesc="MiSans Latin (Latin, Greek, Cyrillic) by Xiaomi, autohinted with ttfautohint and with fontconfig-friendly weight classes"
6
arch=(any)
7
url="https://hyperos.mi.com/font/en/download/"
8
license=(LicenseRef-MiSans)
9
makedepends=(python python-fonttools ttfautohint)
10
provides=(ttf-misans-latin)
11
conflicts=(ttf-misans-latin)
12
options=(!strip)
13
# Xiaomi re-uploads the zip in place without a version in the URL, so the
14
# local file name carries pkgver and the checksum is pinned: a silent upstream
15
# re-spin fails the checksum instead of slipping through. prepare() also checks
16
# that the fonts really are version $pkgver.
17
source=("MiSans_Latin-${pkgver}.zip::https://hyperos.mi.com/font-download/MiSans_Latin.zip"
18
"LICENSE.pdf::https://hyperos.mi.com/font-download/MiSans字体知识产权许可协议.pdf"
19
"fix_weights.py"
20
"set_gasp.py")
21
sha256sums=('d24091ccd409a4152ffcc12cd659c16df9cdcdb4c702d8ae355b321e711f0004'
22
'4a93a27cd2bd81b3b5ecfd0a853144a876fa26938a93a68443c67d74172fcb86'
23
'f7b025ab723a672e0c821c610251199d04a5342c265483eafeb35f3e5f0be45b'
24
'0b0464b268525569b5fa28b4735791efb22f22829ad178629776ae3ea82d7f99')
25
26
# ── Licensing note ──────────────────────────────────────────────────────────
27
#
28
# The MiSans license (§2.2) forbids adapting or redeveloping the fonts. This
29
# PKGBUILD distributes no font files: it downloads Xiaomi's originals and hints
30
# them locally on the user's machine, for that user's own use. You are
31
# responsible for deciding whether that is acceptable to you.
32
#
33
# ── What this package does ──────────────────────────────────────────────────
34
#
35
# Upstream MiSans Latin 4.007 ships effectively unhinted: the static TTFs carry
36
# an 8-byte 'prep' program and not a single glyph instruction. This package:
37
#
38
# 1. takes the ten static TTF weights (Thin … Heavy); the variable font, OTF
39
# and WOFF/WOFF2 files are not used
40
# 2. optionally normalises usWeightClass (FIX_WEIGHTS, default on). Stock
41
# weights make fontconfig pick Medium for "regular" and Heavy for "bold";
42
# see fix_weights.py
43
# 3. hints every weight with ttfautohint, which detects the Latin, Greek and
44
# Cyrillic scripts and builds separate blue zones for each. By default
45
# every weight takes its blue zones from Regular (--reference), so bold
46
# words sit at the same x-height and cap height as the surrounding text
47
# 4. optionally rewrites the gasp table (GASP_MODE)
48
#
49
# Measured on FreeType 2.14.3 (v40 interpreter, grayscale), rendered through
50
# pango/cairo at 9-16px:
51
#
52
# * Only the THIRD letter of --stem-width-mode matters on Linux. v40 reports
53
# itself to the bytecode as DirectWrite ClearType, so nnn, snn and nsn
54
# render pixel-identically; nns does not. The presets below therefore
55
# differ where it counts: n (natural), q (quantized) or s (strong).
56
# * --reference=Regular: Regular/Bold cap height matched at 8 of 8 sizes
57
# (3 of 8 without it) and x-height at 7 of 8 (4 of 8).
58
# * The stock, unhinted fonts break visibly at hintfull (gaps inside words,
59
# uneven baseline); the hinted ones do not.
60
# * No visible effect for MiSans on Linux: gasp (FreeType ignores it),
61
# --composites (identical pixels, larger file), --windows-compatibility
62
# (Windows clipping only), and --increase-x-height 0 vs 14 (nearly
63
# identical). gasp and -W still matter if the fonts are used under Wine.
64
# * Advance widths never change: v40 ignores horizontal hints, so spacing is
65
# exactly the designer's at every setting.
66
#
67
# FreeType only runs TrueType bytecode at hintstyle hintmedium/hintfull. With
68
# the common hintslight setting it uses its own light autohinter instead and
69
# ignores these hints. The package therefore ships (but does not enable)
70
# /usr/share/fontconfig/conf.avail/80-misans-latin-hinted.conf, which turns on
71
# full bytecode hinting for this family only. Enable it with:
72
#
73
# sudo ln -s /usr/share/fontconfig/conf.avail/80-misans-latin-hinted.conf \
74
# /etc/fonts/conf.d/
75
#
76
# ── Build-time options (environment variables) ──────────────────────────────
77
#
78
# FIX_WEIGHTS true/false Normalise usWeightClass (default: true)
79
# HINT_REFERENCE true/false Hint every weight against Regular's blue zones
80
# (--reference; default: true)
81
#
82
# HINT_PRESET name Named bundle of ttfautohint flags (default: balanced)
83
# ("Linux" = the stem letter FreeType v40 actually uses)
84
# balanced stem=qsq (Linux: q) range 8-50 x-height 14 (upstream defaults)
85
# sharp stem=sss (Linux: s) range 6-50 x-height 14 (max contrast, low-DPI)
86
# natural stem=nnn (Linux: n) range 8-50 x-height 0 (least distortion)
87
# light stem=nnn (Linux: n) range 12-50 x-height 0 (HiDPI; <12px left alone)
88
# hack stem=qsq (Linux: q) range 6-50 x-height 10 fallback latn
89
# (the settings source-foundry's Hack is built with)
90
# custom use the individual HINT_* vars below verbatim
91
#
92
# Individual ttfautohint knobs (override the preset; empty = use preset value):
93
# HINT_MODE nnn|qqq|qsq|sss 3-char --stem-width-mode (grayscale/GDI/DW; n/q/s)
94
# On Linux only the 3rd letter has an effect (see above).
95
# HINT_RANGE_MIN N --hinting-range-min (default 8)
96
# HINT_RANGE_MAX N --hinting-range-max (default 50)
97
# HINT_LIMIT N --hinting-limit (default: same as HINT_RANGE_MAX, so
98
# hinting really stops above the range instead of reusing
99
# the largest hint set up to 200px; 0 = no limit)
100
# HINT_XHEIGHT N --increase-x-height (default 14; 0 = disable)
101
# HINT_XSNAP_EXC STR --x-height-snapping-exceptions (e.g. "13-17", "" = none)
102
# HINT_FALLBACK_SCRIPT STR --fallback-script for glyphs outside any script
103
# (symbols, arrows); e.g. latn (default: none)
104
# HINT_WINCOMPAT true/false --windows-compatibility (Windows/Wine only)
105
# HINT_TTFA_TABLE true/false --ttfa-table: embed a TTFA table recording every
106
# parameter used, readable with `ttfautohint --ttfa-info`
107
# (default: false)
108
# HINT_FAMILY_SUFFIX STR -F/--family-suffix, e.g. " Hinted" gives the family
109
# "MiSans Latin Hinted" (the fontconfig snippet follows)
110
#
111
# GASP_MODE keep|sized|smooth|gridfit (default: keep; Windows/Wine only)
112
# keep leave the gasp table as ttfautohint wrote it ({0xFFFF: 15})
113
# sized MS strategy: <=8 grayscale, 9-16 gridfit, 17+ both
114
# smooth all sizes anti-aliased ({0xFFFF: 15}, symmetric flags)
115
# gridfit all sizes gridfit+grayscale ({0xFFFF: 3})
116
#
117
# Examples:
118
# makepkg -si
119
# HINT_PRESET=sharp makepkg -si
120
# HINT_PRESET=custom HINT_MODE=qqs HINT_RANGE_MIN=6 makepkg -si
121
# FIX_WEIGHTS=false HINT_FAMILY_SUFFIX=" Hinted" makepkg -si
122
# ────────────────────────────────────────────────────────────────────────────
123
124
_fontdir="MiSans Latin/ttf"
125
_family="MiSans Latin"
126
127
# Resolve and validate every option from the environment. makepkg runs build()
128
# and package() in separate shells, so both call this; it is deterministic and
129
# never prompts.
130
_resolve_options() {
131
FIX_WEIGHTS="${FIX_WEIGHTS:-true}"
132
HINT_REFERENCE="${HINT_REFERENCE:-true}"
133
HINT_PRESET="${HINT_PRESET:-balanced}"
134
135
local _m _lo _hi _xh _fb
136
case "$HINT_PRESET" in
137
balanced) _m=qsq; _lo=8; _hi=50; _xh=14; _fb=none ;;
138
sharp) _m=sss; _lo=6; _hi=50; _xh=14; _fb=none ;;
139
natural) _m=nnn; _lo=8; _hi=50; _xh=0; _fb=none ;;
140
light) _m=nnn; _lo=12; _hi=50; _xh=0; _fb=none ;;
141
hack) _m=qsq; _lo=6; _hi=50; _xh=10; _fb=latn ;;
142
custom) _m=qsq; _lo=8; _hi=50; _xh=14; _fb=none ;;
143
*)
144
echo "Error: unknown HINT_PRESET='$HINT_PRESET'." >&2
145
echo " Valid: balanced sharp natural light hack custom" >&2
146
exit 1 ;;
147
esac
148
# A preset never overrides a value the user set explicitly.
149
HINT_MODE="${HINT_MODE:-$_m}"
150
HINT_RANGE_MIN="${HINT_RANGE_MIN:-$_lo}"
151
HINT_RANGE_MAX="${HINT_RANGE_MAX:-$_hi}"
152
HINT_LIMIT="${HINT_LIMIT:-$HINT_RANGE_MAX}"
153
HINT_XHEIGHT="${HINT_XHEIGHT:-$_xh}"
154
HINT_FALLBACK_SCRIPT="${HINT_FALLBACK_SCRIPT:-$_fb}"
155
GASP_MODE="${GASP_MODE:-keep}"
156
HINT_WINCOMPAT="${HINT_WINCOMPAT:-false}"
157
HINT_TTFA_TABLE="${HINT_TTFA_TABLE:-false}"
158
159
if [[ ! "$HINT_MODE" =~ ^[nqs]{3}$ ]]; then
160
echo "Error: HINT_MODE='$HINT_MODE' must be 3 chars from n/q/s (e.g. qsq)." >&2
161
exit 1
162
fi
163
local _v
164
for _v in HINT_RANGE_MIN HINT_RANGE_MAX HINT_LIMIT HINT_XHEIGHT; do
165
if [[ ! "${!_v}" =~ ^[0-9]+$ ]]; then
166
echo "Error: $_v='${!_v}' must be a non-negative integer." >&2; exit 1
167
fi
168
done
169
if (( HINT_RANGE_MIN > HINT_RANGE_MAX )); then
170
echo "Error: HINT_RANGE_MIN ($HINT_RANGE_MIN) > HINT_RANGE_MAX ($HINT_RANGE_MAX)." >&2
171
exit 1
172
fi
173
case "$GASP_MODE" in
174
keep|sized|smooth|gridfit) ;;
175
*) echo "Error: GASP_MODE='$GASP_MODE' invalid (keep|sized|smooth|gridfit)." >&2; exit 1 ;;
176
esac
177
if [[ ! "$HINT_FALLBACK_SCRIPT" =~ ^[a-z0-9]{3,4}$ ]]; then
178
echo "Error: HINT_FALLBACK_SCRIPT='$HINT_FALLBACK_SCRIPT' must be a script tag (e.g. none, latn)." >&2
179
exit 1
180
fi
181
for _v in FIX_WEIGHTS HINT_REFERENCE HINT_WINCOMPAT HINT_TTFA_TABLE; do
182
case "${!_v}" in
183
true|false) ;;
184
*) echo "Error: $_v='${!_v}' must be true or false." >&2; exit 1 ;;
185
esac
186
done
187
}
188
189
prepare() {
190
# The checksum already pins the zip; this catches a PKGBUILD whose pkgver was
191
# bumped without looking at what Xiaomi actually shipped.
192
local _ver
193
_ver="$(python -c 'import sys
194
from fontTools.ttLib import TTFont
195
print(str(TTFont(sys.argv[1], lazy=True)["name"].getDebugName(5)).split()[-1])' \
196
"$srcdir/$_fontdir/MiSansLatin-Regular.ttf")"
197
if [[ "$_ver" != "$pkgver" ]]; then
198
echo "Error: fonts report version '$_ver' but pkgver is '$pkgver'." >&2
199
exit 1
200
fi
201
}
202
203
build() {
204
_resolve_options
205
206
echo "==> Options: FIX_WEIGHTS=$FIX_WEIGHTS reference=$HINT_REFERENCE preset=$HINT_PRESET" \
207
"stem=$HINT_MODE range=$HINT_RANGE_MIN-$HINT_RANGE_MAX limit=$HINT_LIMIT" \
208
"x-height=$HINT_XHEIGHT fallback=$HINT_FALLBACK_SCRIPT gasp=$GASP_MODE" \
209
"ttfa-table=$HINT_TTFA_TABLE${HINT_FAMILY_SUFFIX:+ suffix='$HINT_FAMILY_SUFFIX'}"
210
211
rm -rf "$srcdir/work" "$srcdir/hinted"
212
mkdir -p "$srcdir/work" "$srcdir/hinted"
213
cp "$srcdir/$_fontdir/"*.ttf "$srcdir/work/"
214
215
local _count
216
_count=$(find "$srcdir/work" -name '*.ttf' | wc -l)
217
if (( _count != 10 )); then
218
echo "Error: expected 10 static TTF weights, found $_count. Has the zip layout changed?" >&2
219
exit 1
220
fi
221
222
if [[ "$FIX_WEIGHTS" == true ]]; then
223
echo "==> Normalising usWeightClass..."
224
python "$srcdir/fix_weights.py" "$srcdir/work/"*.ttf
225
fi
226
227
local -a _ta_opts=(
228
--hinting-range-min="$HINT_RANGE_MIN"
229
--hinting-range-max="$HINT_RANGE_MAX"
230
--hinting-limit="$HINT_LIMIT"
231
--increase-x-height="$HINT_XHEIGHT"
232
--stem-width-mode="$HINT_MODE"
233
--fallback-script="$HINT_FALLBACK_SCRIPT"
234
--no-info
235
)
236
# Blue zones from the (unhinted, weight-fixed) Regular for every weight, so
237
# all ten share x-height and cap-height pixel rounding. The path is relative
238
# (ttfautohint runs inside work/) because a TTFA table records it verbatim.
239
if [[ "$HINT_REFERENCE" == true ]]; then
240
_ta_opts+=(--reference=MiSansLatin-Regular.ttf)
241
fi
242
if [[ "$HINT_TTFA_TABLE" == true ]]; then _ta_opts+=(--ttfa-table); fi
243
# Honour an explicit empty HINT_XSNAP_EXC (= no exceptions); omit if unset.
244
if [[ "${HINT_XSNAP_EXC+set}" == set ]]; then
245
_ta_opts+=(--x-height-snapping-exceptions="$HINT_XSNAP_EXC")
246
fi
247
if [[ "$HINT_WINCOMPAT" == true ]]; then _ta_opts+=(--windows-compatibility); fi
248
if [[ -n "${HINT_FAMILY_SUFFIX:-}" ]]; then _ta_opts+=(--family-suffix="$HINT_FAMILY_SUFFIX"); fi
249
250
echo "==> Hinting with ttfautohint..."
251
local _f
252
cd "$srcdir/work"
253
for _f in *.ttf; do
254
ttfautohint "${_ta_opts[@]}" "$_f" "$srcdir/hinted/$_f"
255
done
256
257
if [[ "$GASP_MODE" != keep ]]; then
258
echo "==> Applying gasp mode '$GASP_MODE'..."
259
python "$srcdir/set_gasp.py" "$GASP_MODE" "$srcdir/hinted/"*.ttf
260
fi
261
}
262
263
package() {
264
_resolve_options
265
266
install -Dm644 -t "$pkgdir/usr/share/fonts/$pkgname" "$srcdir/hinted/"*.ttf
267
install -Dm644 -t "$pkgdir/usr/share/licenses/$pkgname" "$srcdir/LICENSE.pdf"
268
269
# Opt-in rendering tweak (see the header): full bytecode hinting for this
270
# family only. Shipped in conf.avail and deliberately not enabled.
271
install -Dm644 /dev/stdin \
272
"$pkgdir/usr/share/fontconfig/conf.avail/80-misans-latin-hinted.conf" <<EOF
273
<?xml version="1.0" encoding="UTF-8"?>
274
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
275
<!-- Installed by $pkgname. Use the ttfautohint bytecode hints in these
276
fonts rather than FreeType's light autohinter. -->
277
<fontconfig>
278
<match target="font">
279
<test name="family" compare="eq">
280
<string>${_family}${HINT_FAMILY_SUFFIX:-}</string>
281
</test>
282
<edit name="hinting" mode="assign"><bool>true</bool></edit>
283
<edit name="autohint" mode="assign"><bool>false</bool></edit>
284
<edit name="hintstyle" mode="assign"><const>hintfull</const></edit>
285
</match>
286
</fontconfig>
287
EOF
288
}
289
Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-09-25 11:11:47 | Medium | 2 |
| 2026-09-25 09:14:12 | Low | 3 |
| 2026-09-25 09:11:17 | Medium | 2 |