]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix monospace font calculations on macOS
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Wed, 12 Aug 2020 11:15:44 +0000 (13:15 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Wed, 12 Aug 2020 11:15:44 +0000 (13:15 +0200)
* 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.

src/macfont.m

index 21bc7dde5b3455cc05f21a05be7922a8f4efb6ec..c7430d327723c2386909057fb0d0732267b1177d 100644 (file)
@@ -1120,7 +1120,10 @@ struct macfont_metrics
      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 @@ enum metrics_status
 #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 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
       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 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
                                     / (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 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph,
                                  / (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 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction)
       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 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction)
 
       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);