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

From: Gregory Heytings <[email-masked]>
Date: Sun, 20 Nov 2022 13:57:48 +0000

Stefan, could you please try the attached patch and see if it fixes your 
problem?  (It does here, with your recipe.)

Eli, could you please review that patch?

Thanks.

From ab7090e055b7c2043f9fdb07b760ae8b304fe02c Mon Sep 17 00:00:00 2001
From: Gregory Heytings <[email-masked]>
Date: Sun, 20 Nov 2022 13:50:47 +0000
Subject: [PATCH] Also try 'normal' weight when searching a font with 'medium'
 weight.

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.
In the meantime, commit 65fd3ca84f added support for the 'medium' font
weight, which was previously synonymous to 'normal'.

Together, the two commits 6b1ed2f2c9 and 65fd3ca84f lead to suboptimal
font choices.  When the font chosen for the default face has its
weight set to 'medium' and actually supports that weight,
font_load_for_lface will be called with a weight attribute set to
'medium' in spec for other faces.  However, fonts with an explicit
'medium' weight are much less common than fonts with an explicit
'normal' weight, which means that fonts that only support a 'normal'
weight are rejected, although they are close to the desired font.

Therefore, font_find_for_lface should also try the 'normal' weight
when the weight in spec is 'medium', after trying the 'medium' weight.

* src/font.c (font_find_for_lface): When the weight in SPEC is
'medium', also try the 'normal' weight.
---
 src/font.c | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/font.c b/src/font.c
index 6e720bc285..4222d60231 100644
--- a/src/font.c
+++ b/src/font.c
@@ -2959,9 +2959,9 @@ font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int
 {
   Lisp_Object work;
   Lisp_Object entities, val;
-  Lisp_Object foundry[3], *family, registry[3], adstyle[3];
+  Lisp_Object foundry[3], *family, registry[3], adstyle[3], weight[3];
   int pixel_size;
-  int i, j, k, l;
+  int i, j, k, l, m;
   USE_SAFE_ALLOCA;
 
   /* Registry specification alternatives: from the most specific to
@@ -3081,6 +3081,17 @@ font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int
 	}
     }
 
+  /* If weight is "medium" in SPEC, also try "normal".  Fonts with an
+     explicit "medium" weight are much less common than fonts with an
+     explicit "normal" weight, and for a long time "medium" and
+     "normal" (a.k.a. "regular" a.k.a. "book") were synonymous in
+     Emacs.  See e.g. bug#59347 and bug#57555.  */
+  weight[0] = AREF (spec, FONT_WEIGHT_INDEX);
+  if (EQ (weight[0], Qmedium))
+    weight[1] = Qnormal, weight[2] = zero_vector;
+  else
+    weight[1] = zero_vector;
+
   /* Now look up suitable fonts, from the most specific spec to the
      least specific spec.  Accept the first one that matches.  */
   for (i = 0; SYMBOLP (family[i]); i++)
@@ -3095,18 +3106,22 @@ font_find_for_lface (struct frame *f, Lisp_Object *attrs, Lisp_Object spec, int
 	      for (l = 0; SYMBOLP (adstyle[l]); l++)
 		{
 		  ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
-		  /* Produce the list of candidates for the spec in WORK.  */
-		  entities = font_list_entities (f, work);
-		  if (! NILP (entities))
+		  for (m = 0; SYMBOLP (weight[m]); m++)
 		    {
-		      /* If there are several candidates, select the
-			 best match for PIXEL_SIZE and attributes in ATTRS.  */
-		      val = font_select_entity (f, entities,
-						attrs, pixel_size, c);
-		      if (! NILP (val))
+		      ASET (work, FONT_WEIGHT_INDEX, weight[m]);
+		      /* Produce the list of candidates for the spec in WORK.  */
+		      entities = font_list_entities (f, work);
+		      if (! NILP (entities))
 			{
-			  SAFE_FREE ();
-			  return val;
+			  /* If there are several candidates, select the
+			     best match for PIXEL_SIZE and attributes in ATTRS.  */
+			  val = font_select_entity (f, entities,
+						    attrs, pixel_size, c);
+			  if (! NILP (val))
+			    {
+			      SAFE_FREE ();
+			      return val;
+			    }
 			}
 		    }
 		}
-- 
2.35.1