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' .
This commit is contained in:
Eli Zaretskii 2021-05-27 12:24:29 +03:00
parent 7f11dea662
commit c82afdcc88

View 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);
font_width = FRAME_COLUMN_WIDTH (f);
default_font = Fface_font (Qdefault, Qnil, Qnil);
frame_font = Fframe_parameter (Qnil, Qfont);
if (NILP (g))
break;
thiswidth += char_width (LGLYPH_CHAR (g), dp);
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;