]> git.eshelyaron.com Git - emacs.git/commitdiff
A better fix for 'string-width'
authorEli Zaretskii <eliz@gnu.org>
Thu, 27 May 2021 09:24:29 +0000 (12:24 +0300)
committerEli Zaretskii <eliz@gnu.org>
Thu, 27 May 2021 09:24:29 +0000 (12:24 +0300)
* src/character.c (lisp_string_width): Compute the width when
automatic compositions can happen more accurately, by using the
pixel widths of the grapheme clusters, divided by the default
face's font width.  Disregard the current state of
'auto-composition-mode', for consistency with 'current-column' .

src/character.c

index e0978bb39fa9a5d5e692aa9b6d69e33e58c45eef..5753e883c320ac19dac56503ac46d324c715f34b 100644 (file)
@@ -34,6 +34,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "character.h"
 #include "buffer.h"
+#include "frame.h"
 #include "dispextern.h"
 #include "composite.h"
 #include "disptab.h"
@@ -343,6 +344,14 @@ lisp_string_width (Lisp_Object string, ptrdiff_t from, ptrdiff_t to,
   ptrdiff_t from_byte = i_byte;
   ptrdiff_t width = 0;
   struct Lisp_Char_Table *dp = buffer_display_table ();
+#ifdef HAVE_WINDOW_SYSTEM
+  struct frame *f =
+    (FRAMEP (selected_frame) && FRAME_LIVE_P (XFRAME (selected_frame)))
+    ? XFRAME (selected_frame)
+    : NULL;
+  int font_width = -1;
+  Lisp_Object default_font, frame_font;
+#endif
 
   eassert (precision <= 0 || (nchars && nbytes));
 
@@ -361,23 +370,40 @@ lisp_string_width (Lisp_Object string, ptrdiff_t from, ptrdiff_t to,
          chars = end - i;
          bytes = string_char_to_byte (string, end) - i_byte;
        }
-      else if (!NILP (BVAR (current_buffer, enable_multibyte_characters))
-              && ! NILP (Vauto_composition_mode)
+#ifdef HAVE_WINDOW_SYSTEM
+      else if (f && FRAME_WINDOW_P (f)
+              && multibyte
               && find_automatic_composition (i, -1, &ignore, &end, &val, string)
               && end > i)
        {
-         int j;
-         for (thiswidth = 0, j = 0; j < LGSTRING_GLYPH_LEN (val); j++)
+         int pixelwidth = composition_gstring_width (val, 0,
+                                                     LGSTRING_GLYPH_LEN (val),
+                                                     NULL);
+         /* The below is somewhat expensive, so compute it only once
+            for the entire loop, and only if needed.  */
+         if (font_width < 0)
            {
-             Lisp_Object g = LGSTRING_GLYPH (val, j);
-
-             if (NILP (g))
-               break;
-             thiswidth += char_width (LGLYPH_CHAR (g), dp);
+             font_width = FRAME_COLUMN_WIDTH (f);
+             default_font = Fface_font (Qdefault, Qnil, Qnil);
+             frame_font = Fframe_parameter (Qnil, Qfont);
+
+             if (STRINGP (default_font) && STRINGP (frame_font)
+                 && (SCHARS (default_font) != SCHARS (frame_font)
+                     || SBYTES (default_font) != SBYTES (frame_font)
+                     || memcmp (SDATA (default_font), SDATA (frame_font),
+                                SBYTES (default_font))))
+               {
+                 Lisp_Object font_info = Ffont_info (default_font, Qnil);
+                 font_width = AREF (font_info, 11);
+                 if (font_info <= 0)
+                   font_width = AREF (font_info, 10);
+               }
            }
+         thiswidth = (double) pixelwidth / font_width + 0.5;
          chars = end - i;
          bytes = string_char_to_byte (string, end) - i_byte;
        }
+#endif /* HAVE_WINDOW_SYSTEM */
       else
        {
          int c;