Skip to content

Vertical metrics are mismatched between static fonts #308

Description

@arrowtype

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).

image

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:

  • Roughly matching metrics in IBM Plex and Apple SF.
  • Make caps vertically centered within the default "box" of space in apps like Sketch, Keynote, and in web browsers. This helps buttons & UI elements to look good without fussy CSS nudges.

Environment (please complete the following information):

Additional context

[Will try to fill in specific commits that affected this, if useful.]

Activity

  1. benkiel commented on Feb 1, 2020

    @benkiel
    Collaborator

    AFAIK, mastering files did not change the vertical metrics that were set in #273

  2. arrowtype commented on Feb 3, 2020

    @arrowtype
    OwnerAuthor

    Okay, thanks for commenting! Still have to properly chase this down; will be trying to do so today or tomorrow.

  3. arrowtype commented on Feb 3, 2020

    @arrowtype
    OwnerAuthor

    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/

    image

    https://github.com/arrowtype/recursive/tree/1a1680256d89d6856f9e4eef06ceae247a804537/docs/vertical-metrics

    (Ironically, these fonts do not contain a vmtx table, a description of which I used for the text in that web test).

  4. arrowtype commented on Feb 3, 2020

    @arrowtype
    OwnerAuthor

    Oh, actually, I am finding that even back in v 1.030, this vertical metrics issue was hiding.

    image

    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.

    image

    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')}
    }
    
    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)
    
    
  5. benkiel commented on Feb 3, 2020

    @benkiel
    Collaborator

    The bounding box shouldn't have anything to do with it, just the OS/2 and hhea values, unless Sketch is doing something odd.

  6. davelab6 commented on Feb 4, 2020

    @davelab6
    Collaborator
  7. arrowtype commented on Feb 4, 2020

    @arrowtype
    OwnerAuthor

    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:

    image

    image

  8. arrowtype commented on Feb 4, 2020

    @arrowtype
    OwnerAuthor

    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                          
    
  9. arrowtype commented on Feb 4, 2020

    @arrowtype
    OwnerAuthor

    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"/>
  10. arrowtype commented on Feb 4, 2020

    @arrowtype
    OwnerAuthor

    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.

  11. benkiel commented on Feb 7, 2020

    @benkiel
    Collaborator

    from font bakery OS/2.usWinDescent value should be equal or greater than 363, but got 271 instead [code: descent], just to note

  12. changed the title [-]Vertical metrics are mismatched between fonts in v1.036[/-] [+]Vertical metrics are mismatched between static fonts[/+] on Apr 19, 2020
  13. arrowtype commented on Sep 1, 2020

    @arrowtype
    OwnerAuthor

    Tested this again with Catalina 10.15.5 & Sketch 68.2, and the problem still exists:

    image

    I don’t have a current way to test this in macOS 11, but I will try to do so soon.

  14. 5 remaining items

  15. arrowtype commented on Feb 11, 2021

    @arrowtype
    OwnerAuthor

    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:

    • Abreveacute goes to 1125
    • verticallinelowmod goes to -363
  16. arrowtype commented on Feb 11, 2021

    @arrowtype
    OwnerAuthor

    Recursive’s /verticallinelowmod is too large, and should probably have zero-width spacing. SF Pro puts /verticallinelowmod only goes down to the descender:

    image

    Here is the current Recursive /verticallinelowmod:

    image

  17. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    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.

  18. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    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.

  19. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    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:

    image

    Keynote:

    image

  20. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    Okay, I’ve confirmed that the super-basic character set also has working line heights in static fonts.

    Sketch:

    image

    Keynote:

    image

  21. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    Amazingly, just by removing /verticallinelowmod, the (variable) fonts work almost perfectly:

    image

    But, it is still messing up in Keynote:

    image

    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.

  22. arrowtype commented on Feb 12, 2021

    @arrowtype
    OwnerAuthor

    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. 

    image

    image

    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.

  23. kenmcd commented on Feb 13, 2021

    @kenmcd

    Gotta say the play-by-play is equal parts educational and entertaining. Looking forward to the next posts! :-)

  24. benkiel commented on Feb 13, 2021

    @benkiel
    Collaborator

    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.

  25. arrowtype commented on Feb 13, 2021

    @arrowtype
    OwnerAuthor

    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:

    image

    Keynote:

    image

    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 .case accents in sources to stay below hhea.ascent (950)
    • adjust the verticallinemod in sources to stay above descender not needed
    • build into static fonts to confirm that solution works for statics, as well
    • test statics in Figma
    • rebuild & release!
  26. arrowtype commented on Feb 14, 2021

    @arrowtype
    OwnerAuthor

    Static font testing

    After 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:

    image

    ✅ Things look good in Keynote:

    image

    ✅ Things look good in Figma:

    image

    I’m just about to package these into a new release, and I will be able to close this issue.

  27. arrowtype commented on Feb 14, 2021

    @arrowtype
    OwnerAuthor

    Released!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

aug-2020Issues open as of August 2020 [for planning purposes]

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions