lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Musings on the font-encoding property


From: Jean Abou Samra
Subject: Musings on the font-encoding property
Date: Wed, 29 Mar 2023 15:35:37 +0200
User-agent: Evolution 3.46.4 (3.46.4-1.fc37)

Hi,

Warning: start by taking a cup of coffee, this is all a bit headache-giving. 
Sorry for the long post.

Currently, the algorithm to select a font for normal markup (i.e., I'm not 
talking about music glyphs here) is roughly this:

1. Check the `font-encoding` property. If it's `fetaText`, use the music font, 
treated as a text font. For example:

```
\markup \override #'(font-encoding . fetaText) "fszpm1234"
```

2. If `font-encoding` is `latin1` (the default), then `font-family` is looked 
up and used to determine a font family.

```
\markup \override #'(font-encoding . fetaText) {
  fszpm123
  \override #'(font-encoding . latin1) {
    4
    \override #'(font-family . typewriter)
    4
  }
}
```

We have markup commands that set these properties, so the example above can 
also be written as

```
\markup \dynamic {
  fszpm123
  \text {
    4
    \typewriter 4
  }
}
```

However, I am wondering if it would be better to change this to a one-step 
algorithm:

1. Look up `font-family`. If it's `music`, then use the music font, otherwise 
use a text font as appropriate for the `font-family`.

Why, I hear you ask?

The `font-encoding` property can currently take four different values: 
`fetaMusic`, `fetaText`, `fetaBraces` and `latin1`.Of these four values, I 
believe that LilyPond could determine whether to choose `fetaMusic`, 
`fetaBraces`, or one of `fetaText` and `latin1` by itself. It doesn't make much 
sense, for example, to `\override Script.font-encoding = #'latin1`, unless you 
also have a stencil override, because the script will try to look up music 
glyphs in a font intended to be used as a text font.

```
{
  % no warning ATM, but doesn't print anything
  \override Script.font-encoding = #'latin1
  c'->
}
```

Conversely, if you do a stencil override, you must ensure that the 
`font-encoding` is right:

```
{
  \override Script.stencil = #ly:text-interface::print
  \override Script.text = "abc"
  % it won't work if you comment this out:
  \override Script.font-encoding = #'latin1
  c'->
}
```

This is a bit silly, because the code that looks up a glyph in the font knows 
quite well if it expects an `Open_type_font` (fetaMusic/fetaText) or a 
`Pango_font` (fetaText/latin1), and already tells which it wants through the 
API it is using (either interpreting a text string as markup, or 
`ly:grob-default-font` and the like), yet it needs to ensure that the 
`font-encoding` is right, and if it fails to do so, or if the user changes it 
by themselves, the code will get the wrong font type.

With some internal refactoring, it should be possible to get rid of the 
`fetaMusic` and `fetaBraces` values, which leaves us with `fetaText` vs. 
`latin1`. Now, that means that in addition to the names `fetaText` and `latin1` 
not making a lot of sense in current LilyPond (Feta was originally the only 
possible music font, but it has long been possible to use other fonts, and 
“latin1” is cryptic for Joe User), the `font-encoding` property becomes 
ill-named as well, because while it can be argued that music fonts are 
“encoded” differently than text fonts (they use different glyph namings), 
`fetaText` is really just the same as `latin1`, taking the Feta font (or the 
alternative music font configured by the user) and treating it like a normal 
text font. Only the font selection changes (picking the right design size) as 
well as the default value for font size.

Since both the name of the property and its two possible values will need to 
change anyway, we might as well try to get rid of it.

Now here is the tricky part. When using `fetaText`, the `font-family` is 
currently *sometimes* set to the value `'feta` (note that this value also 
appears in the `fonts` alist introduced by !1888, and for this reason I want to 
rename it to 'music soon). But sometimes only. With something like `\markup 
\dynamic p`, it's just unset, which we can reasonably treat by defaulting to 
`'feta`. But with `\markup \sans { a b c d e \dynamic f }`, it's set to `'sans` 
when interpreting the “f”, so we have an inconsistency again: `font-encoding = 
'fetaText + font-family = 'sans`, a combination that doesn't make sense yet is 
possible.

This is handled in !1888 through an ugly special case:

```
  if (scm_is_eq (encoding, ly_symbol2scm ("fetaMusic"))
      || scm_is_eq (encoding, ly_symbol2scm ("fetaBraces"))
      || scm_is_eq (encoding, ly_symbol2scm ("fetaText")))
    {
      family
        = ly_chain_assoc_get (ly_symbol2scm ("font-family"), chain, SCM_BOOL_F);
      if (scm_is_false (family)
          // This is ugly and should be improved. It happens with things like
          // \markup \sans { più \dynamic p }
          || scm_is_eq (family, ly_symbol2scm ("roman"))
          || scm_is_eq (family, ly_symbol2scm ("sans"))
          || scm_is_eq (family, ly_symbol2scm ("typewriter")))
        {
          if (scm_is_eq (encoding, ly_symbol2scm ("fetaBraces")))
            family = ly_symbol2scm ("brace");
          else // fetaMusic, fetaText
            family = ly_symbol2scm ("feta");
        }
    }
```


(It was essentially the same in the previous code, just not as apparent.)

So, I think it would make things simpler to switch to the 1-step approach. It 
would make text font selection more uniform: just look up the family in the 
fonts alist. It would eliminate the special case above, and the possible 
inconsistencies. Also, I think it's natural from the user standpoint to view 
"music" as a (special) font family along with "roman", "sans" and "typewriter".

What do we have to lose? Some backwards compatibility, mostly. `font-encoding` 
overrides will have to be adapted. It would change things like

```
\once \override Score.VoltaBracket.font-encoding = #'latin1
```

to

```
\once \override Score.VoltaBracket.font-family = #'roman % or 'sans
```

Also, the `\text` markup command would need to go away. Consider

```
\markup \column {
  \line \dynamic { sfz \text molto }
  \line \sans \dynamic { sfz \text molto }
}
```

In the first line, the "molto" is in a roman font, but it's a sans font in the 
second line, because the font-family `'sans` from the outside applies. With the 
proposed change, this would need to become

```
\markup \column {
  \line \dynamic { sfz \roman molto }
  \line \sans \dynamic { sfz \sans molto }
}
```

Because `\dynamic` would override the `font-family`, the value from the outside 
would no longer be reachable, so you would always need to choose your new value 
inside.

I think the benefits are worth the breakage, but this is open for discussion. 
What do you think?

Attachment: signature.asc
Description: This is a digitally signed message part


reply via email to

[Prev in Thread] Current Thread [Next in Thread]