# BST-TIMEOUT: 600 # ONE run of the 7.8 MB data/freetype-probe, where
# # 99-ttf-droid does seven and 99-ttf-bitstream-vera ten.
# # MEASURED at elapsed=41s on target (read off the
# # ==BST-SUITE elapsed= line, not estimated) -- the same 41s
# # 99-ttf-droid measures with seven probe runs, which is what
# # says the cost is the binary and not the face count. The
# # bound is deliberately the SAME 600
# # those four suites carry, for the reason vera's header
# # gives: all five drive the same binary and a suite whose
# # cost is dominated by one binary should not claim a
# # different bound for it. Erring on the family's bound also
# # avoids the mistake BRINTOS-1449 shipped and had to correct
# # -- a bound taken from a guess, at 48x the truth.
#
# cantarell-fonts 0.303.1 -- Cantarell, the humanist sans-serif GNOME uses as its
# interface font. poky meta/recipes-graphics/cantarell-fonts/cantarell-fonts_0.303.1.bb.
#
# ============================================================================
# ONE FILE, ONE PACKAGE, AND A DIRECTORY OF ITS OWN.
# ============================================================================
#
# The recipe builds with -Duseprebuilt=true, so meson takes prebuilt/meson.build
# instead of src/. That file installs Cantarell-VF.otf under `buildvf` and five
# static faces under `buildstatics`; meson_options.txt defaults buildvf=TRUE and
# buildstatics=FALSE and the recipe overrides neither, so exactly one file is
# installed. The five statics are not merely un-installed, they are NOT IN THE
# TARBALL -- prebuilt/ holds one .otf -- so a recipe revision that turned them on
# would fail the build rather than quietly ship five more faces.
#
# cantarell-fonts /usr/share/fonts/cantarell/Cantarell-VF.otf 170588 0644
# cantarell-fonts-dev, -dbg empty placeholders, not installed
# cantarell-fonts-doc DOES NOT EXIST -- see below
#
# fontsdir defaults to ${datadir}/fonts/cantarell and the recipe does not
# override it, so this is the FIRST font port on this image to get a directory of
# its own. /usr/share/fonts/ttf holds the 22 Liberation+Vera faces and
# /usr/share/fonts/truetype the 12 Inconsolata+Gentium+Droid ones; this port
# writes to neither. That removes the whole class of co-tenancy repair the last
# four font ports each had to do to their neighbours' suites -- no sibling suite
# is amended by this ticket -- and it is why dir-count can census the WHOLE
# directory rather than scoping by basename the way those four must.
#
# NO -doc PACKAGE, AND NO LICENCE FILE ON THE IMAGE. FILES:${PN} is an ASSIGNMENT
# that drops the default, which is the same shape as ttf-bitstream-vera's -- but
# where that recipe's own do_install writes three .TXT files for ${PN}-doc to
# pick up, this one installs NOTHING but the font. COPYING (the SIL OFL 1.1 text)
# stays in ${S}; no package could carry it, and dpkg builds no -doc package at
# all. 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 to install" look identical from the file layer alone. The licence
# is not lost: name IDs 13/14 inside the font carry the OFL notice and its URL.
#
# FILES ALSO NAMES ${datadir}/fontconfig, AND NOTHING INSTALLS THERE. There is no
# fontconfig fragment anywhere in cantarell-fonts-0.303.1, on either meson path.
# The directory nevertheless exists on the image, owned by the `fontconfig`
# package, so "absent" and "empty" are both the wrong assertion --
# pkgfiles-no-fontconfig asserts the one thing that is this port's business:
# cantarell-fonts owns no path under it. This matters more than an unused FILES
# entry usually would, because a fragment landing in /etc/fonts/conf.d would
# outrank every co-tenant's aliases silently.
#
# ============================================================================
# THIS PORT TAKES NO GENERIC -- INCLUDING system-ui, WHICH THE CONFIG SAYS IT
# SHOULD. THAT IS A MEASUREMENT, AND IT OVERTURNED THE READING OF THE CONFIG.
# ============================================================================
#
# Cantarell occurs in exactly two files in the whole of fontconfig 2.15.0's
# conf.avail -- checked exhaustively, not sampled -- and both are about one
# generic:
#
# 45-latin.conf:285 Cantarell
# system-ui
# 60-latin.conf:80 system-ui's list, FIRST entry
#
# So serif, sans-serif, monospace, fantasy and cursive cannot be affected by
# construction, and the config plainly says system-ui SHOULD move. An earlier
# draft of this suite asserted exactly that, positively, on the strength of those
# two lines. It is wrong.
#
# MEASURED ON TARGET, WITH EVERYTHING ELSE HELD FIXED: the image built one ticket
# earlier -- same base, same fontconfig, WITHOUT this package -- already answers
# `fc-match system-ui` => Liberation Mono, and so does this one. The delta is
# ZERO on all four generics. The image does enable both conf files (the
# fontconfig package ships them as symlinks in /etc/fonts/conf.d, and 60-latin is
# also why `fc-match monospace` answers Inconsolata at all), so this is not a
# missing-config story.
#
# NOR IS IT A wasm32 DIVERGENCE. A native fontconfig 2.15.0, built from this
# image's own recipe on x86-64 with Cantarell installed, answers Liberation Mono
# for system-ui too. It is upstream fontconfig behaviour, reproducible
# off-target, and NOT a brintOS defect -- so nothing is filed for it.
# `system-ui` is not one of the generics 49-sansserif.conf seeds, and whatever
# the prefer list contributes does not survive the sort.
#
# fc-match-system-ui-unchanged therefore sits alongside the other three rather
# than inverting them. It is worth carrying rather than dropping precisely
# because the config predicts otherwise: if a fontconfig bump ever makes the
# prefer list bite, this case is what says so, and it will need re-pointing
# together with the design-doc note.
#
# NO SIBLING SUITE ASSERTS system-ui -- checked across the whole tests/ tree --
# so nothing goes red either way, and no neighbour is amended. 99-ttf-droid,
# 99-ttf-inconsolata and 99-liberation-fonts assert the other three generics from
# their side, so a disagreement between the suites stays visible.
#
# ============================================================================
# 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 -- 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 and never reaches inittab -- 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, it calls fc-cache, and fc-cache is
# present, so the deferred run cannot fail for want of the tool. Nothing had to
# be overridden. Image-wide postinst success stays 79-run-postinsts' no-unpacked
# case and is not re-litigated here; the fc-* block forces `fc-cache -f` itself
# so no other case depends on any of this.
#
# ============================================================================
# FOUR LAYERS, AND A RED IN AN EARLIER ONE LOCALISES A RED IN A LATER ONE:
#
# file-*, dir-*, the payload arrived intact -- size, bytes, mode, type --
# pkgfiles-*, the package's real footprint is the one file it claims,
# cotenant-* and the two directories this port does not write to are
# unchanged. No font machinery involved at all.
# pkg-*, postinst-* the one package the image really installs, the fontcache
# class's RDEPENDS, and the deferred scriptlet.
# ft-* the image's OWN freetype PARSES the face through its CFF
# driver and agrees about num_faces, num_glyphs,
# units_per_EM, family and style -- the layer the ticket
# asks for by name -- and additionally recognises it as a
# VARIABLE font, which is what fontconfig's six patterns
# downstream rest on.
# 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 -- and where the
# six-patterns-from-one-file shape has to be asked for
# correctly, see the fc-list call for what that cost.
. "$BST_LIB"
S=cantarell-fonts
# THE CANARY, which asserts nothing about cantarell-fonts.
#
# 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/cantarell-fonts-manifest.txt
FACTS=$D/cantarell-fonts-fontfacts.txt
FACES=$D/cantarell-fonts-fcfaces.txt
PROBE_SRC=$D/freetype-probe
FDIR=/usr/share/fonts/cantarell
COT1=/usr/share/fonts/ttf
COT2=/usr/share/fonts/truetype
OTF=$FDIR/Cantarell-VF.otf
PKGLIST=/var/lib/dpkg/info/cantarell-fonts.list
PI=/var/lib/dpkg/info/cantarell-fonts.postinst
tmp=${TMPDIR:-/tmp}
W=$tmp/bst-cantarell.$$
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 cantarell-fonts, 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 cantarell-fonts 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 this port's own directory AND both co-tenant directories, 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 is no doc directory to walk: this recipe installs none (see the header).
find "$FDIR" "$COT1" "$COT2" \
-maxdepth 1 -printf '%p %y %s %m %l\n' 2>/dev/null | LC_ALL=C sort > "$W.inv"
# One sha256sum over the one payload file. Named explicitly rather than globbed:
# the manifest is the list, and dir-no-extras is what says the directory holds
# nothing the manifest does not name.
sha256sum "$OTF" > "$W.sums" 2>&1
# The package's own file list, copied to tmpfs rather than read from the rootfs
# in a redirect (brintos/linux#73). An absent list is not fatal here -- the awk's
# pkgfiles-loaded case reports it -- so this is not guarded with an exit.
cat "$PKGLIST" > "$W.pkgf" 2>/dev/null || : > "$W.pkgf"
# One fc-scan over the one installed file. fontconfig opens it 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 variable flag and the instance index). It reads the FILE, not the
# cache, so it is independent of the fc-cache in the consumer block below.
#
# SIX PATTERNS COME BACK FROM ONE FILE. See the fcfaces control's header.
LC_ALL=C fc-scan --format '%{file|basename}|%{family}|%{style}|%{slant}|%{weight}|%{spacing}|%{postscriptname}|%{fontformat}|%{scalable}|%{outline}|%{variable}|%{index}\n' \
"$OTF" 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 PKGF="$W.pkgf" \
-v FACES="$FACES" -v SCAN="$W.scan" \
-f "$D/cantarell-fonts-verify.awk" "$REF" "$W.sums" "$W.inv" "$W.pkgf" "$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 some other package had installed the same
# bytes, so they cannot say that cantarell-fonts 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. `cantarell-fonts` is a PREFIX of
# `cantarell-fonts-dev`, `-dbg` and `-doc`, so an unanchored match would report
# one stanza as another and make pkg-no-doc-package unfalsifiable.
sed -n '/^Package: cantarell-fonts$/,/^$/p; /^Package: cantarell-fonts-doc$/,/^$/p;
/^Package: cantarell-fonts-dev$/,/^$/p; /^Package: cantarell-fonts-dbg$/,/^$/p' \
/var/lib/dpkg/status > "$W.st" 2>/dev/null
_pkg=""; _main=0; _doc=0; _dev=0; _dbg=0; _arch=0; _dep=0
while IFS= read -r l; do
case "$l" in
"Package: cantarell-fonts") _pkg=main; _main=1 ;;
"Package: cantarell-fonts-doc") _pkg=doc; _doc=1 ;;
"Package: cantarell-fonts-dev") _pkg=dev; _dev=1 ;;
"Package: cantarell-fonts-dbg") _pkg=dbg; _dbg=1 ;;
"Architecture: all")
[ "$_pkg" = main ] && _arch=1 ;;
"Depends: "*)
case "$l" in *fontconfig-utils*) [ "$_pkg" = main ] && _dep=1 ;; esac ;;
esac
done < "$W.st"
# THE ONE PACKAGE THIS IMAGE INSTALLS. A dropped IMAGE_INSTALL line would take
# every file-* and ft-* case with it; this case says the cause is a missing
# PACKAGE rather than missing files.
if [ "$_main" -eq 1 ]; then bst_ok $S/pkg-known
else bst_notok $S/pkg-known "dpkg does not know the package cantarell-fonts"; fi
# THERE IS NO -doc PACKAGE, AND ITS ABSENCE IS THE RECIPE. Nothing but the font
# is installed, so ${PN}-doc is empty and dpkg builds none. This case names that,
# because a future recipe revision that installed COPYING would change what the
# image must ask for -- and because ttf-bitstream-vera, the port this one most
# resembles, DOES ship a -doc and this one deliberately does not.
if [ "$_doc" -eq 0 ]; then bst_ok $S/pkg-no-doc-package
else bst_notok $S/pkg-no-doc-package "dpkg knows a cantarell-fonts-doc package -- the recipe now installs documentation"; fi
# ...AND -dev / -dbg ARE NOT INSTALLED. Both are built and both are empty. They
# are asserted absent rather than ignored: an IMAGE_INSTALL that pulled them in
# would add two packages to the manifest for no payload at all, and nothing else
# in this suite would notice.
if [ "$_dev" -eq 0 ]; then bst_ok $S/pkg-no-dev
else bst_notok $S/pkg-no-dev "cantarell-fonts-dev is installed -- it is an empty placeholder"; fi
if [ "$_dbg" -eq 0 ]; then bst_ok $S/pkg-no-dbg
else bst_notok $S/pkg-no-dbg "cantarell-fonts-dbg is installed -- it is an empty placeholder"; 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.
if [ "$_arch" -eq 1 ]; then bst_ok $S/pkg-arch-all
else bst_notok $S/pkg-arch-all "cantarell-fonts is not Architecture: all"; fi
# THE fontcache CLASS'S RDEPENDS, READ BACK OFF THE TARGET. The recipe declares
# no runtime dependency at all -- 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 "cantarell-fonts does not Depend on fontconfig-utils"; fi
# ------------------------------------------------- the deferred fontcache hook
if [ -f "$PI" ]; then bst_ok $S/postinst-present
else bst_notok $S/postinst-present "$PI is absent -- the fontcache postinst did not reach the image"; fi
# It calls fc-cache on the branch run-postinsts takes ($D unset at first boot).
check_out $S/postinst-runs-fc-cache "fc-cache" cat "$PI"
# ...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 cantarell-fonts but /usr/bin/fc-cache is absent"; fi
# ------------------------------------------------------ freetype parses it
# 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" "$W.pkgf" 2>/dev/null
exit 0
fi
bst_ok $S/probe-present
probe=$tmp/bst-cantarell-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" "$W.pkgf" 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.
#
# NO TRAILING == ON THE FENCE. `==FONT Cantarell-VF.otf==` puts
# "Cantarell-VF.otf==" 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 -- the defect BRINTOS-1449's host pre-flight caught.
: > "$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" "$FDIR/$_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/cantarell-fonts-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 ONE FACE SITS WELL INSIDE THE IMAGE'S EXISTING WORKING SET. #165's
# bracket on this image is ~66 kB to 577,708 bytes; this face is 170,588, the 52
# font files already walked by every fc-cache run are 23,895 to 415,816, and
# TWENTY-TWO of those 52 are larger than this one. So this package cannot
# introduce a new failure mode or a new maximum. Nothing is held out and there
# are no held-out-* cases, which is what distinguishes this suite from
# 99-ttf-droid's.
#
# 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, and MEASURED on the
# resulting image this suite parked here -- reaching 43 of its 50 cases against
# 50/50 in 30 s on the same base pin without the port. 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 -- fc-cache runs and
# returns 0.
#
# 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.
#
# THE OBJECT SET MUST CARRY `style`, AND THAT IS NOT COSMETIC. fc-list DEDUPES
# its output on the properties it was ASKED for, not on the underlying patterns.
# A variable font's six patterns share one file and one family and differ only in
# style and index -- so `fc-list : file family`, which is what every other font
# suite on this image correctly uses, collapses all six into ONE line. Measured
# on target: that spelling reports 1 where `fc-cache -f -v` says
# "/usr/share/fonts/cantarell: caching, new cache contents: 6 fonts" and an
# unrestricted fc-list returns all six. The cache is right; the query was wrong.
fc-list : file family style > "$W.list" 2>&1
# THE FACE IS 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.
#
# SIX ENTRIES, NOT ONE. fc-list reports the cached patterns, and a variable font
# contributes one per named instance plus one for itself -- the same six fc-scan
# produced from the file directly. Asserting 1 here, which is what every other
# font suite on this image correctly asserts for its static faces, would be a red
# on a working port. The line format is now ": :style=