From c82afdcc88442fcfb5ee076aef13dd9721a98192 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 27 May 2021 12:24:29 +0300 Subject: [PATCH] A better fix for 'string-width' * 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 | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/character.c b/src/character.c index e0978bb39fa..5753e883c32 100644 --- a/src/character.c +++ b/src/character.c @@ -34,6 +34,7 @@ along with GNU Emacs. If not, see . */ #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; -- 2.39.5