Subject: bug#67810: 29.1; fonts use synthetic bold on Linux / pgtk

From: Tim Ruffing <[email-masked]>
Date: Mon, 15 Jan 2024 14:11:23 +0100

On Sat, 2024-01-13 at 08:59 +0200, Eli Zaretskii wrote:

> > What if a user wants to disable the `bold' attribute for a font
> > _with_
> > a bold variant?
> > 
> > That's not the feature I had in mind.  I don't see why Emacs should
> > allow users to disable font variants that do exist.  AFAIU, the
> > request was to prevent Emacs from creating a synthesized bold
> > variant
> > if the font doesn't have it, and that's all.  
> > 

Indeed.

@Po: And I totally agree that emacs packages who use icons from symbol
fonts should not set bold in the `face' property. However, as I said
earlier in this thread, I claim that this solves 90% of the cases, but
not all of them: Users may just want to insert icons in parts of their
files with bold font-lock, e.g., headings in org files or markdown
files (say you want to add a light-bulb icon in your notes for
"ideas"). In this case, while org-mode or markdown-mode (or actually
font-lock-mode) sets the bold face, these modes are not the ones that
insert the icon, so they shouldn't be responsible for setting regular
weight on icons. 

I claim that's a valid use case. Of course, one can totally object that
one should use SVGs, or that all of this is too niche so we shouldn't
care about this, and that even a boolean option is not worth the
complexity. And those are fine arguments, and after some more digging,
I'm also not sure anymore...  

Po wrote:
> > > Would it make sense to introduce a variable that disables
> > synthesizing
> > > bold or oblique font variants?
> > 
> > I think it won't until someone informs us of how those features
> > might
> > be
> > disabled in the font drivers that perform this.  The Mac driver is
> > definitely one of them, and possibly the Fontconfig driver as well.

In fact, now I thought a bit more about this, I agree with your
objections to having a simple knob that just disables overstriking in
xfaces.c... Yes, this would help some users, and it's easy to maintain,
but I suspect the behavior will be equally confusing to the current
one. (Think about a candidate docstring: "Inhibits the creation of
synthetic bold faces. This does not have an effect when the creation of
synthetic bolds is done by emacs font drivers, e.g., this variable has
no effect on Mac"... That is probably hard to understand for the
average user, and also it's simply not a solution for Mac users.)

I think you're right: If we want to add a boolean option, then it
should probably should cover all instances where emacs creates
synthetic bold fonts, i.e., not just the catch-all/fallback
overstriking in xfaces.c but also the synthetic bolds in the various
font drivers. (And the option should perhaps cover synthetic italics as
well, not sure. Or there could be a second option...) 

Yeah, then it's indeed more complex than a DEFSYM and two ifs. Though I
believe the complexity will still be manageable and also I don't think
we'll get bitten by this in the future: If this is an "inhibit"-style
option, the only risk is that we'll ever have font driver in the future
that creates synthetic bolds unconditionally.  

I had a look at the mentioned drivers.

For the MacOs driver, the property is set here in macfont.m, see uses
of synthetic_bold_p for the actual drawing. 

  if (!(sym_traits & kCTFontTraitBold)
      && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
    macfont_info->synthetic_bold_p = 1;

For Fontconfig / FT, "git grep -i embolden src" will point you to some
relevant code locations, but my digging shows that this driver will
never create synthetic bolds on demand. [1] 

So it's probably only overstriking and the font driver for MacOS that
would be affected by an option. 

Anyway, if people agree that an option should cover all drivers, the
patch is >5 lines and someone will need to work on it. I may have a
look in the future, but I currently don't have the time to work on it
(and I don't have a Mac, so someone else would need to test it.)  

Tim

[1] Okay, and this is where it's a bit of mess. 

While the code in the fontconfig driver doesn't have logic for creating
an synthetic bold variant when we want to display bold text, it
supports the "embolden" attribute that the user could set in their
config, at least kind of: If I set this in my local.conf for
fontconfig, then suddenly all fonts in all applications are synthetic
bolds, and emacs respects this, too.

<match target="font">
    <edit name="embolden" mode="assign">
      <bool>true</bool>
    </edit>
</match>

Of course, this is usually not meaningful. fontconfig ships with a
config file that is actually meaningful and enables synthetic bold
fonts when necessary, i.e., when no bold variant exists:

<match target="font">
    <!-- check to see if the weight in the font is less than medium
which possibly need emboldening -->
    <test name="weight" compare="less_eq">
        <const>medium</const>
    </test>
    <!-- check to see if the pattern requests bold -->
    <test target="pattern" name="weight" compare="more_eq">
        <const>bold</const>
    </test>
    <!--
      set the embolden flag
      needed for applications using cairo, e.g. gucharmap, gedit, ...
    -->
    <edit name="embolden" mode="assign">
        <bool>true</bool>
    </edit>
    <!--
     set weight to bold
     needed for applications using Xft directly, e.g. Firefox, ...
    -->
    <edit name="weight" mode="assign">
        <const>bold</const>
    </edit>
</match>

See the file 90-synthetic.conf, probably to be found in
/etc/fonts/conf.d .  But THAT setting one doesn't work in emacs. 

The reason is that fontconfig works in two steps:
1. build a database of fonts
2. let applications query the database with pattern matching

The second snippet above is supposed to have an effect in step 2. It
basically says "if the application queries for bold, and we don't have
native bold, set the embolden attribute in the query result".

But here's the thing: emacs will simply never ask for bold. What emacs
does is to ask fontconfig for the database resulting from step 1, and
the database doesn't have the bold font because it doesn't exist. So
emacs will learn that this is a font with weight "regular", and then
emacs will forever believe that the font is regular, and just simply
never query for a bold variant of it in step 2. This is just a
consequence of trying to fit fontconfig into the font driver model of
emacs. They use different concepts, and unless throw away all the emacs
font code, it just won't be possible to make fontconfig as in other
applications .

(See my message #47 in this thread for a way to get around this in
certain cases. One can set <match target="scan" ...> and this then will
influence step 1 and thus the database itself. But this is rather crude
and won't make the 90-synthetic.conf "on-demand" synthetic bold work:
We really need to compare the query pattern with the actual font to
determine whether embolden should be set. I said above that this is
also  https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25147 and
 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=17792 , but now I
believe that this these were mostly fixed in
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35781 already...)

The driver could, of course, set the embolden property automatically if
there's no native bold variant, and this would probably give a nicer
rendering than overstriking. Perhaps the driver should do this.