How to make Graphviz use ~/.config/fontconfig/fonts.conf by default?

I just noticed this, after posting another message here.

Soon after reading a graph file, Graphviz conditions the input by applying various default settings to attributes that weren’t already set. These values are hardwired.

The theory or philosophy behind some of this design was, for a given graph, graphviz using any driver on any platform should yield the same result (or as close to it as possible). I intended for this to work at least for standard Postscript fonts. Over the years, with multiple people at different places working on the code, this may not still be true, but that was the intent at first.

I was able to see the arg passed to pango_font_description_from_string by

lldb dot
run it once to load all the libraries so the following symbol can be resolved
b pango_font_description_from_string
run it again and inspect the stack

Maybe someday graphviz/plugin/pango/gvtextlayout_pango.c should emit useful verbose/debugging messages. As an aside, I noticed that it calls fprintf stderr (which we would probably avoid these days; there is a dedicated API in graphviz to deliver warnings) , and there doesn’t seem to be any other warning/error/console output.

1 Like
  • a test to check that fontconfig is being used (you should see lots of fontconfig debug messages): export FC_DEBUG=4;dot -v myfile.gv -Tpng -omyfile.png 2>&1|less
  • On my system, pango (or something else?) seems to be replacing Times-Roman with DejaVu Serif - before handing that off to fontconfig. (No idea why).
  • Here is a version of ~/.config/fontconfig/fonts.conf that actually fires. It looks for family contains (matches) DejaVu Serif and replaces it with family = Symbol. Far from optimal, but it works - at least on my system.
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
      <!--   does not fire -->
      <match target="pattern">
        <test name="family" compare="contains">
            <string>Times</string>
        </test>
        <edit name="family" mode="assign_replace" binding="strong">
	  <string>Symbol</string>
        </edit>
      </match>

      <!--   does fire -->
      <match target="pattern">
        <test name="family" compare="contains">
            <string>DejaVu Serif</string>
        </test>
        <edit name="family" mode="assign_replace" binding="strong">
	  <string>Symbol</string>
        </edit>
      </match>
</fontconfig>

*But even if someone can figure out how to stop pango from making a hash of things, a fonts.conf that translates every occurrance of Times Roman to XXX will probably bollux up many other applications.

Stephen,

I have it already planned to inspect the relationship of Pango and fontconfig, but good to know!

I’m not sure what exact documentation you mean, but I guess you’re talking of the way Graphviz could render fonts without Pango and fontconfig. Maybe one day, someday, I could delve into this topic. If you mean that that documentation lacks something, I believe it be good to update it.

Only one line, that starting with fontname:, right?

Like the default value for fontname, i.e. Times-Roman?

Seems reasonable, yes.

I didn’t know that tool, thank you!

Steve,

Yes, I tried various FC_DEBUG values, but for some reason I didn’t think of it as a proof. Maybe it would be good to have ./configure output under graphviz-14.0.1 will be compiled with the following: lines like

libraries:
  fontconfig: Yes

(changing Yes to No if fontconfig be not used), and maybe consider other libraries that are also not being listed currently.

In general, to be fair, I’m not used to build applications myself. But when I think about it, it would be good to have ./configure return at least a list of all the things that may be not used under some circumstances (and fontconfig may be not used, according to the documentation). How does that sound?

Be it Pango or not, that’s a useful observation! All the more I see we have a “font supply chain” to inspect here, i.e. Graphviz → Pango → fontconfig (let’s suppose now it looks like that). And as for “why” you get such result, that’s surely a TODO.

What do you mean by “fires”? Is it the output of fc-match that is expected, or the output of Graphviz? For me, when I replace my fonts.conf with the one you showed, both

fc-match Times

and

fc-match 'DejaVu Serif'

give

StandardSymbolsPS.otf: "Standard Symbols PS" "Regular"

and also

echo 'graph { a }' | dot -Tpng -v 2>&1 -o /dev/null | grep fontname

gives

