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, as associated with the current frame.  Since that weight
is different from the weight of the font I requested,
font_delete_unmatched() kicks that font out.

*** How should this be fixed?

I don't understand enough of the rationale behind the font selection
logic to propose a fix.  Changing the order in which font spec entries
are updated _might_ fix the problem, but there is some special-case
handling for the default font that I haven't wrapped my head around.

*** Threats to validity

The above is based on some manual tracing, and I may have made
mistakes while logging.  I am also unfamiliar with the Emacs internals
and font selection algorithm.

** Why this didn't happen before

I previously used the "Terminus" bitmap font, which is no longer
supported due to limitations in the GTK-based font renderer (ftcrhb).
Older Emacs versions might still have behaved "more correctly" due to
the presence of the X font renderer (which is no longer included, to
my understanding).

This bug report is unrelated to the question of whether Emacs should
or should not support bitmap fonts.

** My current workaround

My current workaround replicates a pre-existing Windows NT kludge and
allows fonts to be considered "matching" if the differences in font
weight are small:

=====================================================================
--- emacs-29.1+1/src/font.c     2023-07-30 15:32:46.000000000 +0000
+++ emacs-kludge/src/font.c     2023-09-08 21:03:11.584666482 +0000
@@ -2484,6 +2484,8 @@
                 int candidate = XFIXNUM (AREF (entity, prop)) >> 8;
 
                 if (candidate != required
+                       && (prop != FONT_WEIGHT_INDEX
+                          || eabs (candidate - required) > 25)
 #ifdef HAVE_NTGUI
                     /* A kludge for w32 font search, where listing a
                        family returns only 4 standard weights: regular,
=====================================================================

(The value of 25 should allow both "semi-light" and "medium" fonts to
be used in place of "regular" fonts.)

I don't consider this patch to be a solution to the problem, since I
strongly suspect that it has some undesirable side effects during font
selection (possibly only on specific platforms or for specific fonts /
font weights), but it works well enough for me as a stop-gap fix, and
if this patch also fixes #1029710, I would propose including it in
Debian/sid as a workaround until there is a "proper" fix.

** Other possible workarounds

My reading of `xfns.c' is that Emacs tries to inherit fonts from the
environment, so it may be possible to work around this bug by changing
Gtk defaults.  (This is not something that I have tried, since I am
not very familiar with Gtk.)


-- System Information:
Debian Release: trixie/sid
  APT prefers testing
  APT policy: (990, 'testing'), (900, 'stable'), (500, 'stable-updates'), (500, 
'stable-security'), (5, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 6.5.0-4-amd64 (SMP w/32 CPU threads; PREEMPT)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8), LANGUAGE=en_CA:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages emacs-gtk depends on:
ii  emacs-bin-common     1:29.1+1-5
ii  emacs-common         1:29.1+1-5
ii  libacl1              2.3.1-3
ii  libasound2           1.2.10-1
ii  libc6                2.37-12
ii  libcairo2            1.18.0-1
ii  libdbus-1-3          1.14.10-3
ii  libfontconfig1       2.14.2-6
ii  libfreetype6         2.13.2+dfsg-1
ii  libgccjit0           13.2.0-5
ii  libgdk-pixbuf-2.0-0  2.42.10+dfsg-2
ii  libgif7              5.2.1-2.5
ii  libglib2.0-0         2.78.1-2
ii  libgmp10             2:6.3.0+dfsg-2
ii  libgnutls30          3.8.1-4+b1
ii  libgpm2              1.20.7-10+b1
ii  libgtk-3-0           3.24.38-6
ii  libharfbuzz0b        8.0.1-1
ii  libice6              2:1.0.10-1
ii  libjansson4          2.14-2
ii  libjpeg62-turbo      1:2.1.5-2
ii  liblcms2-2           2.14-2
ii  libm17n-0            1.8.4-1
ii  libotf1              0.9.16-4
ii  libpango-1.0-0       1.51.0+ds-3
ii  libpng16-16          1.6.40-2
ii  librsvg2-2           2.54.7+dfsg-2
ii  libselinux1          3.5-1
ii  libsm6               2:1.2.3-1
ii  libsqlite3-0         3.44.0-1
ii  libsystemd0          254.5-1
ii  libtiff6             4.5.1+git230720-1
ii  libtinfo6            6.4-4
ii  libtree-sitter0      0.20.8-2
ii  libwebp7             1.3.2-0.3
ii  libwebpdemux2        1.3.2-0.3
ii  libx11-6             2:1.8.7-1
ii  libxcomposite1       1:0.4.5-1
ii  libxext6             2:1.3.4-1+b1
ii  libxfixes3           1:6.0.0-2
ii  libxi6               2:1.8-1+b1
ii  libxinerama1         2:1.1.4-3
ii  libxml2              2.9.14+dfsg-1.3
ii  libxrandr2           2:1.5.2-2+b1
ii  libxrender1          1:0.9.10-1.1
ii  zlib1g               1:1.2.13.dfsg-3

Versions of packages emacs-gtk recommends:
ii  fonts-noto-color-emoji  2.038-1

Versions of packages emacs-gtk suggests:
pn  emacs-common-non-dfsg  <none>

-- no debconf information

Reply via email to