Skip to content

1.5

Choose a tag to compare

@sbeitzel sbeitzel released this 15 Sep 18:45
· 83 commits to main since this release
2669952

Text you can write, and text you can take away.

Three fixes from the same downstream consumer that 1.4.0 served. A title can now hold
a percent sign, an I: directive in a header does what the standard says it does, and
text can be outlined without engraving a tune to get it.

Highlights

Outline text without a tune (#146). CeolKit could only turn text into glyph
outlines as a side effect of engraving a tune, so a page with text and no music — a
divider page rasterised by rsvg-convert alongside tune pages, say — meant engraving a
title-only tune and regex-matching its output apart. TextOutliner now does it
directly:

let title = try TextOutliner.outline("Competition Sets", face: .libertinusSerifItalic,
                                     fontSize: 24)
title.svg            // <g fill="black"><path …/>…</g>
title.advanceWidth   // measure to centre or fit it
title.ascent         // typographic ascender at this size
title.descent        // typographic descender, as a positive distance

The fragment is self-contained — pen origin at (0, 0) on the baseline, no ids, no
<use>, no <defs> — so it can be dropped into any SVG as many times as needed and
positioned with a <g transform>. TextOutliner.width(of:face:fontSize:) measures
without decoding outlines. Any bundled face works, including Bravura. Layout is shared
with the engraver rather than reimplemented, so a string measured here and the same
string engraved in a tune are the same width; engraved documents are byte-identical to
1.4.0.

\% is a literal percent sign (#145). ABC v2.2 §2.2.5 makes % start a comment
and \% a percent sign, but every information field cut its payload at the first %,
escaped or not: T:100\% Pipes came out as 100\, and no text field could hold a
percent sign at all. A backslash now escapes the character after it, so \% is not a
comment and \\% — an escaped backslash, then a bare % — is. Text fields decode \%
and \\ (§8.2); every other backslash sequence reaches the value verbatim, as before.
I: payloads keep their escapes, as a %% directive's do, so I:dateformat \%Y now
works where it was previously truncated.

I: stylesheet directives apply in file and tune headers (#148). §3.1.19 makes
I:name payload interchangeable with %%name payload, but only the tune body honoured
it. In the file header or a tune header — where I: fields normally go — the directive
was dropped with no diagnostic. Both headers now read it with the same scope and the
same unknownDirective diagnostic as the %% spelling, and in a tune header the two
spellings resolve by source order. I: fields that are parser instructions
(abc-version, linebreak, …) are unaffected, and a bare I: is ignored.

New in the renderer

Type / member Purpose
TextOutliner.outline(_:face:fontSize:fill:) a string as a self-contained SVG outline fragment
TextOutliner.width(of:face:fontSize:) the advance width, without decoding outlines
OutlinedText the fragment, plus advanceWidth, ascent and descent
CeolKitFontsError.unreadable(Face) a bundled face that is present but cannot be parsed

Smaller changes

  • A line that is %% alone, or followed only by whitespace, is a comment. It used to
    be read as a directive with an empty name and reported as "Unsupported stylesheet
    directive '%%'".
  • Faces are parsed independently, so a request for one face is not failed by a problem
    with another.

Documentation

  • README.md — TextOutliner in the module table.
  • EXTENSIONS.md — a table of contents.

What's Changed

Full Changelog: v1.4.0...v1.5.0

Upgrading

Source-compatible with 1.4.0, with one exception: CeolKitFontsError gains an
unreadable(Face) case, so an exhaustive switch over it without a default needs
one more arm.

Three behaviour changes worth knowing about:

  • Text fields containing \% now keep the percent sign, and \\ decodes to one
    backslash. If you worked around #145 by spelling out "percent" or stripping a trailing
    backslash, remove the workaround.
  • I: stylesheet directives in a file or tune header now take effect. A file that
    carried one — harmlessly, until now — will render differently.
  • A bare %% line no longer produces an unknownDirective diagnostic.