diff options
| author | Eli Zaretskii | 2025-10-27 15:54:10 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2025-10-27 15:54:10 +0200 |
| commit | 23d863357920d283b899fd3757ccfa387a95ffe6 (patch) | |
| tree | e35ab4c448f9fc0488714c770551c3c512dea58d /src | |
| parent | 42dab7e7855348abf2665acabddf737c3aec5de6 (diff) | |
| download | emacs-23d863357920d283b899fd3757ccfa387a95ffe6.tar.gz emacs-23d863357920d283b899fd3757ccfa387a95ffe6.zip | |
Avoid face inheritance cycles
* src/xfaces.c (face_inheritance_cycle): New function.
(Finternal_set_lisp_face_attribute): Signal an error if the
':inherit' attribute of a face is modified in a way that will
cause it to inherit from itself. (Bug#79672)
* test/src/xfaces-tests.el (xfaces-test-circular-inheritance): New
test.
* etc/NEWS: Announce the incompatible change.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xfaces.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/src/xfaces.c b/src/xfaces.c index 7626dfeb75c..ca1bee1d17a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -2426,6 +2426,60 @@ face_inherited_attr (struct window *w, struct frame *f, | |||
| 2426 | return attr_val; | 2426 | return attr_val; |
| 2427 | } | 2427 | } |
| 2428 | 2428 | ||
| 2429 | /* Chase the chain of inheritance for FACE on frame F, and return | ||
| 2430 | non-zero if FACE inherits from its CHILD face, directly or | ||
| 2431 | indirectly. FACE is either a symbol or a list of face symbols, which | ||
| 2432 | are two forms of values for the :inherit attribute of a face. CHILD | ||
| 2433 | must be a face symbol. */ | ||
| 2434 | static bool | ||
| 2435 | face_inheritance_cycle (struct frame *f, Lisp_Object face, Lisp_Object child) | ||
| 2436 | { | ||
| 2437 | Lisp_Object face_attrs[LFACE_VECTOR_SIZE]; | ||
| 2438 | Lisp_Object parent_face; | ||
| 2439 | bool ok, cycle_found = false; | ||
| 2440 | |||
| 2441 | eassert (SYMBOLP (child)); | ||
| 2442 | if (CONSP (face)) | ||
| 2443 | { | ||
| 2444 | Lisp_Object tail; | ||
| 2445 | for (tail = face; !NILP (tail); tail = XCDR (tail)) | ||
| 2446 | { | ||
| 2447 | ok = get_lface_attributes (NULL, f, XCAR (tail), face_attrs, | ||
| 2448 | false, NULL); | ||
| 2449 | if (!ok) | ||
| 2450 | break; | ||
| 2451 | parent_face = face_attrs[LFACE_INHERIT_INDEX]; | ||
| 2452 | if (EQ (parent_face, child)) | ||
| 2453 | cycle_found = true; | ||
| 2454 | else if (!NILP (parent_face) | ||
| 2455 | && !UNSPECIFIEDP (parent_face) | ||
| 2456 | && !IGNORE_DEFFACE_P (parent_face) | ||
| 2457 | && !RESET_P (parent_face)) | ||
| 2458 | cycle_found = face_inheritance_cycle (f, parent_face, child); | ||
| 2459 | if (cycle_found) | ||
| 2460 | break; | ||
| 2461 | } | ||
| 2462 | } | ||
| 2463 | else | ||
| 2464 | { | ||
| 2465 | eassert (SYMBOLP (face)); | ||
| 2466 | ok = get_lface_attributes (NULL, f, face, face_attrs, false, NULL); | ||
| 2467 | if (ok) | ||
| 2468 | { | ||
| 2469 | parent_face = face_attrs[LFACE_INHERIT_INDEX]; | ||
| 2470 | if (EQ (parent_face, child)) | ||
| 2471 | cycle_found = true; | ||
| 2472 | else if (!NILP (parent_face) | ||
| 2473 | && !UNSPECIFIEDP (parent_face) | ||
| 2474 | && !IGNORE_DEFFACE_P (parent_face) | ||
| 2475 | && !RESET_P (parent_face)) | ||
| 2476 | cycle_found = face_inheritance_cycle (f, parent_face, child); | ||
| 2477 | } | ||
| 2478 | } | ||
| 2479 | |||
| 2480 | return cycle_found; | ||
| 2481 | } | ||
| 2482 | |||
| 2429 | /* Merge the named face FACE_NAME on frame F, into the vector of face | 2483 | /* Merge the named face FACE_NAME on frame F, into the vector of face |
| 2430 | attributes TO. Use NAMED_MERGE_POINTS to detect loops in face | 2484 | attributes TO. Use NAMED_MERGE_POINTS to detect loops in face |
| 2431 | inheritance. Return true if FACE_NAME is a valid face name and | 2485 | inheritance. Return true if FACE_NAME is a valid face name and |
| @@ -3654,7 +3708,9 @@ FRAME 0 means change the face on all frames, and change the default | |||
| 3654 | for (tail = value; CONSP (tail); tail = XCDR (tail)) | 3708 | for (tail = value; CONSP (tail); tail = XCDR (tail)) |
| 3655 | if (!SYMBOLP (XCAR (tail))) | 3709 | if (!SYMBOLP (XCAR (tail))) |
| 3656 | break; | 3710 | break; |
| 3657 | if (NILP (tail)) | 3711 | if (face_inheritance_cycle (f, value, face)) |
| 3712 | signal_error ("Face inheritance results in inheritance cycle", value); | ||
| 3713 | else if (NILP (tail)) | ||
| 3658 | ASET (lface, LFACE_INHERIT_INDEX, value); | 3714 | ASET (lface, LFACE_INHERIT_INDEX, value); |
| 3659 | else | 3715 | else |
| 3660 | signal_error ("Invalid face inheritance", value); | 3716 | signal_error ("Invalid face inheritance", value); |