Fix monospace font calculations on macOS

* src/macfont.m (macfont_monospace_width_multiplier): New function
to compute the width for monospace fonts (bug#24582).
(macfont_glyph_extents): Fix monospace glyph computation.
(macfont_shape): Ditto.
This commit is contained in:
YAMAMOTO Mitsuharu 2020-08-12 13:15:44 +02:00 committed by Lars Ingebrigtsen
parent 88567ca8ec
commit fdba95d2f8

View file

@ -1120,7 +1120,10 @@ sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
glyph width. The `width_int' member is an integer that is
closest to the width. The `width_frac' member is the fractional
adjustment representing a value in [-.5, .5], multiplied by
WIDTH_FRAC_SCALE. For synthetic monospace fonts, they represent
WIDTH_FRAC_SCALE. For monospace fonts, non-zero `width_frac'
means `width_int' is further adjusted to a multiple of the
(rounded) font width, and `width_frac' represents adjustment per
unit character. For synthetic monospace fonts, they represent
the advance delta for centering instead of the glyph width. */
signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
};
@ -1148,6 +1151,27 @@ sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
#define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f)
#define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
/* If FONT is monospace and WIDTH can be regarded as a multiple of its
width where the multiplier is greater than 1, then return the
multiplier. Otherwise return 0. */
static int
macfont_monospace_width_multiplier (struct font *font, CGFloat width)
{
struct macfont_info *macfont_info = (struct macfont_info *) font;
int multiplier = 0;
if (macfont_info->spacing == MACFONT_SPACING_MONO
&& font->space_width != 0)
{
multiplier = lround (width / font->space_width);
if (multiplier == 1
|| lround (width / multiplier) != font->space_width)
multiplier = 0;
}
return multiplier;
}
static int
macfont_glyph_extents (struct font *font, CGGlyph glyph,
struct font_metrics *metrics, CGFloat *advance_delta,
@ -1192,13 +1216,38 @@ sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
else
fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
/* For synthetic mono fonts, cache->width_{int,frac} holds the
advance delta value. */
if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
fwidth = (font->pixel_size - fwidth) / 2;
cache->width_int = lround (fwidth);
cache->width_frac = lround ((fwidth - cache->width_int)
* WIDTH_FRAC_SCALE);
if (macfont_info->spacing == MACFONT_SPACING_MONO)
{
/* Some monospace fonts for programming languages contain
wider ligature glyphs consisting of multiple characters.
For such glyphs, simply rounding the combined fractional
width to an integer can result in a value that is not a
multiple of the (rounded) font width. */
int multiplier = macfont_monospace_width_multiplier (font, fwidth);
if (multiplier)
{
cache->width_int = font->space_width * multiplier;
cache->width_frac = lround ((fwidth / multiplier
- font->space_width)
* WIDTH_FRAC_SCALE);
}
else
{
cache->width_int = lround (fwidth);
cache->width_frac = 0;
}
}
else
{
/* For synthetic mono fonts, cache->width_{int,frac} holds
the advance delta value. */
if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
fwidth = (font->pixel_size - fwidth) / 2;
cache->width_int = lround (fwidth);
cache->width_frac = lround ((fwidth - cache->width_int)
* WIDTH_FRAC_SCALE);
}
METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
}
if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
@ -1235,6 +1284,10 @@ sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
/ (CGFloat) (WIDTH_FRAC_SCALE * 2));
break;
case MACFONT_SPACING_MONO:
if (cache->width_frac)
bounds.origin.x += - ((cache->width_frac
/ (CGFloat) (WIDTH_FRAC_SCALE * 2))
* (cache->width_int / font->space_width));
break;
case MACFONT_SPACING_SYNTHETIC_MONO:
bounds.origin.x += (cache->width_int
@ -1271,7 +1324,16 @@ sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
/ (CGFloat) (WIDTH_FRAC_SCALE * 2)));
break;
case MACFONT_SPACING_MONO:
*advance_delta = 0;
if (cache->width_frac)
*advance_delta = 0;
else
{
CGFloat delta = - ((cache->width_frac
/ (CGFloat) (WIDTH_FRAC_SCALE * 2))
* (cache->width_int / font->space_width));
*advance_delta = (force_integral_p ? round (delta) : delta);
}
break;
case MACFONT_SPACING_SYNTHETIC_MONO:
*advance_delta = (force_integral_p ? cache->width_int
@ -3015,7 +3077,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
struct mac_glyph_layout *gl = glyph_layouts + i;
EMACS_INT from, to;
struct font_metrics metrics;
int xoff, yoff, wadjust;
int xoff, yoff, wadjust, multiplier;
if (NILP (lglyph))
{
@ -3068,7 +3130,11 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
xoff = lround (gl->advance_delta);
yoff = lround (- gl->baseline_delta);
wadjust = lround (gl->advance);
multiplier = macfont_monospace_width_multiplier (font, gl->advance);
if (multiplier)
wadjust = font->space_width * multiplier;
else
wadjust = lround (gl->advance);
if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
{
Lisp_Object vec = make_uninit_vector (3);