Subject: bug#59347: 29.0.50; `:family` face setting ignored

From: Gregory Heytings <[email-masked]>
Date: Tue, 22 Nov 2022 07:59:22 +0000

>> By the way, I suspect (but do not have a recipe right now) that the 
>> same bug exists with the :width and :slant attributes (namely, that 
>> setting the font for the default face with an "exotic" value leads to 
>> suboptimal/wrong font choices for other faces), and that they should 
>> also be set to nil in font_find_for_lface.
>
> IIUC the way we manage choose fonts is that we ask for a list of fonts 
> matching a particular pattern.  If that list is empty we make the 
> pattern more coarse and try again.  And when the list is not empty we 
> choose the best fit based on a score.
>

Yes, that's roughly speaking what is happening indeed.  Except that if we 
constraint, when we build it, the list of candidates to a specific weight 
and/or slant and/or width, scoring the candidates becomes pointless, 
because all candidates in the list will (by definition) be perfect 
matches.

>
> So in essence, what you're saying is that we should rely more on 
> scoring, and start with a coarser pattern right from the beginning?
>

What I'm saying (now) is that we should rely on scoring, not that we 
should rely _more_ on scoring.

New (again) patch attached.

From d21017c8b2fdf017f78217b34e6a5411b605e37c Mon Sep 17 00:00:00 2001
From: Gregory Heytings <[email-masked]>
Date: Tue, 22 Nov 2022 07:58:30 +0000
Subject: [PATCH] Unset the weight/slant/width in font specs when searching for
 a font

Between commits bf0d3f76dc (2014) and 6b1ed2f2c9 (2022),
realize_gui_face called font_load_for_lface with an empty or partly
emptied font spec, i.e. it ignored a part of its attrs argument.  The
rationale given in bug#17973, which led to bf0d3f76dc, is not clear.
However, 6b1ed2f2c9 leads to suboptimal font choices, in particular
when the font chosen for the default face has a weight, slant or width
that is not supported by other available fonts on the system, such as
'medium' or 'heavy'.  Furthermore, calling font_list_entities without
unsetting these attributes arbitrarily limits the number of candidates
to only those that are perfect matches, which means that scoring the
candidates becomes in fact pointless.  Therefore, the weight, slant
and width attributes in the spec argument to font_find_for_lface must
be unset, like the size attribute.

* src/font.c (font_find_for_lface): Unset the weight, slant and width
of the font spec.  Fixes bug#57555 and bug#59347.
---
 src/font.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/font.c b/src/font.c
index 6e720bc285..0723e080dd 100644
--- a/src/font.c
+++ b/src/font.c
@@ -3003,6 +3003,15 @@ font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int
     }
   ASET (work, FONT_SIZE_INDEX, Qnil);
 
+  /* Unset the font weight, slant and width.  The best possible values
+     for these attributes is determined later, when the candidate list
+     returned by font_list_entities is sorted by font_select_entity
+     (which calls font_sort_entities, which calls font_score).  See
+     bug#59347.  */
+  ASET (work, FONT_WEIGHT_INDEX, Qnil);
+  ASET (work, FONT_SLANT_INDEX, Qnil);
+  ASET (work, FONT_WIDTH_INDEX, Qnil);
+
   /* Foundry specification alternatives: from the most specific to the
      least specific and finally an unspecified one.  */
   foundry[0] = AREF (work, FONT_FOUNDRY_INDEX);
-- 
2.35.1