Text rendering on Mac versus Windows
-
How's everyone handling the text rendering differences between Mac and Windows?
I develop on a Mac and when I finally saw the plugin in Windows, I was horrified at the text rendering!

Leaving aside the awful 1x rendering issues, the font metrics were off by much more than I'd like.
Since all my font sizes are defined in a
Typographynamespace, I added a platform-specific scaling function to resize the fonts - interestingly scaling two fonts in opposite directions.
Is there a more elegant/robust way to handle this? Are my fonts the problem here?
-
@dannytaurus said in Text rendering on Mac versus Windows:
I added a platform-specific scaling function to resize the fonts - interestingly scaling two fonts in opposite directions
That's what I do.
I also use Google fonts when I can because they tend to have fewer issues.
-
@David-Healey I switched to Google fonts for exactly that reason - hoping they would have decent hinting for Windows.
But both fonts need scaling factors (x1.12 and x1.2) for Windows and the baseline is even off on one of them. *sigh*
-
@David-Healey Turns out, it's not Windows/JUCE/HISE/our code - it's the fonts themselves!

PSA: If your fonts render bigger/smaller on Windows than Mac, your font files are probably broken (and how to fix them)
Claude and I just solved a cross-platform rendering issue that I'd been treating as "JUCE renders fonts differently on Windows" - turns out it was nothing of the sort, and the fix is a one-time patch to the TTFs themselves.
Sharing here because I nearly shipped a table of per-platform correction factors instead.
Symptom: the same embedded font at the same nominal size rendered ~12–24% smaller on Windows than on macOS (three different fonts, three different ratios).
Cause: a TTF carries three sets of vertical metrics -
hhea,OS/2 typo, andOS/2 win- and they're allowed to disagree with each other. macOS (CoreText) sizes fonts fromhhea; JUCE on Windows uses theOS/2 winmetrics.This isn't from dodgy free fonts — they're popular stock Google Fonts downloads (Barlow, Barlow Condensed and Michroma). All three even set the
USE_TYPO_METRICSflag asking renderers to use the consistent tables, but the JUCE Windows path ignores it.Diagnosis (predict the divergence before you patch anything):
# Python script, and fontTools should be installed (pip install fontTools)) from fontTools.ttLib import TTFont f = TTFont("MyFont.ttf") hhea, os2 = f["hhea"], f["OS/2"] print("hhea total:", hhea.ascent + abs(hhea.descent)) print("win total:", os2.usWinAscent + os2.usWinDescent)If
win/hheamatches your measured Mac to Windows size ratio, this is your problem. Mine predicted x1.24, x1.13, x1.12 against measured x1.2, x1.12, x1.12. Close enough proof for me.Fix
os2.usWinAscent = hhea.ascent os2.usWinDescent = abs(hhea.descent) f.save("MyFont.ttf")Mac rendering is untouched (
hheaunchanged), Windows converges to match.After patching, all my script-side correction factors went to 1.0 and both platforms render pixel-identical sizes. Meaning I could remove all the platform-specific text scaling code I had just added.

Gotcha
- Classic "HISE caches fonts per session" - after replacing a TTF in place, fully quit and relaunch HISE before testing or exporting. A recompile silently keeps the old typeface.
-
Glad you found the root cause, will make things much easier. I'll see if I can do the same with bash.
-
@dannytaurus said in Text rendering on Mac versus Windows:
JUCE on Windows uses the OS/2 win metrics.
Why don't we patch JUCE to always use the mac values or the OpenType values?
-
@David-Healey Had Claude do a deep dive on this. My summary:
1. It was fixed in JUCE 8.
JUCE 8 (2024) introduced
TypefaceMetricsKindwith two modes:legacy(the old per-platform behaviour - explicitly documented as "metrics may differ for the same font file on different platforms") andportable(same metrics everywhere, based on thesTypometrics - i.e. the same table family our harmonisation aligned everything to).portableis the default for the newFontOptionsAPI.legacysurvives only for the deprecatedFontconstructors. JUCE 9 (released three days ago) carries that forward. So the divergence we measured isn't just fixed upstream - it's acknowledged as a framework bug with a designed migration path.2. Submitting a JUCE 6 fix to JUCE is a non-starter. It's 2 major versions EOL. Fixed in JUCE 8 anyway.
3. Would a fix even be accepted, considering it's technically the font at fault?
JUCE 8 is the counterargument to that. The JUCE team looked at this exact situation and concluded the framework should absorb it. And our own data supports that: Google-shipped fonts (multiple Barlows and Michroma) carry disagreeing tables. When the ecosystem's most mainstream font foundry ships "broken" metrics, they're not broken - the platform-divergent reading of them is.
4. Submit a fix to HISE
This would technically be a fix to the current
JUCE_customizedsubmodule repo and I don't really want to go there. It's a heavily customised version of JUCE 6 and sounds like at some point Christoph will move to JUCE 9 (judging by previous comments), possibly inheriting the fix anyway, so I wouldn't know where to start with this.I'm happy to leave all this here with a note to @Christoph-Hart that if he wants to take this on I'm sure we would all appreciate it but it feels too messy/convoluted for me to take on right now.
-
Update: Claude-generated gist here of the suggested patch: https://gist.github.com/weavermedia/3fc4a419920fcda8de389a89d7aec68d