Skip to content

cairo: report the cap height and measure the x-height - #243

Merged
fredkiefer merged 1 commit into
gnustep:masterfrom
probonopd:fix-cairo-cap-height
Sep 28, 2026
Merged

fredkiefer merged 1 commit into
gnustep:masterfrom
probonopd:fix-cairo-cap-height

Conversation

@probonopd

@probonopd probonopd commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

On the cairo backend -[NSFont capHeight] is 0 for every font, and -xHeight is a fixed 60 percent of the ascender rather than the font's own value. Anything that centres a line of text on one of these metrics, a table cell or a custom control drawing its own label, then sits several points too high. Seen with a hand-drawn source list cell whose labels were visibly above the row centre.

Reproducer, a small tool printing the metrics of three fonts:

#import <AppKit/AppKit.h>
int main(void)
{
  @autoreleasepool
    {
      [NSApplication sharedApplication];
      for (NSFont *f in @[[NSFont systemFontOfSize: 13],
                          [NSFont boldSystemFontOfSize: 11],
                          [NSFont userFontOfSize: 12]])
        printf("%s %g: ascender %.2f descender %.2f capHeight %.2f xHeight %.2f\n",
               [[f fontName] UTF8String], [f pointSize], [f ascender],
               [f descender], [f capHeight], [f xHeight]);
    }
  return 0;
}

Before (master, Inter as the system font):

Inter-Medium 13: ascender 12.59 descender -3.14 capHeight 0.00 xHeight 7.56
Inter-Bold 11: ascender 10.66 descender -2.65 capHeight 0.00 xHeight 6.39
Inter-Medium 12: ascender 11.62 descender -2.89 capHeight 0.00 xHeight 6.97

After:

Inter-Medium 13: ascender 12.59 descender -3.14 capHeight 9.46 xHeight 7.10
Inter-Bold 11: ascender 10.66 descender -2.65 capHeight 8.00 xHeight 6.00
Inter-Medium 12: ascender 11.62 descender -2.89 capHeight 8.73 xHeight 6.55

Inter's cap height is 0.727 em, so 9.46 at 13 points is the real value, and its x-height is 0.546 em, so the old estimate was 6 percent high. The change takes both from cairo_scaled_font_text_extents of "H" and "x" on the scaled font, which works for every face cairo renders, and keeps the old estimate for the x-height only when the face has no "x" glyph.

The second commit fixes -boundingRectForGlyph: on the same backend, which returned cairo's y-down extents unchanged: y_bearing is the top of the ink measured downwards from the origin, so the rect sat below the baseline in the font's y-up coordinates, unlike the Xlib and Xft backends, which return the origin at the bottom of the ink. Same tool, printing the rect of four glyphs of the 13 point system font, before:

H: origin (1.05, -9.46) size (7.59 x 9.46)
x: origin (0.36, -7.10) size (6.52 x 7.10)
g: origin (0.61, -7.19) size (6.51 x 9.99)
p: origin (0.94, -7.19) size (6.49 x 9.84)

After:

H: origin (1.05, 0.00) size (7.59 x 9.46)
x: origin (0.36, 0.00) size (6.52 x 7.10)
g: origin (0.61, -2.81) size (6.51 x 9.99)
p: origin (0.94, -2.65) size (6.49 x 9.84)

The origin is now -(y_bearing + height): the bottom of the ink, 2.81 points below the baseline for the descender of g, on the baseline for H and x.

cc @pkgdemon

CairoFontInfo never set capHeight, so -[NSFont capHeight] returned 0 for
every font on the cairo backend, and xHeight was estimated as 60 percent
of the ascender, which is off by 10 to 15 percent for common faces.
Both are now taken from the extents of the letters H and x of the scaled
font, so applications that centre text on one of these metrics place it
where the eye expects.
probonopd added a commit to gershwin-desktop/gershwin-developer that referenced this pull request Sep 28, 2026
On the cairo backend -[NSFont capHeight] was always 0 and -xHeight a
guess of 60 percent of the ascender, so any table cell or control that
centres its text on one of those metrics drew it several points too high;
the AppGarden sidebar showed it plainly. The patch takes both values from
the extents of the letters H and x of the scaled font, which works for
every face cairo renders. Sent upstream as gnustep/libs-back#243; the
stripped diff and the PR text sit next to the patch.
Comment thread Source/cairo/CairoFontInfo.m
@fredkiefer
fredkiefer merged commit 9731f15 into gnustep:master Sep 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants