Closed arrowtype closed 3 years ago
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 ttx
to access the OS/2
and hhea
tables 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 vmtx
table, 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 the g
descender.
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')}
}
The bounding box shouldn't have anything to do with it, just the OS/2
and hhea
values, 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 head
values, 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.48
Aside from very minor differences in yMin
and yMax
, 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
Tested this again with Catalina 10.15.5 & Sketch 68.2, and the problem still exists:
I don’t have a current way to test this in macOS 11, but I will try to do so soon.
FYI, I have an idea on this that I need to test. It might be caused by the Panose values.
Checking back on this.
Sans Linear Regular
vs Sans Linear Bold
)FWIW, a good fdiff
recipe to get mostly-probably-relevant details is:
fdiff --exclude glyf,cmap,hmtx,cvt RecursiveSansLnrSt-Regular.ttf RecursiveSansLnrSt-Bold.ttf
This is with the latest font release, 1.072
. Here is the Casual vs Linear, Reg vs Bold, showing that the Linear Bold sets at 70
, whereas the others default to 58
:
From #418, I determined that the family minY is -455, and the family maxY is 1208. I’ll overshoot this and make a glyph that is -500 to 1300, just to keep it obvious. If this works to make similar line-heights, I will re-check min & max Y values, then make a more-accurate glyph.
I’ll add the box-drawing character │
(U+2502), in case it makes a difference to make a character with a Unicode value. I’ll then build that into a TTF with fontmake, so I can merge that into usual TTFs, change the family names, then check those.
UPDATE:
I tried this at https://github.com/arrowtype/recursive/commit/e809fadd9870a85edbe0ee42ddbcc376dd8dd02d.
Even with this "flamethrower" approach to trying to brute-force the problem, the line-height discrepancies remain. Here are the two fonts (Linear Regular & Linear Bold) with a tall glyph (-500
to 1300
y values). So, I suppose this may indicate that either:
A mentor helped me find a (partial?) solution to this issue. In every font:
OS/2.usWinAscent
& hhea.ascent
to the highest point (1125
) across all styles OS/2.usWinDescent
& hhea.descent
to the lowest point across all styles (363
/-363
)OS/2.sTypoAscender
and OS/2.sTypoDescender
values to add up to UPM (800
and -200
, respectively). This is required to match line heights in Keynote.These values come from the head
table:
<unitsPerEm value="1000"/>
<yMin value="-363"/>
<yMax value="1125"/>
This approach does seem to fix the immediate issue, matching line heights across fonts:
However, a drawback of these specific values is that they result in fairly tall line heights. Compared to IBM Plex Sans and Apple SF Pro:
Another problem is that the font is no longer “vertically centered” in its default text box (centered on unaccented uppercase letters, which start most button text, UI labels, etc), which is desirable for a UI font. SF Pro seems to achieve this by having very squished Vietnamese accents, whereas IBM Plex just allows these to exceed the general text box:
But hopefully, maybe, this issue can probably be solved by reducing the highest & lowest points across the styles, then setting these values accordingly.
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.italic
Interestingly, 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:
Recursive’s /verticallinelowmod is too large, and should probably have zero-width spacing. SF Pro puts /verticallinelowmod only goes down to the descender:
Here is the current Recursive /verticallinelowmod:
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.ascent
to 950
OS/2.sTypoDescender
, & hhea.descent
to -250
OS/2.usWinDescent
to 250
...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:
Okay, I’ve confirmed that the super-basic character set also has working line heights in static 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.073
are 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! :-)
FYI, 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.
Okay, 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 .case
accents of the Linear ExtraBold sources to stay below 950
, 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:
.case
accents in sources to stay below hhea.ascent (950)verticallinemod
in sources to stay above descender~ not neededAfter adjusting the .case accents to stay under 950
units (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.
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: https://github.com/arrowtype/recursive/issues/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.]