summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2026-05-28 18:36:11 +0300
committerEli Zaretskii <eliz@gnu.org>2026-05-28 18:36:11 +0300
commit7ee33143981199184e8b12db12ed7d0a26b947f5 (patch)
tree1e1a3d8d23dd60bd3f90eac9bdebfb1ee900ef4b /src
parent833553dd9aec0072961a7f1a7797f9481855a07f (diff)
Speed-up cursor motion under 'display-line-numbers-mode'
* src/xfaces.c (Finternal_lisp_face_equal_p): Accept an additional optional argument INHERIT; if non-nil, consider two faces equal if one inherits from the other and doesn't specify any other attributes to be different from it. * src/xdisp.c (try_cursor_movement, try_window_id): Call 'Finternal_lisp_face_equal_p' with non-nil INHERIT argument, to speed up redisplay in the default case when line numbers are shown. (Bug#81133) * test/src/xfaces-tests.el (xfaces-test-face-equality): New test.
Diffstat (limited to 'src')
-rw-r--r--src/xdisp.c4
-rw-r--r--src/xfaces.c49
2 files changed, 48 insertions, 5 deletions
diff --git a/src/xdisp.c b/src/xdisp.c
index 1691bd0d80e..dabe63b902a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -19856,7 +19856,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
&& !(!NILP (Vdisplay_line_numbers)
&& NILP (Finternal_lisp_face_equal_p (Qline_number,
Qline_number_current_line,
- w->frame)))
+ w->frame, Qt)))
/* This code is not used for mini-buffer for the sake of the case
of redisplaying to replace an echo area message; since in
that case the mini-buffer contents per se are usually
@@ -22657,7 +22657,7 @@ try_window_id (struct window *w)
|| (!NILP (Vdisplay_line_numbers)
&& NILP (Finternal_lisp_face_equal_p (Qline_number,
Qline_number_current_line,
- w->frame))))
+ w->frame, Qt))))
GIVE_UP (24);
/* composition-break-at-point is incompatible with the optimizations
diff --git a/src/xfaces.c b/src/xfaces.c
index 73d475c757f..fcec00fbc1f 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -4527,12 +4527,16 @@ lface_equal_p (Lisp_Object *v1, Lisp_Object *v2)
DEFUN ("internal-lisp-face-equal-p", Finternal_lisp_face_equal_p,
- Sinternal_lisp_face_equal_p, 2, 3, 0,
+ Sinternal_lisp_face_equal_p, 2, 4, 0,
doc: /* True if FACE1 and FACE2 are equal.
If the optional argument FRAME is given, report on FACE1 and FACE2 in that frame.
If FRAME is t, report on the defaults for FACE1 and FACE2 (for new frames).
-If FRAME is omitted or nil, use the selected frame. */)
- (Lisp_Object face1, Lisp_Object face2, Lisp_Object frame)
+If FRAME is omitted or nil, use the selected frame.
+Optional fourth argument INHERIT, if non-nil, means the faces
+are considered equal if one inherits from the other in a way
+that makes them have the same attributes when used on display. */)
+ (Lisp_Object face1, Lisp_Object face2, Lisp_Object frame,
+ Lisp_Object inherit)
{
bool equal_p;
struct frame *f;
@@ -4548,6 +4552,45 @@ If FRAME is omitted or nil, use the selected frame. */)
lface2 = lface_from_face_name (f, face2, true);
equal_p = lface_equal_p (XVECTOR (lface1)->contents,
XVECTOR (lface2)->contents);
+ if (!(NILP (inherit) || equal_p))
+ {
+ /* The below is a subset of merging the descendant face with its
+ parent(s). We only consider a direct inheritance (so no FACE1
+ that inherits from some other face which inherits from FACE2),
+ and the values of :inherit that are lists are not considered.
+ This is enough in simple cases such as the line-number-current
+ face that inherits from line-number. */
+ Lisp_Object attrs1[LFACE_VECTOR_SIZE], attrs2[LFACE_VECTOR_SIZE];
+ int i;
+ equal_p = true;
+ memcpy (attrs1, xvector_contents (lface1), sizeof attrs1);
+ memcpy (attrs2, xvector_contents (lface2), sizeof attrs2);
+ /* If either face inherits from the other one, and all the other
+ face attributes of the inheriting face are either unspecified
+ or equal to those of the parent face, consider the faces equal. */
+ if (EQ (attrs1[LFACE_INHERIT_INDEX], face2))
+ {
+ for (i = 1; i < LFACE_VECTOR_SIZE && equal_p; ++i)
+ {
+ if (i == LFACE_INHERIT_INDEX)
+ continue;
+ equal_p = face_attr_equal_p (attrs1[i], attrs2[i])
+ || UNSPECIFIEDP (attrs1[i]);
+ }
+ }
+ else if (EQ (attrs2[LFACE_INHERIT_INDEX], face1))
+ {
+ for (i = 1; i < LFACE_VECTOR_SIZE && equal_p; ++i)
+ {
+ if (i == LFACE_INHERIT_INDEX)
+ continue;
+ equal_p = face_attr_equal_p (attrs1[i], attrs2[i])
+ || UNSPECIFIEDP (attrs2[i]);
+ }
+ }
+
+ }
+
return equal_p ? Qt : Qnil;
}