fontname: "Times-Roman" resolved to: (ps:pango  DejaVu Serif, ) (PangoCairoFcFont) "Standard Symbols PS, Regular" /usr/share/fonts/opentype/urw-base35/StandardSymbolsPS.otf

So it looks in all three cases it’s the same “Standard Symbols PS”. So which one is different than for you?

That’s true, that be a trade-off if one want only Graphviz to have its font translated. But fontconfig seems to be flexible. Maybe such translation be not that much of a concern if one know good enough what they can do with fontconfig?

fontconfig is effectively a rule-based Expert system (older AI technology that preceeded neural nets). fires is an old term from my days as a developer of Expert Systems.

The second “rule” - DejaVu Serif replaced by Symbol - “fires” when using Graphviz, even though the 1st “rule” - Times replaced by Symbol - does not.
The 1st rule does “fire” for fc-match.
It was a mistake to use Symbol for both rules. It would be more useful to have used different font families.

I agree that some kind of config file wouuld be a nice addition to Graphviz.

OK, thanks, I wasn’t clear. By “what ‘fires’ mean” I meant “how you check that it fires”. “Fires” is clear for me here. But it might be just because I’m not used to see this word in any other context, and this in turn becase I’m not a native English speaker.

But what is this behavior to show?


I thought that this thread could benefit from having a clearer picture of it all, so I made, naturally, a graph.

[dot]
digraph {
graphviz:se
→ pango:ne
[ label = “?” ]

pango:se
    -> fontconfig:ne
    [ label = "?" ]

fontconfig:nw
    -> pango:sw
    [ label = "?" ]

pango:nw
    -> graphviz:sw
    [ label = "?" ]

}
[/dot]

PS. Why doesn’t the [dot] tag work?

PS2. Interesting. I visited Render Graphviz graphs directly in your posts a few minutes ago, and the graphs there seemed to be being rendered properly. Now they are not.

PS3. I’ve made a note about it in that thread, Render Graphviz graphs directly in your posts - #26 by decision-making-mike

Update. Having [dot] not working sometimes, let’s have at least a standalone PNG version of the diagram.

Update 2. I’ve labeled it (and changed the font (to Gentium)).

Let me make a recap.

I didn’t now where to put double quotes, and where to omit them, so I decided to put them only when I get them in the output (I don’t think they matter, but still it’s good to be precise).




From those four diagrams I infer that

  1. as for the default fontname case, if Graphviz indeed passes to Pango Times-Roman, then the font I get from Graphviz ("DejaVu Serif, Book") is different than that when I run fc-match Times-Roman ("Nimbus Roman" "Regular"),

  2. as for the fontname = serif case, I get the same font as when I run fc-match serif ("EB Garamond, 08 Regular").

So it looks reasonable to assume, at least for now, that Graphviz is not involved in the problem, and to check Pango and fontconfig. If we assume fontconfig behave the same when called by Pango as when I run fc-match, then it’s likely that Pango converts Times-Roman to something. Then, fontconfig get this something and just return the font that it assume be best for it.

I’m especially curious why there is this additional string (ps:pango DejaVu Serif, ) in the output of Graphviz in the default fontname case. Compare once again that when I run

echo 'graph { a }' | dot -Tpng -v 2>&1 | grep fontname

I get

fontname: "Times-Roman" resolved to: (ps:pango  DejaVu Serif, ) (PangoCairoFcFont) "DejaVu Serif, Book" /usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf

with said string, but when I run

echo 'graph { a [ fontname = serif ] }' | dot -Tpng -v 2>&1 | grep fontname

I get

fontname: "serif" resolved to: (PangoCairoFcFont) "EB Garamond, 08 Regular" /usr/share/fonts/opentype/ebgaramond/EBGaramond08-Regular.otf

without a similar string.

We could intercept calls from pango to fontconfig, if that helps.

It’s not likely the pango project will agree to change their semantics for us, so this may not be a good use of further time.

Once upon a time, we wanted fontconfig to indicate that a binding had essentially failed (though a fallback font was substituted) so we could inform the operator, “Hey, Silly-Handwriting is not available on this computer”, but we didn’t get that.