ttf-misans-latin-hinted

MEDIUM
maintainer gaougalos 0 votes scanned 2026-09-25 11:11:47.608437
View on AUR
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>
2pkgname=ttf-misans-latin-hinted
3pkgver=4.007
4pkgrel=1
5pkgdesc="MiSans Latin (Latin, Greek, Cyrillic) by Xiaomi, autohinted with ttfautohint and with fontconfig-friendly weight classes"
6arch=(any)
7url="https://hyperos.mi.com/font/en/download/"
8license=(LicenseRef-MiSans)
9makedepends=(python python-fonttools ttfautohint)
10provides=(ttf-misans-latin)
11conflicts=(ttf-misans-latin)
12options=(!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.
17source=("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")
21sha256sums=('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
189prepare() {
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
194from fontTools.ttLib import TTFont
195print(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
203build() {
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
263package() {
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>
287EOF
288}
289

Scan history

Scanned at (UTC)SeverityRules
2026-09-25 11:11:47 Medium 2
2026-09-25 09:14:12 Low 3
2026-09-25 09:11:17 Medium 2

Report a package

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

0 / 4000
Your suggestion