Package: emacs-gtk
Version: 1:29.1+1-5
Severity: important
Tags: patch
X-Debbugs-Cc: creic...@gmail.com
Dear Maintainer,
(This is a resubmission; the previous bug may have been lost to spam
filtering.)
As of the upgrade to 29.1 on 2023-09-06, Emacs seems to be
disregarding some user preferences for the font for the "default"
face.
* What led up to the situation?
The upgrade to Emacs 29.1 on 2023-09-06.
* What exactly did you do (or not do) that was effective (or ineffective)?
Executing the following steps:
- (customize-face 'default)
- Font Family: setting "Terminus (TTF)"
- Font Foundry: setting "PfEd"
- Optionally (does not affect outcome):
- Weight: setting "medium"
- Disabling any font attributes (inlcuding Weight)
- [Apply]
Equivalently:
(custom-set-faces
'(default ((t (:inherit nil :extend nil :stipple nil :background "black"
:foreground "white" :inverse-video nil :box nil :strike-through nil :overline
nil :underline nil :slant normal :weight medium :height 120 :width normal
:foundry "PfEd" :family "Terminus (TTF)"
)
* What was the outcome of this action?
Emacs used the "Purisa" font as default font. This font has the same Font
Foundry as "Terminus (TTF)" but is a "Comic Sans"-like special-purpose font
and unsuitable for normal operations.
* What outcome did you expect instead?
I expected Emacs 29.1 to honour my configuration settings, as Emacs 28 did
before.
* Observations
- This only affects the default face. Based on my attempte to debug the
problem (see below), the bug is caused by special treatment for the
default face.
- This bug is likely related to #1029710, which was reported at the same
time as my original (regrettably spam-filtered?) report.
- I have narrowed down the bug somewhat (see below) and am using a
local workaround.
- This issue affects emacs-gtk and emacs-pgtk equally.
- This issue affects X11 and wayland equally.
* Debugging results
** Why this seems to happen
Here is the flow of events that leads to the problem, to the best of
my (very limited) understanding:
1. At some point, the font spec for the default face is set up
2. I set my preferences for the default face
3. My preferences are applied to the default face spec in some order
4. During "Font Family" selection, the following happens at some point:
a) While searching for suitable fonts, Emacs calls font_list_entities(f, spec)
b) font_list_entities(f, spec) (font.c, L2540) does some
preprocessing and then:
1. asks the driver for a list `vec' of suitable fonts (L2585)
2. and filters out unsuitable fonts (L2602), calling
c) font_delete_unmatched(vec, spec, size) in turn scans the `vec' to
remove elements that don't match `spec'.
1. Specifically, for properties like font weight
(FONT_WEIGHT_INDEX), L2486 checks if the requested property is
an exact match and otherwise removes the candidate (L2502).
2. I assume that L2477 skips checks for properties that are left
unconstrained (nil) in the spec but have not verified that.
The unexpected behaviour happens at 4.c:
4.c.2 always seems to allow filtering by font weight, no matter what I
select in the font face
4.c.1 always seems to require a font weigth of 80 ("regular"), no
matter what I select in the font face interface.
I have tried to investigate further to check:
- Does the wrong weight come from a hardcoded value?
- Does the wrong weight come from a stale font spec attribute?
*** Hardcoded value?
I tried modifying the `font_weights' table in font.c, but was only
able to "fix" the behaviour by entirely removing the entry for
weight 80. My interpretation is that the value "80" probably comes
from one of the default fallback fonts and is accidentally retained in
the font spec (i.e., the weight doesn't seem to be hardcoded
anywhere in Emacs).
*** Stale font attribute?
I traced the calls to `internal-set-lisp-face-attribute' immediately
after updating the font. Below is the order in which the attributes
are set (some appear more than once):
:underline
:overline
:strike-through
:box
:inverse-video
:stipple
:inherit
:extend
:family
:foundry
:inherit
:extend
:stipple
:background
:foreground
:inverse-video
:box
:strike-through
:overline
:underline
:slant
:weight
:height
:width
Note how :family is set before :weight is updated (to the correct
value):
- After setting :family, the font spec is associated with a font
object for the "Purisa" font, but at least retains :family
(of the font that I requested).
- Once :weight is updated, internal-set-lisp-face-attribute calls
set_font_frame_param(), at which point :family becomes "nil".
My current interpretation (based on the above) is that
font_list_entities() gets called after the "Font Family" entry has
been updated in the `spec' but before the weight is updated; instead,
the spec probably inherits the weight of the current font for the
default face,