# BST-TIMEOUT: 600 # 81 cases, SEVEN of them runs of the 7.8 MB # # data/freetype-probe. MEASURED at elapsed=40/42/42/41s on # # four independent clean boots (2026-08-25, local runner), # # read off the ==BST-SUITE elapsed= line and NOT estimated # # -- which is what BRINTOS-1449 had to correct when it # # shipped a bound taken from a guess at 48x the truth. # # The bound is 99-ttf-gentium's, 99-ttf-inconsolata's and # # 99-ttf-bitstream-vera's, for the reason vera's header # # gives: all four drive the SAME probe binary, and a suite # # whose cost is dominated by one binary should not claim a # # different bound for it. Those three measured 37s against # # this one's 41s; the extra 4s is three more probe runs over # # smaller files. 600 is ~15x the measurement, so a hung # # suite costs ten minutes of a sweep rather than thirty -- # # which is not academic here, see the consumer block. # # ttf-droid 0.1+git -- the Droid family, Android's system faces, taken by the # recipe straight from the platform_frameworks_base git tree. # meta-openembedded meta-oe/recipes-graphics/ttf-fonts/ttf-droid_git.bb. # # ============================================================================ # THIS IMAGE INSTALLS THREE OF THE RECIPE'S FIVE PACKAGES, AND THAT IS THE # PORT'S ONE DECISION. # ============================================================================ # # ttf.inc's do_install copies every *.tt[cf] under ${S}; the recipe's # do_install:append then removes eight of the seventeen, leaving NINE faces. # `PACKAGES` is an ASSIGNMENT naming five font packages -- so there is no # `ttf-droid` package at all, and no `ttf-droid-doc` either -- and this image # installs three of the five: # # ttf-droid-sans DroidSans.ttf 190776, DroidSans-Bold.ttf 194488 # ttf-droid-sans-mono DroidSansMono.ttf 119380 # ttf-droid-serif DroidSerif-{Bold 185228, BoldItalic 190304, # Italic 177560, Regular 172916}.ttf # # HELD OUT, DELIBERATELY: # # ttf-droid-sans-fallback DroidSansFallback.ttf 3,725,920 # ttf-droid-sans-japanese DroidSansJapanese.ttf 1,173,140 # # WHY. File-backed mmap on this arm is REFUSED above a mapping-length threshold, # and the consumer does not receive a failed mmap and fall back -- it PARKS, # beyond the reach of both SIGTERM and SIGKILL, taking the guest and every suite # behind it in the same boot. BRINTOS-1450 measured that on ttf-dejavu and # bracketed the threshold on this image between ~66 kB and 577,708 bytes; the # kernel logs `hwjs-mmap ... file-backed mmap REFUSED (pread64 population # failed) ... errno 517` on the first face over it. That ticket is HELD, not # landed, because DejaVu's over-threshold face sits inside its core family and # cannot be detached. # # Droid's two do detach -- they are whole sub-packages -- which is what makes # this port landable where that one is not. And the seven that remain are not # merely under the threshold, they are under the whole image's existing working # set: the largest of them (194,488) is SMALLER than the smallest of the twelve # Liberation faces this image already scans on every fc-cache (281,536), whose # range runs to 415,816. So this port adds no new maximum, no new failure mode, # and nothing to the band #165 is about. The two held out are 2.0x and 6.4x the # 577,708 datapoint and 2.8x and 9.0x the image's current largest face. # # held-out-DroidSansFallback.ttf and held-out-DroidSansJapanese.ttf assert the # decision from the file layer, so an IMAGE_INSTALL that added either package # back produces a NAMED red on the line that caused it, rather than a whole # suite -- and every suite after it in the same boot -- falling silent. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 remove -- hold # ttf-droid-sans-fallback and ttf-droid-sans-japanese out of IMAGE_INSTALL; both # go back in when the mmap population path tolerates a mapping this size. # # ============================================================================ # # NO -doc PACKAGE, AND NO LICENCE FILE ON THE IMAGE. `PACKAGES` drops ${PN} and # ${PN}-doc, and do_install only ever copies *.tt[cf] -- so README.txt, NOTICE # and MODULE_LICENSE_APACHE2 never leave ${S} and no package could carry them. # That is the recipe's behaviour, not this port's choice, and requirement 3 is # every file the RECIPE DECLARES, all of which ship. pkg-no-doc-package asserts # the absence, because "the -doc line was forgotten" and "there is no -doc # package by design" look identical from the file layer alone. # # FOUR LAYERS, AND A RED IN AN EARLIER ONE LOCALISES A RED IN A LATER ONE: # # file-*, ttf-*, the payload arrived intact -- size, bytes, mode, type -- # held-out-*, and the directory this port shares was not disturbed. # cotenant-* No font machinery involved at all. # pkg-*, postinst-* the three packages the image really installs, the # fontcache class's RDEPENDS, and the deferred scriptlet. # ft-* the image's OWN freetype PARSES all seven faces through # its TrueType driver and agrees about num_faces, # num_glyphs, units_per_EM, family and style. This is the # layer the ticket asks for by name. # fcq-*, fc-* fontconfig's independent parse (fc-scan, against a native # x86-64 control), then discovery and matching THROUGH THE # CACHE, which is a different path again. # # THE DIRECTORY IS NOW SHARED THREE WAYS. /usr/share/fonts/truetype was created # by ttf-inconsolata, joined by ttf-gentium, and joined again here. Both # neighbours already scope their own "no-extras" cases by basename # (`^Inconsolata`, `^Gen.*\.ttf$`), so NEITHER had to be amended for this port -- # which is the payoff of the repair ttf-gentium made to ttf-inconsolata one # ticket ago. Their `cotenant-ttfdir` cases count /usr/share/fonts/ttf, which # this port never writes to, so those are unaffected too. This suite asserts # both neighbours' payloads from its side, so a disagreement stays visible. # # THIS PORT TAKES OVER NO GENERIC, AND THAT IS ASSERTED RATHER THAN ASSUMED -- # WHICH MATTERS MORE HERE THAN IT DID FOR GENTIUM. This is the first port to add # a MONOSPACE face since ttf-inconsolata took `monospace` from Liberation Mono, # and DroidSansMono.ttf really is one (fc-scan derives spacing=100 from its # advance widths -- fcq-spacing-mono). It cannot displace Inconsolata anyway, # because no Droid family appears on ANY generic's preference list in # fontconfig's shipped 60-latin.conf -- checked for serif, sans-serif, # monospace, fantasy, cursive and system-ui. This port adds a sans, a serif AND # a mono, so all three generics are asserted unchanged, where 99-ttf-gentium # needed only one. # # THE fontcache POSTINST IS THE THING THE TICKET SAYS TO CHECK RATHER THAN # ASSUME, AND IT IS CHECKED IN THE ONE FORM THAT IS BOOT-MODE INDEPENDENT. # fontcache.bbclass appends fontconfig-utils to RDEPENDS for every FONT_PACKAGES # entry -- read back off the target here, not off the recipe -- and registers an # update_font_cache intercept that runs fc-cache under qemu-user. There is no # wasm32 qemu-user, so it is deferred to run-postinsts at first boot, which # /etc/inittab does run (BRINTOS-53). Whether it HAS run depends on the pid 1 the # harness booted -- the local runner goes straight to a shell -- so asserting the # configured state would report the runner's choice as a package red. What is # asserted instead is boot-mode independent and is the actual risk the ticket # names: the scriptlet is on the image for all three packages, it calls fc-cache, # and fc-cache is present, so the deferred run cannot fail for want of the tool. . "$BST_LIB" S=ttf-droid # THE CANARY, which asserts nothing about ttf-droid. # # A suite's FIRST BST result line is lost between the guest's printf and the # host's read -- per-suite, deterministic, and NOT a defect in the host tool # (BRINTOS-1149 established that and filed it as linux-in-the-browser#177). # The harness reports the deficit but computes its pass count as total-minus- # failures, so THE DROPPED LINE IS COUNTED AS A PASS. A nothing-case therefore # stands in that position and the eaten line costs nothing; every real case below # is still counted. It sits ahead of the `require` guards deliberately, because a # `require` that skips would emit its skip as the first line and be eaten too. # # Remove this case when linux-in-the-browser#177 is fixed. bst_ok $S/suite-canary D=$BST_DATA REF=$D/ttf-droid-manifest.txt FACTS=$D/ttf-droid-fontfacts.txt FACES=$D/ttf-droid-fcfaces.txt PROBE_SRC=$D/freetype-probe TTFDIR=/usr/share/fonts/truetype COTDIR=/usr/share/fonts/ttf PI_SANS=/var/lib/dpkg/info/ttf-droid-sans.postinst PI_MONO=/var/lib/dpkg/info/ttf-droid-sans-mono.postinst PI_SERIF=/var/lib/dpkg/info/ttf-droid-serif.postinst tmp=${TMPDIR:-/tmp} W=$tmp/bst-ttf-droid.$$ require gawk $S/gawk-present require sha256sum $S/sha256sum-present require find $S/find-present # fc-scan runs in the payload block, ahead of the consumer block's own check, so # its absence is guarded here. It is NOT a `require`: fontconfig-utils is a hard # Depends of all three packages, so an absent fc-scan is a defect in the port # rather than a legitimately absent tool, and a skip would report it green. if [ -x /usr/bin/fc-scan ]; then bst_ok $S/fc-scan-present else bst_notok $S/fc-scan-present "fontconfig-utils is a Depends of ttf-droid-sans but /usr/bin/fc-scan is absent"; fi if [ ! -f "$REF" ] || [ ! -f "$FACTS" ] || [ ! -f "$FACES" ]; then bst_notok $S/ref-present "the reference data did not ship: $REF / $FACTS / $FACES" exit 0 fi bst_ok $S/ref-present # ------------------------------------------------------------- payload shape # One find over the shared font directory AND the other font directory, so every # count is a measurement from the same pass. %y catches a symlink where a regular # file is meant and %m the mode -- neither of which `test -f` can see. There are # no doc directories to walk: this recipe installs none (see the header). find "$TTFDIR" "$COTDIR" \ -maxdepth 1 -printf '%p %y %s %m %l\n' 2>/dev/null | LC_ALL=C sort > "$W.inv" # One sha256sum over all seven payload files. Named explicitly rather than # globbed: the manifest is the list, and a glob over a SHARED directory would # digest Inconsolata and the four Gentium faces too and report them as # unexpected entries. sha256sum "$TTFDIR"/DroidSans.ttf "$TTFDIR"/DroidSans-Bold.ttf \ "$TTFDIR"/DroidSansMono.ttf "$TTFDIR"/DroidSerif-Bold.ttf \ "$TTFDIR"/DroidSerif-BoldItalic.ttf "$TTFDIR"/DroidSerif-Italic.ttf \ "$TTFDIR"/DroidSerif-Regular.ttf > "$W.sums" 2>&1 # One fc-scan over all seven installed faces. fontconfig opens them through # FreeType, so this is a second, independent parse -- and it reads fields # freetype's own API does not name (the PostScript name, the derived # slant/weight/spacing, the format, the charset). It reads the FILES, not the # cache, so it is independent of the fc-cache in the consumer block below. LC_ALL=C fc-scan --format '%{file|basename}|%{family}|%{style}|%{slant}|%{weight}|%{spacing}|%{postscriptname}|%{fontformat}|%{scalable}|%{outline}|%{charset}\n' \ "$TTFDIR"/DroidSans.ttf "$TTFDIR"/DroidSans-Bold.ttf \ "$TTFDIR"/DroidSansMono.ttf "$TTFDIR"/DroidSerif-Bold.ttf \ "$TTFDIR"/DroidSerif-BoldItalic.ttf "$TTFDIR"/DroidSerif-Italic.ttf \ "$TTFDIR"/DroidSerif-Regular.ttf 2>/dev/null | LC_ALL=C sort > "$W.scan" LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" \ -v FACES="$FACES" -v SCAN="$W.scan" \ -f "$D/ttf-droid-verify.awk" "$REF" "$W.sums" "$W.inv" "$FACES" "$W.scan" # ---------------------------------------------------- the packaging on target # THE PACKAGE DATABASE IS THE ONLY PLACE THE SPLIT IS VISIBLE ON TARGET. The # file-* cases would look identical if do_install had written all seven files # into one package, so they cannot say that ttf-droid-serif is a real package the # image installs rather than an IMAGE_INSTALL line that resolved to nothing. One # sed pulls every stanza; the loop is shell builtins. The stanzas are read from a # tmpfs copy, never redirected from the rootfs (brintos/linux#73). # # THE ANCHORS ARE EXACT ON PURPOSE. `ttf-droid-sans` is a PREFIX of # `ttf-droid-sans-mono`, `-fallback` and `-japanese`, so an unanchored match # would report the mono package's stanza as the sans package's and make # pkg-no-fallback-package unfalsifiable. sed -n '/^Package: ttf-droid$/,/^$/p; /^Package: ttf-droid-doc$/,/^$/p; /^Package: ttf-droid-sans$/,/^$/p; /^Package: ttf-droid-sans-mono$/,/^$/p; /^Package: ttf-droid-serif$/,/^$/p; /^Package: ttf-droid-sans-fallback$/,/^$/p; /^Package: ttf-droid-sans-japanese$/,/^$/p' \ /var/lib/dpkg/status > "$W.st" 2>/dev/null _pkg=""; _sans=0; _mono=0; _serif=0; _bare=0; _doc=0; _fb=0; _jp=0 _asans=0; _amono=0; _aserif=0; _dsans=0; _dmono=0; _dserif=0 while IFS= read -r l; do case "$l" in "Package: ttf-droid") _pkg=bare; _bare=1 ;; "Package: ttf-droid-doc") _pkg=doc; _doc=1 ;; "Package: ttf-droid-sans") _pkg=sans; _sans=1 ;; "Package: ttf-droid-sans-mono") _pkg=mono; _mono=1 ;; "Package: ttf-droid-serif") _pkg=serif; _serif=1 ;; "Package: ttf-droid-sans-fallback") _pkg=fb; _fb=1 ;; "Package: ttf-droid-sans-japanese") _pkg=jp; _jp=1 ;; "Architecture: all") [ "$_pkg" = sans ] && _asans=1 [ "$_pkg" = mono ] && _amono=1 [ "$_pkg" = serif ] && _aserif=1 ;; "Depends: "*) case "$l" in *fontconfig-utils*) [ "$_pkg" = sans ] && _dsans=1 [ "$_pkg" = mono ] && _dmono=1 [ "$_pkg" = serif ] && _dserif=1 ;; esac ;; esac done < "$W.st" # THE THREE PACKAGES THIS IMAGE INSTALLS. Each is a third of the port: a dropped # IMAGE_INSTALL line would take that family's file-* and ft-* cases with it, and # these cases say the cause is a missing PACKAGE rather than missing files. if [ "$_sans" -eq 1 ]; then bst_ok $S/pkg-sans-known else bst_notok $S/pkg-sans-known "dpkg does not know the package ttf-droid-sans"; fi if [ "$_mono" -eq 1 ]; then bst_ok $S/pkg-mono-known else bst_notok $S/pkg-mono-known "dpkg does not know the package ttf-droid-sans-mono"; fi if [ "$_serif" -eq 1 ]; then bst_ok $S/pkg-serif-known else bst_notok $S/pkg-serif-known "dpkg does not know the package ttf-droid-serif"; fi # THERE IS NO ttf-droid PACKAGE, AND ITS ABSENCE IS THE RECIPE. `PACKAGES` is an # assignment that omits ${PN} entirely, so `IMAGE_INSTALL += "ttf-droid"` would # not resolve. This case names that, because a future recipe revision restoring # the default PACKAGES would change what the image must ask for. if [ "$_bare" -eq 0 ]; then bst_ok $S/pkg-no-bare-package else bst_notok $S/pkg-no-bare-package "dpkg knows a ttf-droid package -- PACKAGES no longer omits \${PN}"; fi if [ "$_doc" -eq 0 ]; then bst_ok $S/pkg-no-doc-package else bst_notok $S/pkg-no-doc-package "dpkg knows a ttf-droid-doc package -- PACKAGES no longer omits \${PN}-doc"; fi # THE TWO HELD OUT, ASSERTED FROM THE PACKAGE LAYER AS WELL AS THE FILE LAYER. # held-out-* in the verify awk says the FILES are absent; these say the PACKAGES # are, which is the layer an IMAGE_INSTALL edit actually moves. Both are needed: # a package installed with its files somehow missing would pass one and not the # other, and that difference is the whole diagnosis. if [ "$_fb" -eq 0 ]; then bst_ok $S/pkg-no-fallback-package else bst_notok $S/pkg-no-fallback-package "ttf-droid-sans-fallback is installed -- 3725920 bytes, linux-in-the-browser#165 will wedge fc-cache"; fi if [ "$_jp" -eq 0 ]; then bst_ok $S/pkg-no-japanese-package else bst_notok $S/pkg-no-japanese-package "ttf-droid-sans-japanese is installed -- 1173140 bytes, linux-in-the-browser#165 will wedge fc-cache"; fi # `allarch` reached the package metadata, which is what makes the byte-identity # reference in the manifest a statement about this build rather than a # coincidence. Asserted for all three: they are built by one recipe but packaged # separately, and a class that reached one need not have reached the others. if [ "$_asans" -eq 1 ]; then bst_ok $S/pkg-sans-arch-all else bst_notok $S/pkg-sans-arch-all "ttf-droid-sans is not Architecture: all"; fi if [ "$_amono" -eq 1 ]; then bst_ok $S/pkg-mono-arch-all else bst_notok $S/pkg-mono-arch-all "ttf-droid-sans-mono is not Architecture: all"; fi if [ "$_aserif" -eq 1 ]; then bst_ok $S/pkg-serif-arch-all else bst_notok $S/pkg-serif-arch-all "ttf-droid-serif is not Architecture: all"; fi # THE fontcache CLASS'S RDEPENDS, READ BACK OFF THE TARGET. The recipe declares # no runtime dependency at all and ttf.inc sets INHIBIT_DEFAULT_DEPS -- # fontcache.bbclass appends fontconfig-utils to each FONT_PACKAGES entry -- so # these are the cases that say the class did its half for all three packages and # that the dependency resolved against a package this image already carried # (fontconfig-utils has been here since BRINTOS-1032). if [ "$_dsans" -eq 1 ]; then bst_ok $S/pkg-sans-depends-fontconfig else bst_notok $S/pkg-sans-depends-fontconfig "ttf-droid-sans does not Depend on fontconfig-utils"; fi if [ "$_dmono" -eq 1 ]; then bst_ok $S/pkg-mono-depends-fontconfig else bst_notok $S/pkg-mono-depends-fontconfig "ttf-droid-sans-mono does not Depend on fontconfig-utils"; fi if [ "$_dserif" -eq 1 ]; then bst_ok $S/pkg-serif-depends-fontconfig else bst_notok $S/pkg-serif-depends-fontconfig "ttf-droid-serif does not Depend on fontconfig-utils"; fi # ------------------------------------------------- the deferred fontcache hook # ALL THREE packages are in FONT_PACKAGES, so all three get a scriptlet. # Asserted separately for the same reason as the RDEPENDS above. if [ -f "$PI_SANS" ]; then bst_ok $S/postinst-sans-present else bst_notok $S/postinst-sans-present "$PI_SANS is absent -- the fontcache postinst did not reach the image"; fi if [ -f "$PI_MONO" ]; then bst_ok $S/postinst-mono-present else bst_notok $S/postinst-mono-present "$PI_MONO is absent -- the fontcache postinst did not reach the image"; fi if [ -f "$PI_SERIF" ]; then bst_ok $S/postinst-serif-present else bst_notok $S/postinst-serif-present "$PI_SERIF is absent -- the fontcache postinst did not reach the image"; fi # They call fc-cache on the branch run-postinsts takes ($D unset at first boot). check_out $S/postinst-sans-runs-fc-cache "fc-cache" cat "$PI_SANS" check_out $S/postinst-mono-runs-fc-cache "fc-cache" cat "$PI_MONO" check_out $S/postinst-serif-runs-fc-cache "fc-cache" cat "$PI_SERIF" # ...and the tool that branch needs is present, so the deferred run cannot fail # for want of it. This is the ticket's stated risk, and it is a shell builtin. if [ -x /usr/bin/fc-cache ]; then bst_ok $S/fc-cache-present else bst_notok $S/fc-cache-present "fontconfig-utils is a Depends of ttf-droid-sans but /usr/bin/fc-cache is absent"; fi # ------------------------------------------------------ freetype parses them # The rootfs is read-only at browser runtime and data/ arrives 0644, so the probe # is copied to /tmp (mode=1777 tmpfs, no noexec) and the bit is set there. Never # `test -x` the shipped payload: that passes against a hand-placed copy and fails # against every image that ever built the package. if [ ! -f "$PROBE_SRC" ]; then bst_notok $S/probe-present "$PROBE_SRC did not ship" rm -f "$W.inv" "$W.sums" "$W.scan" "$W.st" 2>/dev/null exit 0 fi bst_ok $S/probe-present probe=$tmp/bst-ttfdroid-probe.$$ if cp "$PROBE_SRC" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then bst_ok $S/probe-stage else bst_notok $S/probe-stage "cannot stage $PROBE_SRC" rm -f "$probe" "$W.inv" "$W.sums" "$W.scan" "$W.st" 2>/dev/null exit 0 fi # The face list comes from the FACTS file rather than from a glob, so a face the # manifest knows about but the image lost is reported as "the probe was never run # over X" instead of silently dropping out of the loop. A glob would additionally # pick up Inconsolata.ttf and the four Gen*.ttf out of this shared directory. # # NO TRAILING == ON THE FENCE. `==FONT DroidSans.ttf==` puts "DroidSans.ttf==" in # awk's $2, which matches no key in the facts table, and every per-face case then # reds with "the probe was never run over ..." while ft-ran stays green. : > "$W.ft" _faces=$(LC_ALL=C gawk '!/^#/ && NF >= 5 { print $1 }' "$FACTS") for _f in $_faces; do printf '==FONT %s\n' "$_f" >> "$W.ft" "$probe" "$TTFDIR/$_f" >> "$W.ft" 2>&1 _rc=$? printf '==RC %s %d\n' "$_f" "$_rc" >> "$W.ft" done rm -f "$probe" 2>/dev/null LC_ALL=C gawk -v FACTS="$FACTS" -v FT="$W.ft" \ -f "$D/ttf-droid-ftverify.awk" "$FACTS" "$W.ft" # --------------------------------------------------------- the consumer block # # EVERYTHING BELOW THIS LINE CAN COST THE GUEST, AND THAT IS WHY IT IS LAST. # fc-cache mmaps each face it walks, and file-backed mmap on this arm is REFUSED # above a mapping-length threshold (linux-in-the-browser#165) -- and the consumer # does not get a failed mmap and fall back, it PARKS, beyond the reach of both # SIGTERM and SIGKILL, taking the guest and every suite behind it in the same # boot. Ordering this block last is the only thing that actually protects the # evidence: every case above has already been emitted by the time the first # mapping happens. # # THIS PORT'S SEVEN FACES SIT BELOW THE IMAGE'S ENTIRE EXISTING WORKING SET, # which is the honest statement of its risk and is a stronger one than any # earlier font port could make. #165's bracket on this image is ~66 kB to # 577,708 bytes; these are 119,380 to 194,488, and the twelve Liberation faces # already walked by every fc-cache run 281,536 to 415,816 -- every one of them # LARGER than anything this port adds. So this package cannot introduce a new # failure mode or a new maximum; it adds seven mappings strictly below a band the # image already lives in. The two faces that would NOT have been are held out, # and asserted absent above. # # THE BOUND IS BEST-EFFORT AND IS NOT WHAT MAKES THIS SAFE. #165 measured that a # parked fc-cache survives SIGKILL, so `timeout` cannot reclaim it and will # itself hang when the park is the unkillable kind. It is here for the case where # the call merely runs long, and the ordering above is here for the case where it # does not come back at all. Recorded rather than dressed up, because a bound # that looks protective and is not is worse than none. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 remove -- bound the fc-cache call # and order the consumer block last; both go when the mmap population path # tolerates a parking read. # `fc-cache`, NOT `fc-cache -f`, SINCE BRINTOS-1725. The -f rebuilt every # directory whether or not its cache was valid, which means mapping every face on # the image; a file-backed mapping above roughly 578 kB is REFUSED over the cloud # FUSE bridge and the caller PARKS, beyond SIGKILL (linux-in-the-browser#165, # bracketed by BRINTOS-1450). Before ttf-pt-sans the image's largest face was # Ubuntu-L.ttf at 415,552 bytes, under the bracket, and this call was harmless; # that port adds four faces above it, the largest 584,812. # # THIS SUITE WAS NOT ITSELF MEASURED PARKING, and that is worth stating rather # than implying. Four of its peers were, on the ported image, each reaching its # consumer block and dying at the 600 s bound -- 99-cantarell-fonts at 43 of 50, # 99-ttf-gentium at 47 of 55, 99-source-code-pro-fonts at 86 of 96 and # 99-liberation-fonts at 24 of 25 -- against 50/50 and 55/55 for the first two on # the same base pin without the port. This suite makes the same call over the # same font set, so it is amended by the same rule. Without -f, fc-cache rebuilds # only what is stale, and nothing is: /var/cache/fontconfig ships populated, and # `fc-cache` returns 0 in 3 s on that image where `timeout -k 5 150 fc-cache -f` # never returned. The case still asserts what it always did. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 revisit -- drop -f so only a stale # cache is rebuilt; it goes back in when the mmap population path tolerates a # parking read. # BST-TIMEOUT-OK: fc-cache walks the font dirs and exits; -k 5 90 is belt-and-braces. timeout -k 5 90 fc-cache > "$W.cache" 2>&1 _rc=$? if [ "$_rc" -eq 0 ]; then bst_ok $S/fc-cache-rc elif [ "$_rc" -eq 124 ] || [ "$_rc" -eq 137 ]; then bst_notok $S/fc-cache-rc "fc-cache did not return within 90s -- linux-in-the-browser#165 (mmap population parked)" else bst_notok $S/fc-cache-rc "fc-cache exited $_rc: $(_bst_1line "$(cat "$W.cache")")"; fi # One fc-list for the whole consumer read; the parsing below is shell builtins. fc-list : file family > "$W.list" 2>&1 # THE FACES ARE DISCOVERABLE, not merely present on disk. A cache that serialised # wrongly, or a FreeType that refused the outlines, shows up here while every # file-* case above stays green -- which is the split that says where to look. for _pair in "DroidSans.ttf:Droid Sans" "DroidSans-Bold.ttf:Droid Sans" \ "DroidSansMono.ttf:Droid Sans Mono" \ "DroidSerif-Bold.ttf:Droid Serif" "DroidSerif-BoldItalic.ttf:Droid Serif" \ "DroidSerif-Italic.ttf:Droid Serif" "DroidSerif-Regular.ttf:Droid Serif"; do _bn=${_pair%%:*}; _wantfam=${_pair#*:} _seen=0; _fam="" while IFS= read -r l; do case "$l" in "$TTFDIR/$_bn":*) ;; *) continue ;; esac _seen=$((_seen+1)) _fam=${l#*: } done < "$W.list" if [ "$_seen" -eq 1 ] && [ "$_fam" = "$_wantfam" ]; then bst_ok "$S/fc-list-$_bn" else bst_notok "$S/fc-list-$_bn" "fc-list reports $_seen entries for $TTFDIR/$_bn family '$_fam', want 1 of '$_wantfam'" fi done # ...AND EACH FAMILY RESOLVES BACK TO OUR REGULAR FACE. fc-match never fails -- # it always returns some face -- so this is real only because 34 other faces are # installed alongside: a family name that did not reach the cache falls through # to Liberation, which is exactly what 99-terminus-font's first on-target run # reported for its own family. for _pair in "Droid Sans:DroidSans.ttf" "Droid Sans Mono:DroidSansMono.ttf" \ "Droid Serif:DroidSerif-Regular.ttf"; do _fam=${_pair%%:*}; _wantf=${_pair#*:} _out=$(fc-match --format '%{file} %{family}\n' "$_fam" 2>&1) case "$_out" in "$TTFDIR/$_wantf $_fam") bst_ok "$S/fc-match-$_wantf" ;; *) bst_notok "$S/fc-match-$_wantf" "fc-match $_fam => '$(_bst_1line "$_out")', want '$TTFDIR/$_wantf $_fam'" ;; esac done # THE THREE GENERICS THIS PORT DOES **NOT** TAKE OVER, ASSERTED FROM THIS SIDE. # This port adds a sans, a serif AND a monospace face, so it is the first that # could plausibly have moved any of the three -- and the mono one is the real # risk, because installing ttf-inconsolata is exactly what moved `monospace` # off Liberation Mono two tickets ago. No Droid family is on 60-latin.conf's # preference list for serif, sans-serif, monospace, fantasy, cursive or # system-ui, so none of them moves. These are NOT restatements of the # fc-match-Droid* cases above: those would stay green if installing these # families had ALSO displaced a generic. 99-liberation-fonts and # 99-ttf-inconsolata assert the same three facts from the other side, so a # disagreement between the suites is visible rather than silent. # monospace READS `Source Code Pro` SINCE BRINTOS-1455, NOT `Inconsolata`, AND # THAT IS STILL WHAT THIS CASE IS FOR. The case asserts that THIS port did not # move the generic, which is unchanged and is why it keeps its -unchanged name; # what moved is the value it must be compared against. source-code-pro-fonts # ships a fontconfig fragment whose takes monospace outright (see # 99-source-code-pro-fonts), so leaving `Inconsolata` here would have reported # that port's intended behaviour as a red in this one. # THREE OF THESE MOVED FOR BRINTOS-1729 AND THE REASONS ARE NOT THE SAME. # ttf-tlwg ships ten fragments into /etc/fonts/conf.d at 64, and # PREPENDS ahead of the generic while 30-liberation-aliases.conf's # only APPENDS behind it -- so Kinnari takes `serif` and Waree takes # `sans-serif` by CONFIGURATION. `monospace` is untouched, because # source-code-pro-fonts' own loads at 44, ahead of these. # # THE UNBOUND GENERICS MOVED FOR A DIFFERENT REASON AND IT IS WORTH KEEPING # STRAIGHT: `system-ui`, `cursive` and `fantasy` have NO preference list in this # fontconfig at all, so they fall to whichever face sorts first across the WHOLE # image. 58 new faces changed that answer to Waree without any fragment naming # them. That is not ttf-tlwg taking a generic; it is what an unbound generic # does on every neighbouring font port, which is why 99-ttf-mplus declines to # pin them and 99-ttf-abyssinica (BRINTOS-1728) says the same. # # THE CASES ARE AMENDED, NOT DELETED, as they were for BRINTOS-1455 and # BRINTOS-1729's own two: what they are worth is that the generic resolves to # the family the configuration actually selects, and they still say that. for _pair in "sans-serif:Waree" "serif:Kinnari" "monospace:Source Code Pro"; do _gen=${_pair%%:*}; _want=${_pair#*:} _out=$(fc-match --format '%{family}\n' "$_gen" 2>&1) case "$_out" in "$_want") bst_ok "$S/fc-match-$_gen-unchanged" ;; *) bst_notok "$S/fc-match-$_gen-unchanged" "fc-match $_gen => '$(_bst_1line "$_out")', want '$_want' -- this port must not take the generic" ;; esac done rm -f "$W.inv" "$W.sums" "$W.scan" "$W.st" "$W.ft" "$W.cache" "$W.list" 2>/dev/null