I’ve looked into this a bit now. I suspect that the issue is indeed to do with the particular metrics of the font.
Currently, the drawing position for vertically-centred text is computed by attempting to centre the bounding-box for the text. The bounding box is derived from the ascent and descent of the font. That is, we expect that when drawing text inside a box that is sized exactly to the font’s ascender and descender, it should appear centred within that box.
Of course, this doesn’t work if the font contains bad metrics data.
Here are the metrics of the DIN and Acumin font files you linked:
As you can see, in both of these fonts, the Typo and Win descent values are roughly equivalent, but the Typo and Win Ascent values are significantly different.
JUCE’s ‘portable’ metrics kind uses HarfBuzz to fetch the font metrics. As far as I can tell from debugging, HarfBuzz will always return the Typo or HHead metrics values, and never the Win ascent/descent values. So, in the “2KHz label” test case you posted above, we can assume that typo metrics are being used.
If we update the rendering a bit to display the bounding boxes for the glyphs, we can see the problem more clearly. The bounding boxes are correctly centred, but the ascender value is too large relative to the descender value, so the characters appear to hug the top of the bounding box.
The following screenshot shows what happens if we pick the ‘legacy’ metrics kind instead (on Windows - other platforms behave differently). Now, the Win ascent/descent values are used instead of the typo values.
Now, the ratio of ascent:descent means that more space is given over to the ascender, and the text appears to be better centred.
Finally, we can show that this issue is not specific to JUCE by testing out the font in a browser. This snippet vertically centres some text in the DIN font inside a fixed-size rect.
<!DOCTYPE html>
<html>
<style>
@font-face {
font-family: "DIN";
src: url("/path/to/DIN.ttf");
}
.center {
display: flex;
margin: auto;
width: 300px;
height: 50px;
font-size: 50px;
background: darkred;
color: white;
justify-content: center;
align-items: center;
font-family: "DIN";
}
</style>
<body>
<p class="center">20000Hz</p>
</body>
</html>
You can try changing the font-family line to see how other fonts look. Helvetica, Arial, and Verdana all look better to me, but none of them are ‘perfect’.
I suspect that the FreeType wrapper you were using may have been selecting Win metrics rather than Typo metrics, though I haven’t attempted to verify this.
Unfortunately, I’m not sure where to go from here. In the short term, perhaps the font(s) can be patched to replace the typo metrics values with the win metrics values. This seems like it would be a fairly straightforward change, but I don’t know whether it might have other repercussions, e.g. for baseline positioning.
A bigger change would be to add some kind of metrics override in JUCE when loading a font from a data block, to specify which kind of metrics should be preferred. Perhaps this could be enabled via new members in the TypefaceMetricsKind enum. A different approach would be to support something like the CSS ascent-override and descent-override directly in Font.
I’d prefer to avoid making changes in JUCE until we have a few reports of similar issues/fonts, so that we can be sure we’re adding a feature that addresses the requirements of all users.