Identically configured urxvt has different width/font rendering on different X servers

1

I have two different desktop hosts connected via their DisplayPort outputs to two DisplayPort inputs on the same 4K monitor:

  • idyllic, a small-form-factor PC using the onboard Intel HD Graphics 500 of its Celeron N3350 processor. (I've also a similar system at another location with a Pentium N4200 processor and Intel 505 graphics that functions identically at 4K, as far as I can tell.)
  • logarithmic, a fairly generic old ATX system with an Intel i5-3450 CPU and an ATI Radeon 7870 graphics card

Both systems are running fully up-to-date Debian 9 and are configured as identically as I can manage. In particular:

  • The X server DPI is 96 on both systems, checked with grep DPI /var/log/Xorg.0.log and xdpyinfo | grep dots
  • The Xft DPI is 120 on both systems, checked with xrdb -query | grep dpi.
  • Both are configured with xrdb -cpp cpp -merge $HOME/.Xresources from an identical file, and I've confirmed that xrdb -query produces identical output on both. I also have exactly the same set of Source Code Pro fonts loaded into ~/.fonts on both systems.

On either of them I can start an 80-column xterm, configured with XTerm*VT100*font: -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1 and they look identical and are 484 pixels wide. This doesn't change if I start the xterm client on the other machine displaying on the local X server using ssh -X.

However, urxvt is different depending on which X server I'm using. I've configured the font X resource as:

Rxvt.font:  xft:Source Code Pro:size=9,xft:Source Han Sans,xft:DejaVu Serif:size=8,xft:DejaVu Sans Mono:size=8

When I start urxvt to display on idyllic's X server, either locally or started on the other host with ssh -X, an 80 column terminal is 644 pixels wide and 106 columns high when maximized vertically. However, when I start it to display on logarithmic's X server (again either locally or with a remote client using ssh -X), an 80 column urxvt is 726 pixels wide, though still 106 columns high when maximized vertically.

So, the question:

What's causing urxvt on logarithmic to be wider, and how do I make it the same nice narrow size as idyllic? Even if you don't know, debugging hints would be appreciated. I'm happy to write programs (preferring Python or similar over C or similar) that talk to the X11 servers and let me play around with similar rendering to what urxvt is doing to see if the problem can be found that way, if you have concrete suggestions on what APIs I should be calling and what kind of results I should be looking for.

A side question: xft: fonts are rendered by the X client, right? If that's correct, it would seem to be a big hint that some setting in the X11 server is changing how the same client on the same host is rendering fonts depending on which X11 server it's talking to.

EDIT: xfce4-terminal Information

I've tried starting up an xfce4-terminal and setting the font to 9 point Source Code Pro medium; it comes out the same on both X11 servers, always in the wider format that urxvt uses on logarithmic. This seems to indicate that it's something to do with urxvt itself or perhaps the Xft library (if xfce4-terminal doesn't use that; I am pretty sure that urxvt does), and not FreeType?

EDIT: xtrace Information

I have further information from xtrace (thanks for the idea, @Uli Schlachter!) that at least lets me see things go wrong in more detail. Running even just xtrace urxvt -e true produces a couple of hundred kilobytes of output, so obviously I'm not going to include that all here, but here are some key bits. The diffs below are of sessions idyllicidyllic and idylliclogarithmic, i.e., idyllic ran the urxvt in both cases but displayed first on itself and second remotely on logarithmic.

At line 156 in each the CreateWindow call confirms windows being created with the same height but different widths, as I mentioned above (I measured one window width dead on, but the other two pixels out):

-000:<:005e: 48: Request(1): CreateWindow depth=0x18 window=0x03200009 parent=0x000000e7 x=0 y=0 width=644 height=904 border-width=0 class=InputOutput(0x0001) visual=0x00000021 value-list={background-pixel=0x00ffffe0 border-pixel=0x00ffffe0 override-redirect=false(0x00) colormap=0x00000020}
+000:<:005e: 48: Request(1): CreateWindow depth=0x18 window=0x05400009 parent=0x000004bb x=0 y=0 width=724 height=904 border-width=0 class=InputOutput(0x0001) visual=0x00000021 value-list={background-pixel=0x00ffffe0 border-pixel=0x00ffffe0 override-redirect=false(0x00) colormap=0x00000020}

Starting at line 138 of each I see this diff (second line truncated for sanity), which seems to confirm, with width=7 vs. width=9 for the glyphs being created, that it's a character width issue.

-000:<:004c: 12: RENDER-Request(139,17): CreateGlyphSet gsid=0x03200008 format=0x00000024
-000:<:004d:108: RENDER-Request(139,20): AddGlyphs glyphset=0x03200008 glyphids=0x0000036d; glyphs={width=7 height=10 x=-1 y=10 xOff=9 yOff=0}; data=0x00,0x3e,...
+000:<:004c: 12: RENDER-Request(139,17): CreateGlyphSet gsid=0x05400008 format=0x00000026
+000:<:004d:388: RENDER-Request(139,20): AddGlyphs glyphset=0x05400008 glyphids=0x0000036d; glyphs={width=9 height=10 x=0 y=10 xOff=9 yOff=0}; data=0x00,0x00,...

(This continues on for further characters, with width 8 vs. 10, 9 vs. 11, etc.)

So presumably whatever it was that's causing this came somewhere before line 138. Looking before that the majority of diffs seem to be changes in the ID numbers used for objects, so it's a bit painful to find out what the real diffs are.

So what major differences do I see? Well, the initial response after the client connects is almost identical except that logarithmic (the one with the discrete Radeon graphics card) returns a lot more visuals. Both start with:

{id=0x00000021 class=TrueColor(0x04) bits/rgb-value=8 colormap-entries=256 red-mask=0x00ff0000 green-mask=0x0000ff00 blue-mask=0x000000ff},
{id=0x00000022 class=DirectColor(0x05) bits/rgb-value=8 colormap-entries=256 red-mask=0x00ff0000 green-mask=0x0000ff00 blue-mask=0x000000ff},

The list after that seems mainly duplicates, just with a lot more duplicates on the logarithmic side.

The next big difference is in a Reply to QueryPictFormats: where the screens=... depths=... visuals={...} list of visuals is, again, much much longer on the logarithmic side.

But at the very end of that there is a more notable difference:

-subpixels=Unknown(0x0);
+subpixels=HorizontalRGB(0x1);

After that there's a QueryFont for fixed which returns some differing data, which looks like just IDs, and anyway seems used only for creating a cursor as it's then closed immediately after that. Then it goes and seems to be pretty much the same (again, modulo IDs, unless I missed something) until line 139.

EDIT: FontConfig Debugging

I've also tried checking FC_DEBUG against each server with FC_DEBUG=8191 urxvt -e true 2>outputfile. I confirmed that the width is indeed still different when done this way. Diffing the two output files produces in the 8.5 MB of output only three instances of the following difference (- is _idyllic,+` is logarithmic):

-   rgba: 0(i)(s)
+   rgba: 1(i)(s)
fonts
x11
xorg
urxvt
asked on Stack Overflow Aug 22, 2018 by cjs • edited Sep 3, 2018 by cjs

1 Answer

2

The issue is the subpixel rendering by Xft/FreeType which, as with a few other settings, can have a dramatic effect on the width of fonts that are rendered while not changing the height at all.

The FontConfig debugging makes it clear that the subpixel rendering setting is different. Setting this explicitly in the X resources will make both systems work the same:

  • Xft.rgba: rgb will make both systems render the font wider on both X11 servers (the way they do when either renders to logarithmic without this set).
  • Xft.rgba: none will make both systems render the font narrower on both X11 servers (the way they do when either renders to idyllic without this set).

Thus, adding Xft.rgba: none to the ~/.Xresources fixes the problem.

while this answer is currently the accepted one because it solves the problem, I would be very pleased to change accept another answer that provides a deeper explanation of exactly what's going on here.

answered on Stack Overflow Sep 4, 2018 by cjs

User contributions licensed under CC BY-SA 3.0