Compare commits

...
4 Commits
Author SHA1 Message Date
rogeeandmultica-agent 0ce20e7517 HH-708: stream font fixture into probe container
Build and publish image / image (pull_request) Successful in 2m53s
Co-authored-by: multica-agent <github@multica.ai>
2026-08-26 21:21:14 +08:00
rogeeandmultica-agent dafe8a3968 HH-708: fail runtime font checks correctly
Co-authored-by: multica-agent <github@multica.ai>
2026-08-26 21:21:14 +08:00
rogeeandmultica-agent 308b6c82aa HH-708: verify runtime font fallbacks
Co-authored-by: multica-agent <github@multica.ai>
2026-08-26 21:21:14 +08:00
rogeeandmultica-agent cfa48ceb43 HH-708: align container fonts with fingerprint maps
Co-authored-by: multica-agent <github@multica.ai>
2026-08-26 21:20:44 +08:00
3 changed files with 114 additions and 0 deletions
+11
View File
@@ -25,8 +25,19 @@ LABEL org.opencontainers.image.revision="$OCI_REVISION" \
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
fonts-croscore \
fonts-crosextra-caladea \
fonts-crosextra-carlito \
fonts-dejavu-core \
fonts-dejavu-extra \
fonts-freefont-ttf \
fonts-liberation \
fonts-liberation-sans-narrow \
fonts-noto-core \
fonts-noto-cjk \
fonts-noto-color-emoji \
fonts-ubuntu \
fonts-urw-base35 \
libasound2t64 \
libatk-bridge2.0-0t64 \
libatk1.0-0t64 \
+56
View File
@@ -30,3 +30,59 @@ DOCKER_LOG="$docker_log" OCI_REVISION=test PUSH=true PATH="$tmpdir:$PATH" \
./scripts/build.sh registry.example/fingerprint-chromium > "$tmpdir/output"
test "$(cat "$docker_log")" = "manifest inspect registry.example/fingerprint-chromium:1.2.3.4"
grep -q 'skipping build and push' "$tmpdir/output"
font_packages=(
fonts-croscore
fonts-crosextra-caladea
fonts-crosextra-carlito
fonts-dejavu-core
fonts-dejavu-extra
fonts-freefont-ttf
fonts-liberation
fonts-liberation-sans-narrow
fonts-noto-cjk
fonts-noto-color-emoji
fonts-noto-core
fonts-ubuntu
fonts-urw-base35
)
version="$(curl --fail --location --retry 3 --silent --show-error \
https://api.github.com/repos/adryfish/fingerprint-chromium/releases/latest \
| jq -er '.tag_name | select(test("^[0-9]+(\\.[0-9]+){3}$"))')"
image="fingerprint-chromium-test:$version"
CHROME_VERSION="$version" ./scripts/build.sh fingerprint-chromium-test
docker run --rm --entrypoint sh "$image" -c '
for package do
test "$(dpkg-query -W -f="\${Status}" "$package" 2>/dev/null)" = "install ok installed" || exit 1
done
' sh "${font_packages[@]}"
docker run --rm --entrypoint sh "$image" -c '
for font do
fc-match --format "%{family}\n" "$font" | grep -Fq "$font" || exit 1
done
' sh Arimo Tinos Cousine Caladea Carlito \
'Noto Sans CJK JP' 'Noto Sans CJK SC' 'Noto Sans CJK TC' \
'Noto Serif CJK JP' 'Noto Serif CJK SC' 'Noto Serif CJK TC'
probe() {
local platform="$1" threshold="$2" output count
output="$(docker run --rm -i --entrypoint sh "$image" -c '
cat >/tmp/font-probe.html
exec /opt/chromium/chrome --no-sandbox --headless=new --disable-gpu --disable-dev-shm-usage \
--fingerprint=1000 --fingerprint-platform="$1" \
--dump-dom "file:///tmp/font-probe.html#$1"
' sh "$platform" <tests/font-probe.html 2>/dev/null)"
count="$(sed -n 's/.*data-count="\([0-9][0-9]*\)".*/\1/p' <<<"$output")"
[[ "$count" =~ ^[0-9]+$ && "$count" -ge "$threshold" ]] || {
printf '%s font probe: expected >= %s, got %s\n' "$platform" "$threshold" "${count:-none}" >&2
return 1
}
printf '%s font probe: %s\n' "$platform" "$count"
}
probe windows 22
probe macos 24
probe linux 27
+47
View File
@@ -0,0 +1,47 @@
<!doctype html>
<output id="result"></output>
<script>
const fonts = {
windows: [
'Arial Black', 'Bahnschrift', 'Cambria', 'Candara', 'Cascadia Code',
'Comic Sans MS', 'Consolas', 'Constantia', 'Corbel', 'Ebrima',
'Franklin Gothic Medium', 'Gabriola', 'Gadugi', 'Georgia', 'Impact',
'Ink Free', 'Javanese Text', 'Lucida Console', 'Malgun Gothic',
'Microsoft YaHei', 'Palatino Linotype', 'Segoe UI', 'SimSun', 'Tahoma',
'Trebuchet MS', 'Verdana', 'Webdings', 'Wingdings', 'Yu Gothic'
],
macos: [
'Academy Engraved LET', 'American Typewriter', 'Andale Mono',
'Apple Chancery', 'Apple Color Emoji', 'Apple Symbols', 'Avenir',
'Avenir Next', 'Baskerville', 'Big Caslon', 'Bradley Hand', 'Chalkboard',
'Chalkduster', 'Charter', 'Cochin', 'Copperplate', 'Didot', 'Futura',
'Geneva', 'Gill Sans', 'Helvetica Neue', 'Herculanum', 'Hoefler Text',
'Lucida Grande', 'Marker Felt', 'Menlo', 'Monaco', 'Optima', 'Papyrus',
'PingFang SC', 'Rockwell', 'SF Pro Display', 'Skia', 'Snell Roundhand',
'Songti SC', 'Times', 'Trattatello', 'Zapfino'
],
linux: [
'Arimo', 'Caladea', 'Carlito', 'Cousine', 'DejaVu Math TeX Gyre',
'DejaVu Sans', 'DejaVu Sans Mono', 'DejaVu Serif', 'FreeMono', 'FreeSans',
'FreeSerif', 'Liberation Mono', 'Liberation Sans', 'Liberation Sans Narrow',
'Liberation Serif', 'Nimbus Mono PS', 'Nimbus Roman', 'Nimbus Sans',
'Nimbus Sans Narrow', 'Noto Color Emoji', 'Noto Sans', 'Noto Sans CJK JP',
'Noto Sans CJK SC', 'Noto Serif', 'Noto Serif CJK JP', 'Noto Serif CJK SC',
'Tinos', 'Ubuntu', 'Ubuntu Mono'
]
};
const platform = location.hash.slice(1);
const sample = 'mmmmmmmmmmlli';
const bases = ['monospace', 'sans-serif', 'serif'];
const context = document.createElement('canvas').getContext('2d');
const widths = bases.map(base => {
context.font = `72px ${base}`;
return context.measureText(sample).width;
});
const detected = fonts[platform].filter(font => bases.some((base, index) => {
context.font = `72px "${font}",${base}`;
return context.measureText(sample).width !== widths[index];
}));
result.dataset.count = detected.length;
result.textContent = `${platform}:${detected.join('|')}`;
</script>