Skip to content

Should we use font metrics for line height instead of "lp"? #31220

@QuLogic

Description

@QuLogic

Currently, we set a minimum line height by measuring the height and depth of the "lp" string. Line spacing is then some multiple of the line height (by default 1.2×).

# Full vertical extent of font, including ascenders and descenders:
_, lp_h, lp_d = _get_text_metrics_with_cache(
renderer, "lp", self._fontproperties,
ismath="TeX" if self.get_usetex() else False,
dpi=self.get_figure(root=True).dpi)
min_dy = (lp_h - lp_d) * self._linespacing

Looking back into the history, this used to be "Tglp":
# Find full vertical extent, including ascenders and descenders:
tmp, heightt = renderer.get_text_width_height(
'Tglp', self._fontproperties, ismath=False)

and before that just a "T" was used for line height:
tmp, heightt = renderer.get_text_width_height(
'T', self._fontproperties, ismath=False)

and before that, the "T" was used only for empty lines:
if not len(line) and not self.is_math_text():
# approx the height of empty line with tall char
tmp, h = renderer.get_text_width_height(
'T', self._fontproperties, ismath=False)

Now that we are supporting more fonts and languages, this may not be ideal. For example, for the test in #30725, I only specified the OpenMoji font. This font contains only emoji and no Latin characters of any kind. This causes warnings that both l and p are not found even though they aren't used in any user strings. We then end up with the ascender/descender values for the Last Resort font. I haven't found a specific example, but I can imagine a user may be setting some language-specific font that contains no Latin characters and no fallback, and would trigger this warning as well, which might be a bit mysterious.

Microsoft's recommendation is to use the ascender value to measure from top to baseline and descender value from baseline to bottom, plus a line gap to produce the interline spacing (suggested to add up to 120% the height similar to our default.) Of course, fonts being fonts, there are 2 other sets of vertical metrics and various strategies for dealing with them.

Regardless of the multiple values to try, from the history, I don't think we went with the measurement strategy because it was thought that the embedded values were unreliable. Rather, it seems to have been from necessity of not having a font parser.

So the question now goes (with some of my thoughts in parentheses):

  1. Should we move to font metrics instead? (I think so.)
  2. If so, which strategy to use? (probably the webfont or Google ones.)
  3. Should we still try to measure lp and set some combined minimum or just trust the fonts aren't broken? (hopefully not required.)
  4. What do we do when fallbacks are specified? Currently we get the measurement from the first to match the "lp" string. Should we instead look at all the specified fonts and take a minimum of all of them (even if not used in the text)? Or measure all the fonts used in a line? Or measure all the fonts used in an entire text object? (probably not the first option, unsure whether the second or third.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions