# BST-TIMEOUT: 300 # MEASURED, not predicted: elapsed=32s over 49 cases on a # # clean boot (2026-08-30, hz1, local-verify on the runtime # # the image was built from) -- 49 being what this suite ran # # BEFORE the merge against main dropped its system-ui case; # # it runs 48 now, so the measured bound is if anything # # looser and every figure below belongs to that 49-case run. # # Read off this suite's own # # ==BST-SUITE elapsed= line. So the bound is ~9.4x the run. # # That is the convention at this size -- 57-fontconfig sits # # at 300 on a measured 76s, and 99-ttf-hunkyfonts at 300 on # # a measured 35s -- and reading the line rather than # # reasoning about it is the correction BRINTOS-1449 had to # # ship when it guessed at 48x the truth. # # # # THE "NO PROBE, SO CHEAPER PER CASE" PREDICTION WAS WRONG, # # AND IN THE UNSAFE DIRECTION. This suite starts no probe # # binary, so an earlier draft of this header reasoned it # # would come in under 99-ttf-hunkyfonts' measured # # 0.48-0.57 s/case. It runs at 0.65 s/case (32s / 49), # # ABOVE 99-cantarell-fonts' 0.60 s/case (30s / 50) measured # # in the same boot -- which does drive a probe. # # # # The reason is that per-case cost here is dominated by # # EXECS, not by what is exec'd: this suite's consumer block # # runs seven fc-match calls, two fc-list calls, an fc-cache # # and a recursive `grep -ril` over /etc/fonts, so its # # exec-to-case ratio is higher than a suite that starts one # # probe and reads its output. Recorded because the # # prediction is the natural one to make and it does not # # hold; on this arm a process's memory is not returned when # # it exits, so exec COUNT is the thing to reason about. # # ttf-abyssinica 2.100 -- Abyssinica SIL, SIL International's Ethiopic-script # font for Amharic, Tigrinya and Ge'ez, under OFL-1.1. meta-openembedded # meta-oe/recipes-graphics/ttf-fonts/ttf-abyssinica_2.100.bb. # # ============================================================================ # THE POINT OF THIS FONT IS THE ETHIOPIC CHARSET, SO THAT IS WHAT THE SUITE # CHECKS -- NOT ONLY THAT A FILE ARRIVED. # ============================================================================ # # Every ordinary font assertion in this suite -- the pinned file list, the # digest, fc-cache, fc-list, fc-query, fc-match -- is satisfied by a 331,004-byte # file with the right name and the right internal name table. NONE of them asks # whether the thing can write Amharic. The eth-* cases do, by reading the face's # own charset through fc-query and counting the codepoints it covers in each of # the five Ethiopic Unicode blocks against a committed control: # # Ethiopic U+1200..U+137F 358 of 384 # Ethiopic Supplement U+1380..U+139F 26 of 32 # Ethiopic Extended U+2D80..U+2DDF 79 of 96 # Ethiopic Extended-A U+AB00..U+AB2F 32 of 48 # Ethiopic Extended-B U+1E7E0..U+1E7FF 28 of 32 # --- # 523 Ethiopic codepoints, of 843 # # MEASURED (2026-08-30, fontconfig 2.15.0). The counts are less than the block # sizes because Unicode leaves holes in these blocks and SIL does not draw every # assigned slot; a control written from the block sizes would fail on a correct # font. THE COUNTS ARE ASSERTED AND NOT ONLY THE PRESENCE OF EACH BLOCK, because # presence is the check that passes on a font whose outlines were truncated -- # a broken glyf table still leaves a non-empty range in every block. # # ============================================================================ # BEFORE THIS PORT, NOTHING ON THIS IMAGE COVERED AMHARIC AT ALL. # ============================================================================ # # MEASURED as a 2x2 on a reconstruction of this image's font tree, with and # without this package (2026-08-30, fontconfig 2.15.0): # # WITHOUT: fc-list ":lang=am" -> (nothing) # WITH: fc-list ":lang=am" -> AbyssinicaSIL-Regular.ttf # # So fc-list-lang-am-sole is not a restatement of fc-match-Abyssinica-SIL: it # says this package is the image's ONLY supplier of the script, which is the # thing the port exists to change and the thing a later font port could silently # take over. The face advertises am, gez, ti-er, ti-et, byn, sid, tig and wal # among 94 language tags. # # NOTE ti IS NOT IN THE FACE'S LANG LIST -- ti-er AND ti-et ARE. fontconfig # normalises a bare `ti` request onto them, so `fc-match :lang=ti` still lands # here, but a case asserting the literal tag `ti` in the lang list would be # asserting something false. The suite queries ti-et. # # ============================================================================ # ONE FACE, AND `FILES:${PN} = "${datadir}"` IS WHY THE PAYLOAD IS PINNED HARD. # ============================================================================ # # FILES_INFO:ttf-abyssinica AbyssinicaSIL-Regular.ttf 331,004 # # READ OFF THE BUILT PACKAGE (pkgdata/runtime/ttf-abyssinica), not predicted # from the FILES glob -- which is the WHOLE of ${datadir} and would tell you # nothing. SIL ships Abyssinica as a single Regular weight: there is no Bold, no # Italic and no BoldItalic to be missing, and a suite assuming a four-face family # by convention would report three absent files that were never drawn. # # The upstream zip carries a good deal MORE than the face -- OFL.txt, # FONTLOG.txt, README.txt, OFL-FAQ.txt, documentation/ (odt, pdf, doc) and web/ # (.woff, .woff2, an example .css and .html). With `FILES:${PN} = "${datadir}"` # open that wide, the only thing keeping them out of the image is ttf.inc's # do_install copying `*.tt[cf]` and nothing else. no-woff asserts that from the # file layer and pkg-no-doc-package from the package layer, because "the licence # text is absent" and "the licence text was dropped" look identical otherwise. # # NO LICENCE TEXT REACHES THE IMAGE, AND THAT IS THE RECIPE. LIC_FILES_CHKSUM # points at ${S}/OFL.txt, which do_install does not copy. That is upstream # Yocto's ordinary behaviour for ttf.inc and not a defect of this port; it is # recorded here so a reader does not go looking for it. # # ============================================================================ # fc-match RESOLVES THE FAMILY TO THIS PACKAGE -- THE TICKET'S REQUIREMENT IN # ITS LITERAL WORDING. THE "UNPROVIDED FAMILY" HALF IS NOT MET, AND THE REASON # IS MEASURED. # ============================================================================ # # MEASURED (2026-08-30, fontconfig 2.15.0 over this image's whole font tree): # # fc-match "Abyssinica SIL" -> /usr/share/fonts/truetype/AbyssinicaSIL-Regular.ttf # fc-match sans-serif -> LiberationSans-Regular.ttf (unchanged) # fc-match serif -> LiberationSerif-Regular.ttf (unchanged) # fc-match monospace -> SourceCodePro-Regular.otf (unchanged) # # The ticket also asks that "fc-match for a family name this package does not # provide is asserted to NOT resolve here, so a mis-scoped fontconfig entry fails # rather than passing by accident". THAT CASE IS NOT IN THIS SUITE, because the # 2x2 shows the premise does not hold on this image and the case would be red for # a reason that has nothing to do with a mis-scoped entry: # # WITHOUT this port: "Zzzz Nonexistent" -> LiberationMono-Regular.ttf # WITH this port: "Zzzz Nonexistent" -> AbyssinicaSIL-Regular.ttf # # EVERY unmatched family name moves, not names resembling this one: "Comic Sans # MS" and "Hunky Mono" move too, and so does a name that resembles this family # but is not it. fc-match never returns nothing -- it always returns a best # match -- so the image has an arbitrary unknown-family incumbent either way, and # this port becomes it. # # THREE EXPLANATIONS WERE RULED OUT BY MEASUREMENT, NOT BY ARGUMENT: # - a fontconfig fragment from this package: `grep -ril abyssinica /etc/fonts` # returns nothing (this is what conf-no-fragment asserts on target); # - language coverage: this face carries 94 lang tags against Liberation's # 193, so the WINNER HAS FEWER; # - spacing: `fc-match "Zzzz Nonexistent:spacing=100"` still lands here. # Which comparator in fontconfig's sort actually decides it was NOT established, # and is not guessed at here. # # So the ticket's INTENT -- that this package must not capture matching it has # no business capturing -- is asserted by the two cases that can carry it: # conf-no-fragment (this package ships no fontconfig entry at all) and the three # fc-match-generic-* cases (the generics real consumers actually resolve keep # their incumbents). The unknown-family fallback is recorded here as a measured # observation and deliberately NOT asserted: it is a whole-image property that # the next font port will move again, so a case pinning it would be rot rather # than coverage. # # ============================================================================ # ORDERING AND THE fc-cache BOUND # ============================================================================ # # `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; that ticket MEASURED four font suites parking here on an image whose # largest face had gone over the line. Without -f, fc-cache rebuilds only what is # stale. This face is 331,004 bytes, which is LARGER than any face those four # suites walk, so this suite keeps the bound and the last-place ordering rather # than reasoning that it is safe. # # BRINTOS-WORKAROUND: linux-in-the-browser#165 revisit -- drop -f so only a stale # cache is rebuilt, bound the call, and order the consumer block last; all three # go when the mmap population path tolerates a parking read. . "$BST_LIB" S=ttf-abyssinica # THE CANARY, which asserts nothing about ttf-abyssinica. # # 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-abyssinica-manifest.txt FACES=$D/ttf-abyssinica-fcfaces.txt ETH=$D/ttf-abyssinica-charset.txt TTFDIR=/usr/share/fonts/truetype COTDIR=/usr/share/fonts/ttf OURFILE=AbyssinicaSIL-Regular.ttf PI=/var/lib/dpkg/info/ttf-abyssinica.postinst LIST=/var/lib/dpkg/info/ttf-abyssinica.list tmp=${TMPDIR:-/tmp} W=$tmp/bst-ttf-abyssinica.$$ require gawk $S/gawk-present require sha256sum $S/sha256sum-present require find $S/find-present # fc-query 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 this package, so an absent fc-query is a defect in the port rather # than a legitimately absent tool, and a skip would report it green. if [ -x /usr/bin/fc-query ]; then bst_ok $S/fc-query-present else bst_notok $S/fc-query-present "fontconfig-utils is a Depends of ttf-abyssinica but /usr/bin/fc-query is absent"; fi if [ ! -f "$REF" ] || [ ! -f "$FACES" ] || [ ! -f "$ETH" ]; then bst_notok $S/ref-present "the reference data did not ship: $REF / $FACES / $ETH" exit 0 fi bst_ok $S/ref-present # ------------------------------------------------------------- payload shape # One find over this package's directory and over the other font directory, so # every count below 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. find "$TTFDIR" "$COTDIR" \ -maxdepth 1 -printf '%p %y %s %m %l\n' 2>/dev/null | LC_ALL=C sort > "$W.inv" # One sha256sum over the payload. Named explicitly rather than globbed: a glob of # "$TTFDIR"/Abyssinica* would be right today but would also silently absorb a # second Abyssinica file, which is precisely what ttf-count exists to catch. sha256sum "$TTFDIR/$OURFILE" > "$W.sums" 2>&1 # One fc-query sweep over the installed face -- the ticket's named check. It # reads the FILE, not the cache, so it is independent of the fc-cache in the # consumer block below. Field order matches the committed control. LC_ALL=C fc-query --format '%{file|basename}|%{family}|%{style}|%{slant}|%{weight}|%{spacing}|%{fontformat}\n' \ "$TTFDIR/$OURFILE" 2>/dev/null | LC_ALL=C sort > "$W.scan" # THE CHARSET, read from the face itself. This is the read the eth-* cases are # built on and it is the one assertion in this suite that is about the font # rather than about the file. LC_ALL=C fc-query --format '%{charset}' "$TTFDIR/$OURFILE" 2>/dev/null > "$W.cs" LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" \ -v FACES="$FACES" -v SCAN="$W.scan" -v ETH="$ETH" -v CS="$W.cs" \ -f "$D/ttf-abyssinica-verify.awk" "$REF" "$W.sums" "$W.inv" "$FACES" "$W.scan" "$ETH" "$W.cs" # ---------------------------------------------------- the packaging on target # ONE PACKAGE, AND ITS NAME MATCHES THE RECIPE -- which is worth asserting here # precisely because the sibling font ports on this image are the cases where it # does NOT (ttf-hunkyfonts ships ttf-hunky-sans and ttf-hunky-serif; ttf-droid # ships ttf-droid-sans and ttf-droid-serif). `FONT_PACKAGES = "${PN}"` and the # default PACKAGES, so `IMAGE_INSTALL += "ttf-abyssinica"` resolves. The stanzas # are read from a tmpfs copy, never redirected from the rootfs # (brintos/linux#73). # # THE ANCHORS ARE EXACT ON PURPOSE. `ttf-abyssinica` is a prefix of # `ttf-abyssinica-doc`, so an unanchored match would misfile the stanzas and make # pkg-no-doc-package unfalsifiable. sed -n '/^Package: ttf-abyssinica$/,/^$/p; /^Package: ttf-abyssinica-doc$/,/^$/p' \ /var/lib/dpkg/status > "$W.st" 2>/dev/null _pkg=""; _known=0; _doc=0; _arch=0; _dep=0 while IFS= read -r l; do case "$l" in "Package: ttf-abyssinica") _pkg=main; _known=1 ;; "Package: ttf-abyssinica-doc") _pkg=doc; _doc=1 ;; "Architecture: all") [ "$_pkg" = main ] && _arch=1 ;; "Depends: "*) case "$l" in *fontconfig-utils*) [ "$_pkg" = main ] && _dep=1 ;; esac ;; esac done < "$W.st" if [ "$_known" -eq 1 ]; then bst_ok $S/pkg-known else bst_notok $S/pkg-known "dpkg does not know the package ttf-abyssinica"; fi # THERE IS NO -doc PACKAGE, AND ITS ABSENCE IS do_install RATHER THAN A DROPPED # LINE. The recipe leaves PACKAGES at the default, so ttf-abyssinica-doc EXISTS # as a definition -- it is simply empty, because do_install copies `*.tt[cf]` # and the zip's OFL.txt, README.txt and documentation/ never leave ${S}. An # empty package is not written out, so dpkg must not know it. if [ "$_doc" -eq 0 ]; then bst_ok $S/pkg-no-doc-package else bst_notok $S/pkg-no-doc-package "dpkg knows a ttf-abyssinica-doc package -- do_install now installs something under \${datadir}/doc"; fi # `allarch` reached the package metadata, which is what makes the byte-identity # claim in the manifest a statement about this build rather than a coincidence. if [ "$_arch" -eq 1 ]; then bst_ok $S/pkg-arch-all else bst_notok $S/pkg-arch-all "ttf-abyssinica 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 # this is the case that says the class did its half and that the dependency # resolved against a package this image already carried (fontconfig-utils has # been here since BRINTOS-1032). if [ "$_dep" -eq 1 ]; then bst_ok $S/pkg-depends-fontconfig else bst_notok $S/pkg-depends-fontconfig "ttf-abyssinica does not Depend on fontconfig-utils"; fi # WHICH FILES THE PACKAGE OWNS, FROM THE PACKAGE DATABASE. `FILES:${PN}` is the # whole of ${datadir}, so this is the only place on target that says the package # claimed ONE path and not a directory's worth. THE LIST IS COPIED TO TMPFS AND # READ FROM THERE: a `while read ... < /var/lib/dpkg/info/x.list` in the # TOP-LEVEL shell is a stdin redirect FROM the rootfs, which on this arm ends the # suite where it stands and emits nothing further -- brintos/linux#73, and the # repo's own check-suite-redirects.py refuses it at do_install. # # BRINTOS-WORKAROUND: brintos/linux#73 remove -- stage the dpkg file list on # tmpfs rather than redirecting the top-level shell's stdin from the rootfs. cat "$LIST" > "$W.ls" 2>/dev/null # dpkg's .list NAMES THE DIRECTORIES THE PACKAGE CREATED, and it names them # WITHOUT a trailing slash -- /., /usr, /usr/share, /usr/share/fonts and # /usr/share/fonts/truetype all appear here beside the face. An earlier draft of # this case filtered on a trailing slash and reported all five as files this # package should not own; the port was fine and the guard was wrong. Directories # are skipped by asking the target, which is the only thing that can tell them # apart from a file at this layer. _own=0; _ownextra="" while IFS= read -r l; do [ -z "$l" ] && continue [ -d "$l" ] && continue case "$l" in "$TTFDIR/$OURFILE") _own=$((_own+1)) ;; *) _ownextra="$_ownextra ${l}" ;; esac done < "$W.ls" if [ "$_own" -eq 1 ]; then bst_ok $S/pkg-owns-face else bst_notok $S/pkg-owns-face "dpkg says ttf-abyssinica owns $_own copy of $TTFDIR/$OURFILE, want 1"; fi if [ -z "$_ownextra" ]; then bst_ok $S/pkg-owns-nothing-else else bst_notok $S/pkg-owns-nothing-else "ttf-abyssinica also owns:$(_bst_1line "$_ownextra")"; fi # THE DEFERRED FIRST-BOOT SCRIPTLET. fontcache.bbclass writes a pkg_postinst # that calls fc-cache; on this image it is deferred to first boot rather than run # at rootfs time, so it must be PRESENT on target and must actually call # fc-cache. Both halves: a present scriptlet that no longer calls fc-cache would # leave the cache case below green only because something else rebuilt it. if [ -f "$PI" ]; then bst_ok $S/postinst-present else bst_notok $S/postinst-present "$PI is absent -- fontcache.bbclass did not write a postinst"; fi if grep -q 'fc-cache' "$PI" 2>/dev/null; then bst_ok $S/postinst-runs-fc-cache else bst_notok $S/postinst-runs-fc-cache "$PI does not call fc-cache"; fi # ------------------------------------------------------------ the consumer side # ORDERED LAST, DELIBERATELY -- see the fc-cache note in the header. Everything # above has already emitted by the time the bounded fc-cache runs, so a park here # costs this block and not the suite's evidence. if [ -x /usr/bin/fc-cache ]; then bst_ok $S/fc-cache-present else bst_notok $S/fc-cache-present "/usr/bin/fc-cache is absent"; fi # 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 FACE IS DISCOVERABLE THROUGH THE CACHE, not merely present on disk and # parseable by fc-query. A cache that serialised wrongly, or a FreeType that # refused the outlines, shows up here while every file-* and fcq-* case above # stays green -- which is the split that says where to look. Matched on the FULL # PATH, so nothing outside this package's directory can satisfy it. _seen=0; _fam="" while IFS= read -r l; do case "$l" in "$TTFDIR/$OURFILE":*) ;; *) continue ;; esac _seen=$((_seen+1)) _fam=${l#*: } done < "$W.list" if [ "$_seen" -eq 1 ] && [ "$_fam" = "Abyssinica SIL" ]; then bst_ok "$S/fc-list-$OURFILE" else bst_notok "$S/fc-list-$OURFILE" "fc-list reports $_seen entries for $TTFDIR/$OURFILE family '$_fam', want 1 of 'Abyssinica SIL'" fi # THE FAMILY RESOLVES TO THIS PACKAGE'S FACE. This is the ticket's "proves the # font is actually usable and not merely present on disk" check, and it holds in # the ticket's own wording: nothing else on this image supplies this family name. # fc-match never fails -- it always returns some face -- so this is real only # because ~70 other faces are installed alongside: a family that did not reach # the cache falls through to one of them, which is exactly what 99-terminus-font's # first on-target run reported for its own family. The FILE is asserted, not just # the family, so a fallthrough that happened to be renamed cannot pass. _out=$(fc-match --format '%{file} %{family}' "Abyssinica SIL" 2>&1) if [ "$_out" = "$TTFDIR/$OURFILE Abyssinica SIL" ]; then bst_ok $S/fc-match-Abyssinica-SIL else bst_notok $S/fc-match-Abyssinica-SIL "fc-match 'Abyssinica SIL' => '$(_bst_1line "$_out")', want '$TTFDIR/$OURFILE Abyssinica SIL'"; fi # THE SCRIPT RESOLVES TO THIS PACKAGE, WHICH IS WHAT THE PORT IS FOR. A consumer # asking for Amharic by language rather than by family name is the realistic # path, and it is a different question from the family lookup above: it goes # through fontconfig's lang matching over the whole font set. Three tags, because # the ticket names Amharic and Tigrinya and the face also advertises Ge'ez. # # ti-et, NOT ti. The face's lang list carries ti-er and ti-et and NOT a bare ti # -- measured -- so the specific tag is the honest probe. for _lang in am ti-et gez; do _out=$(fc-match --format '%{file}' ":lang=$_lang" 2>&1) if [ "$_out" = "$TTFDIR/$OURFILE" ]; then bst_ok "$S/fc-match-lang-$_lang" else bst_notok "$S/fc-match-lang-$_lang" "fc-match ':lang=$_lang' => '$(_bst_1line "$_out")', want $TTFDIR/$OURFILE"; fi done # THIS PACKAGE IS THE IMAGE'S SOLE SUPPLIER OF THE SCRIPT. MEASURED as a 2x2: # without this port `fc-list ":lang=am"` returns NOTHING on this image, and with # it, exactly this face. That is a different claim from fc-match-lang-am above, # which would stay green if a second Ethiopic font arrived and merely lost the # ranking. A red here says the image gained another supplier -- worth knowing, # and not necessarily a fault. # --format, NOT the `file` element: `fc-list file` prints ": " with # a trailing colon AND space, which an earlier draft of this case stripped with # `sed 's/:$//'` and did not, so it compared ": " against "" and # reported the right answer as wrong. --format emits the bare path. fc-list --format '%{file}\n' ":lang=am" 2>/dev/null > "$W.lang" _n=0; _bad="" while IFS= read -r l; do [ -z "$l" ] && continue _n=$((_n+1)) [ "$l" = "$TTFDIR/$OURFILE" ] || _bad="$_bad $l" done < "$W.lang" if [ "$_n" -eq 1 ] && [ -z "$_bad" ]; then bst_ok $S/fc-list-lang-am-sole else bst_notok $S/fc-list-lang-am-sole "fc-list ':lang=am' returns $_n face(s):$(_bst_1line "$_bad") -- want only $TTFDIR/$OURFILE"; fi # THIS PACKAGE SHIPS NO FONTCONFIG FRAGMENT, ASSERTED ON TARGET. This is the # case that carries the ticket's "so a mis-scoped fontconfig entry fails rather # than passing by accident" -- see the header for why the unprovided-family probe # the ticket words it as cannot be written on this image. A fragment naming this # family is exactly how a font port takes matching it has no business taking, and # it is the one mechanism this package could introduce. _frag=$(grep -ril abyssinica /etc/fonts 2>/dev/null | tr '\n' ' ') if [ -z "$_frag" ]; then bst_ok $S/conf-no-fragment else bst_notok $S/conf-no-fragment "/etc/fonts names this family in:$(_bst_1line "$_frag") -- this package ships no fontconfig fragment"; fi # THE THREE GENERICS THIS PORT DOES **NOT** TAKE OVER, ASSERTED FROM THIS SIDE. # This family appears on no preference list in this image's /etc/fonts (asserted # directly above) and is not monospaced, so all three generics keep their # incumbents. This is NOT a restatement of the fc-match-* cases: those stay green # if installing this family ALSO displaced a generic, which is precisely what # installing ttf-inconsolata did to `monospace` one ticket after it landed. The # incumbents are named so a red says which one moved. # # system-ui IS DELIBERATELY NOT ASSERTED HERE, AND THAT IS A MEASURED DECISION # RATHER THAN AN OMISSION. On the image this port was built and verified on it # DID move: `fc-match system-ui` answered Liberation Mono one ticket earlier and # `Abyssinica SIL` here. That is not a preference list biting -- 60-latin.conf:77 # does carry a alias for system-ui, and 99-cantarell-fonts established # by measurement (on target AND off it, against a native fontconfig 2.15.0) that # the alias does NOT decide the answer. system-ui is seeded as a generic by # nothing, so the query behaves as an UNMATCHED FAMILY NAME and takes whatever # the image's unknown-family fallback currently is -- exactly as # "Zzzz Nonexistent" does, and the two moved together in the same 2x2. # # ON THE MERGED TREE IT DOES NOT MOVE AT ALL, AND THAT IS WHY THERE IS NO CASE. # Measured at the merge against `main`: system-ui ranks 1 Roboto, 2 Abyssinica # SIL, 3 Liberation Mono, 4 Liberation Sans -- ttf-roboto's twenty faces keep the # fallback, and this one face ranks second. An `Abyssinica SIL` assertion here # would have been green on this branch's own pre-merge image and RED the moment # it landed, which is the whole reason this port asserts the three BOUND generics # and nothing else. The value lives in 99-cantarell-fonts, which asserts it as # `Roboto` from the side that owns it. # # THE DURABLE REPAIR IS NOT THIS PORT'S TO MAKE: give system-ui a real binding # rather than a list that does not bite, and it stops being a fallback # incumbent that every font port re-points. That is distro policy, out of scope # for a package port, and recorded in this ticket's design doc. # AMENDED FOR BRINTOS-1729 (ttf-tlwg), WHICH TAKES sans-serif AND serif # IMAGE-WIDE. ttf-tlwg ships ten fragments into /etc/fonts/conf.d # at 64; PREPENDS ahead of the generic while 30-liberation-aliases.conf's # only APPENDS behind it, so Kinnari takes `serif` and Waree takes # `sans-serif` for every suite on this image at once. It is CONFIGURATION-driven, # so it does not depend on how large the font set is. monospace is unaffected -- # source-code-pro-fonts' own loads at 44, ahead of these. THE CASE IS # AMENDED, NOT DELETED: what it asserts is that THIS port does not take a generic, # which is still true, and only the value it is compared against moved. for _pair in "sans-serif:Waree" "serif:Kinnari" "monospace:Source Code Pro"; do _g=${_pair%%:*}; _want=${_pair#*:} _out=$(fc-match --format '%{family}' "$_g" 2>&1) if [ "$_out" = "$_want" ]; then bst_ok "$S/fc-match-generic-$_g" else bst_notok "$S/fc-match-generic-$_g" "fc-match $_g => '$(_bst_1line "$_out")', want '$_want' -- this port must not take a generic"; fi done rm -f "$W.inv" "$W.sums" "$W.scan" "$W.cs" "$W.st" "$W.ls" "$W.cache" "$W.list" "$W.lang" 2>/dev/null