Repository navigation
Vertical metrics are mismatched between static fonts #308
Description
Activity
AFAIK, mastering files did not change the vertical metrics that were set in #273
Okay, thanks for commenting! Still have to properly chase this down; will be trying to do so today or tomorrow.
This issue is weirder that I expected, and it may be a problem in Sketch or macOS.
Initial findings
If I use
ttxto access theOS/2andhheatables of Recursive Mono Linear ExtraBold vs Recursive Mono Casual ExtraBold, then compare the two files, I cannot find any differences related to vertical metrics.A test webpage with very simple CSS shows that both fonts align with consistency: https://arrowtype.github.io/recursive/vertical-metrics/
(Ironically, these fonts do not contain a
vmtxtable, a description of which I used for the text in that web test).Oh, actually, I am finding that even back in v 1.030, this vertical metrics issue was hiding.
It is also slightly stranger than expected. In the Linear styles, Medium–ExtraBold instances get the strange line-heights, but Light–Regular and Black–ExtraBlack instances do not. This happens both for Mono and Sans sub-families.
I get the exact same result in v1.036.
My best guess is, an ascender or descender (potentially the
g) gets a little bit longer from the Light to the the ExtraBold master, but is more compact in the ExtraBlack master. This happens with thegdescender.If I look at the yMin and yMax for three OTF outputs, I get this:
{'Recursive Mono Linear ExtraBlack': { 'yMax': (1175, 'uni0306_hookabovecomb'), 'yMin': (-426, 'uni1EF5.italic')}, 'Recursive Mono Linear ExtraBold': { 'yMax': (1156, 'uni1E4C'), 'yMin': (-408, 'uni1EF5.italic')}, 'Recursive Mono Linear Light': { 'yMax': (1125, 'uni0306_uni0300'), 'yMin': (-363, 'uni02CC')}}The main thing takeaway I get from this is that values decrease from ExtraBlack to Light, with no bigger values in the ExtraBold instance. So, there's no glyph bounds that would suggest line-height is being calculated as needing to be "bigger" in the middle instances.
If I limit the check to only basic Latin characters (just in case Sketch / macOS is checking a simple letter's bounds and calculating the base lineHeight from there), I find something similar.
{ 'Recursive Mono Linear ExtraBlack': { 'yMax': (812, 'i'), 'yMin': (-200, 'y')}, 'Recursive Mono Linear ExtraBold': { 'yMax': (802, 'j'), 'yMin': (-250, 'g')}, 'Recursive Mono Linear Light': { 'yMax': (760, 'f'), 'yMin': (-250, 'g')} }RoboFont script used to check yMin and yMax (Click to expand)
Dropdown details
import pprint af = AllFonts() minMaxY = {} glyphsToCheck = 'A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z'.split() print(glyphsToCheck) for f in af: fontname = f.info.familyName + ' ' + f.info.styleName if fontname not in minMaxY.keys(): minMaxY[fontname] = {'yMin': (0,''), 'yMax': (0,'')} for name in glyphsToCheck: try: yMin = f[name].bounds[1] yMax = f[name].bounds[3] if yMin <= minMaxY[fontname]['yMin'][0]: minMaxY[fontname]['yMin'] = (yMin, name) if yMax >= minMaxY[fontname]['yMax'][0]: minMaxY[fontname]['yMax'] = (yMax, name) except: pass pp = pprint.PrettyPrinter(depth=3) pp.pprint(minMaxY)The bounding box shouldn't have anything to do with it, just the
OS/2andhheavalues, unless Sketch is doing something odd.- Some systems do use the bounding box - such as Android
I've also heard that Adobe apps set the first baseline based on the ascender of
d(setting it to the top of the text box).This isn't surprising, but just as a data point to show this isn't something specific to only Sketch, I have found this to also be present in other macOS, CoreText-using apps like Keynote & Pages:
Using font-line and fdiff, I'm finding no differences in vertical metrics that would explain this. Am I just missing something?
Worth noting: in the two fonts below, ExtraBlack has greater yMax and yMin
headvalues, but doesn't have the excessive line height issue. Maybe there's some kind of interaction between these values and font weight, or some other unexpected interaction causing this?I can use fdiff to compare Casual and Linear ExtraBold, which should have nearly the same values for everything aside from specific contours – however, what tables might be relevant to such a search?
fonts_1.036/Static_OTF/RecursiveMonoLnr-ExtraBold.otf | fonts_1.036/Static_OTF/RecursiveMonoLnr-XBlk.otf | :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: Metrics | Metrics :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: [head] Units per Em: 1000 | [head] Units per Em: 1000 [head] yMax: 1156 | [head] yMax: 1175 [head] yMin: -408 | [head] yMin: -426 [OS/2] CapHeight: 700 | [OS/2] CapHeight: 700 [OS/2] xHeight: 540 | [OS/2] xHeight: 550 [OS/2] TypoAscender: 950 | [OS/2] TypoAscender: 950 [OS/2] TypoDescender: -250 | [OS/2] TypoDescender: -250 [OS/2] WinAscent: 1207 | [OS/2] WinAscent: 1207 [OS/2] WinDescent: 271 | [OS/2] WinDescent: 271 [hhea] Ascent: 950 | [hhea] Ascent: 950 [hhea] Descent: -250 | [hhea] Descent: -250 | [hhea] LineGap: 0 | [hhea] LineGap: 0 [OS/2] TypoLineGap: 0 | [OS/2] TypoLineGap: 0 | :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: Ascent to Descent Calculations | Ascent to Descent Calculations :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: [hhea] Ascent to Descent: 1200 | [hhea] Ascent to Descent: 1200 [OS/2] TypoAscender to TypoDescender: 1200 | [OS/2] TypoAscender to TypoDescender: 1200 [OS/2] WinAscent to WinDescent: 1478 | [OS/2] WinAscent to WinDescent: 1478 | :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: Delta Values | Delta Values :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: [hhea] Ascent to [OS/2] TypoAscender: 0 | [hhea] Ascent to [OS/2] TypoAscender: 0 [hhea] Descent to [OS/2] TypoDescender: 0 | [hhea] Descent to [OS/2] TypoDescender: 0 [OS/2] WinAscent to [OS/2] TypoAscender: 257 | [OS/2] WinAscent to [OS/2] TypoAscender: 257 [OS/2] WinDescent to [OS/2] TypoDescender: 21 | [OS/2] WinDescent to [OS/2] TypoDescender: 21 | :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: Baseline to Baseline Distances | Baseline to Baseline Distances :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: hhea metrics: 1200 | hhea metrics: 1200 typo metrics: 1200 | typo metrics: 1200 win metrics: 1478 | win metrics: 1478 | [OS/2] fsSelection USE_TYPO_METRICS bit set: True | [OS/2] fsSelection USE_TYPO_METRICS bit set: True | :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: Ratios | Ratios :::::::::::::::::::::::::::::::::::::::::::::::::: | :::::::::::::::::::::::::::::::::::::::::::::::::: hhea metrics / UPM: 1.2 | hhea metrics / UPM: 1.2 typo metrics / UPM: 1.2 | typo metrics / UPM: 1.2 win metrics / UPM: 1.48 | win metrics / UPM: 1.48Aside from very minor differences in
yMinandyMax, Casual & Linear fonts have very little difference between them, from what I can tell:▶ fdiff fonts_1.036/Static_OTF/RecursiveMonoLnr-ExtraBold.otf fonts_1.036/Static_OTF/RecursiveMonoCsl-ExtraBd.otf --include head,hhea,OS/2 -c --- fonts_1.036/Static_OTF/RecursiveMonoLnr-ExtraBold.otf 2020-01-28T23:19:29.067990-07:00 +++ fonts_1.036/Static_OTF/RecursiveMonoCsl-ExtraBd.otf 2020-01-28T23:18:37.616959-07:00 @@ -5,16 +5,16 @@ <!-- Most of this table will be recalculated by the compiler --> <tableVersion value="1.0"/> <fontRevision value="1.036"/> - <checkSumAdjustment value="0x496e3041"/> + <checkSumAdjustment value="0x274039b9"/> <magicNumber value="0x5f0f3cf5"/> <flags value="00000000 00000011"/> <unitsPerEm value="1000"/> - <created value="Tue Jan 28 23:15:41 2020"/> - <modified value="Wed Jan 29 06:19:29 2020"/> - <xMin value="-322"/> - <yMin value="-408"/> - <xMax value="2360"/> - <yMax value="1156"/> + <created value="Tue Jan 28 23:14:57 2020"/> + <modified value="Wed Jan 29 06:18:37 2020"/> + <xMin value="-280"/> + <yMin value="-405"/> + <xMax value="2355"/> + <yMax value="1164"/> <macStyle value="00000000 00000000"/> <lowestRecPPEM value="3"/> <fontDirectionHint value="2"/> @@ -28,9 +28,9 @@ <descent value="-250"/> <lineGap value="0"/> <advanceWidthMax value="2400"/> - <minLeftSideBearing value="-322"/> - <minRightSideBearing value="-422"/> - <xMaxExtent value="2360"/> + <minLeftSideBearing value="-280"/> + <minRightSideBearing value="-349"/> + <xMaxExtent value="2355"/> <caretSlopeRise value="1"/> <caretSlopeRun value="0"/> <caretOffset value="0"/> @@ -63,14 +63,14 @@ <sFamilyClass value="0"/> <panose> <bFamilyType value="2"/> - <bSerifStyle value="11"/> + <bSerifStyle value="15"/> <bWeight value="9"/> <bProportion value="9"/> - <bContrast value="4"/> - <bStrokeVariation value="2"/> + <bContrast value="5"/> + <bStrokeVariation value="5"/> <bArmStyle value="2"/> <bLetterForm value="4"/> - <bMidline value="2"/> + <bMidline value="3"/> <bXHeight value="4"/> </panose> <ulUnicodeRange1 value="00100000 00000000 00000000 00000111"/>
My best guess is that we might be able to use CTLineBoundsOptions in Swift to peer into what CoreText gets for leading values. However, I don't know the first thing about using Swift.
from font bakery
OS/2.usWinDescent value should be equal or greater than 363, but got 271 instead [code: descent], just to note- changed the title
[-]Vertical metrics are mismatched between fonts in v1.036[/-][+]Vertical metrics are mismatched between static fonts[/+]on Apr 19, 2020 5 remaining items
Just to note this down, I’ve used the script src/01-shell-scripts-for-sources/metrics/find-min_max_y_vals.py to check for the yMin & yMax of the sources:
maxY of UFOs in mastering/build/src is 1208 Font with maxY is Recursive Mono Casual C Slanted in brevecomb_hookabovecomb minY of UFOs in mastering/build/src is -455 Font with minY is Recursive Sans Linear C Slanted in ydotbelow.italicInterestingly, the yMin & yMax in the fonts is not quite 1208 and -455, so I had to also search for the specific yMin/yMax. In several of the sources:
- Abreveacute goes to 1125
- verticallinelowmod goes to -363
I found that if I follow SF Pro’s lead and set ascenders & descenders to be set for the overall text box rather than for the general letterforms, and do the following...
OS/2.usWinAscent,OS/2.sTypoAscender, &hhea.ascentto950OS/2.sTypoDescender, &hhea.descentto-250OS/2.usWinDescentto250
...it works nicely for the variable font, but doesn’t work for the static fonts. :|
Maybe different PANOSE values could affect this? IBM Plex has a smaller text box than total Vietnamese accents, and it seems to work fine.
Comparing the PANOSE values of IBM Plex Sans against Recursive Linear Sans:
<panose> <bFamilyType value="2"/> <bSerifStyle value="11"/> <bWeight value="8"/> - <bProportion value="3"/> - <bContrast value="5"/> + <bProportion value="4"/> + <bContrast value="4"/> <bStrokeVariation value="2"/> - <bArmStyle value="3"/> - <bLetterForm value="0"/> + <bArmStyle value="2"/> + <bLetterForm value="4"/> <bMidline value="2"/> - <bXHeight value="3"/> + <bXHeight value="4"/> </panose>Meanings are documented in Apple TrueType docs.
Dimension Plex Recursive bProportion 3 (Modern) 4 (Even Width) bContrast 5 (Medium Low) 4 (Low) bArmStyle 3 (Straight Arms/Wedge) 2 (Straight Arms/Horizontal) bLetterForm 0 (Any) 4 (Normal/Boxed) bXHeight 3 (Constant/Standard) 4 (Constant/Large) ...but even if I just copy-paste the IBM Plex panose values into Recursive, the static fonts still have inconsistent line heights.
I think this means I have to change some glyph shaping (like the /verticallinelowmod) to see whether that will affect line heights.
Before I try adjusting glyph sizing, I’m trying a simpler/stupider approach: I’ve made a copy of a build-prepped directory, and I’m removing almost all glyphs from these. I will then build fonts from them, and see whether the issues are solved. If the issues are solved, it will be a good indication that the issue is in the glyph sizing. If the issues persist ... I’ll have to keep thinking.
Okay, that brute-force subset actually worked better than expected!
I limited the fonts to just A–Z, a–z, 0–9. (I also messed up an eliminated i & j, which are composed from idotless, jdotless, & dotcomb.) I removed VF rules (rvrn) and other features. I changed the family name to make it simple to find in a menu. After that – and without changing other font info – the line heights are working as expected. To me, this suggests that tall metrics probably are forcing the awkward text box heights and inconsistencies.
I’ve just tested with a VF so far, so I’ll also build statics and see whether the line heights are similar there. If so, I’ll move on to more-surgical adjustments of glyph sizing in the fonts.
Sketch:
Keynote:
Amazingly, just by removing /verticallinelowmod, the (variable) fonts work almost perfectly:
But, it is still messing up in Keynote:
So, this is further indication that extreme glyph boundaries are probably causing the line-height discrepancies. Next, I’ll try to remove/edit Vietnamese caps, to see whether that completes this solution.
I’ve installed macOS 11 (Big Sur) on an external SSD, and I’ve found that line-height issues in
v1.073are resolved in TextEdit & Sketch, but still a problem in Keynote.So, this doesn’t really change anything: the next logical step is to try lowering Vietnamese accents for uppercase letters, and seeing whether this produces even line heights.
Gotta say the play-by-play is equal parts educational and entertaining. Looking forward to the next posts! :-)
Reacted by Stephen NixonFYI, I have an idea on this that I need to test. It might be caused by the Panose values.
The above idea; scratch it. When I was looking for differences, Panose was all I found, but I that's a dead end.
Reacted by Stephen NixonOkay, I think I’ve found the answer!
Testing showed that if the height of single-accented caps stays below the
hhea.ascent, line heights work as expected.I have adjusted the
.caseaccents of the Linear ExtraBold sources to stay below950, and things are now working as desired. Previously, some were a bit higher than this, so interpolated heights were causing the strange layout results from Medium to ExtraBold.This is in addition to removing the extra-low
verticallinemod, so I believe that this also probably as an effect.Sketch:
Keynote:
So, luckily, I don’t have to change all of the Vietnamese accents. I did the tests so far in git-ignored "build-prepped" sources, so my remaining steps here are:
- adjust
.caseaccents in sources to stay below hhea.ascent (950) -
adjust thenot neededverticallinemodin sources to stay above descender - build into static fonts to confirm that solution works for statics, as well
- test statics in Figma
- rebuild & release!
- adjust
Static font testing
After adjusting the .case accents to stay under
950units (not including Vietnamese, which go taller), I’ve built both Static & Variable fonts (permalink), then tested them in macOS Catalina (10.15.5). I was aiming for consistent line heights between all Casual & Linear styles, and vertically-centered uppercase letters (to make button text, icon labels, and general UI look centered by default).✅ Things look good in Sketch:
✅ Things look good in Keynote:
✅ Things look good in Figma:
I’m just about to package these into a new release, and I will be able to close this issue.
- added a commit that references this issue
on Feb 14, 2021 Released!





















Problem description
I'm getting an unexpected difference in the default line-heights of only a few static instances of Recursive. (Not currently sure if this is the case in Recursive variable, but I'll check).
This is a regression of metrics that were fixed earlier. Details at:#273
I believe this was impacted by the merging of mastering scripts, which follow the official Google Fonts metrics guidelines. Unfortunately, these guidelines are not very useful for a UI font.UPDATE: nope; I just hadn't caught this specific problem earlier.
Expected behavior
Vertical metrics should match what is currently (or appear to be) in Recursive Mono Casual, not Recursive Mono Linear.
They should:
Environment (please complete the following information):
Additional context
[Will try to fill in specific commits that affected this, if useful.]