Bug in 3.141592653-2.6-0.999995 (TeX Live 2023) with fontspec and tabularray?

Max Chernoff mseven at telus.net
Thu Apr 18 04:33:47 CEST 2024


Hi Karl,

On Wed, 2024-04-17 at 14:13 -0600, karl at freefriends.org wrote:
> The question that comes to my mind is, what does LuaTeX do here?
> Luigi (or anyone), when computing the width of a run of
> OpenType/TrueType glyphs, does luatex take the width values (reals) from
> the font and round each one individually, then sum them up? Or add the
> reals and only round the sum?

LuaTeX mostly treats fonts like a traditional TeX engine, with the
metrics kept separate from the actual glyph drawings. Until a page is
actually shipped out, the engine only ever looks at the metrics, which
are provided to it as a Lua table (see

   $TEXMFCACHE/luatex-cache/generic/fonts/otl/*.lua

for an example of what these look like). Based off of

   texk/web2c/luatexdir/font/texfont.h:90

the glyph widths appear to be stored in scaled points. And based off of

   texk/web2c/luatexdir/font/luafont.c:1358

these values appear to be rounded (not truncated) since
lua_numeric_field_by_index eventually expands to floor(width + 0.5).

To the engine, computing the length of a run of glyphs is treated the
same getting the width of a node list, so LuaTeX would sum these rounded
values. (Glyph nodes are actually a little special because of hz
expansion, but this is still calculated in scaled points so it doesn't
make much of a difference here)

This is all for "node" mode though. When using "harf" mode, the font and
glyph processing is completely different and I have no idea what happens
then.

> Overall, I think the thing to find (somehow) is at what low-level point
> LuaTeX and XeTeX compute something differently.

Here are some maybe helpful test files. This first one lets you change
LuaTeX so that instead of rounding the glyph widths, it truncates them.
By default, LuaTeX and XeTeX both give good linebreaks with 10pt and bad
linebreaks with 10bp, but if you enable the truncation code, LuaTeX will
give good linebreaks with 10bp too.

   \ifdefined\directlua
       \input luaotfload.sty

       %%% Uncomment to test truncation
       % \directlua{
       %     function fonts.constructors.aftercopyingcharacters(target)
       %         for _, t in pairs(target.characters) do
       %             t.width = math.floor(t.width)
       %         end
       %     end
       % }
   \fi

   %%% No weird line breaks with 10pt
   % \font\testfont=[lmroman10-regular] at 10pt
   \font\testfont=[lmroman10-regular] at 10bp
   \testfont

   \hsize=50em
   \parindent=0pt
   \rightskip=0pt plus 1fil

   \newcount\i
   \loop\ifnum\i<200
       \advance\i by 1
       \number\numexpr \i - ((\i - 5)/ 10) * 10\relax
       \allowbreak
   \repeat

   \bye

This second one extends your original example so that it also gives bad
output with LuaTeX, either by widening each glyph by 1sp or by
shortening every hbox by 1sp.

   \ifdefined\directlua
       \input luaotfload.sty

       \directlua{
           %%% Uncomment to shrink every hbox by 1sp
           % luatexbase.add_to_callback("hpack_filter", function (head)
           %     local shrink = node.new("kern")
           %     shrink.kern = -1
           %     node.slide(head).next = shrink
           %
           %     return true
           % end, "shrink hboxes")

           %%% Uncomment to expand every glyph by 1sp, only when in a paragraph
           % luatexbase.add_to_callback("pre_linebreak_filter", function (head)
           %     local n = head
           %     repeat
           %         if n.id == node.id("glyph") then
           %             local new = node.copy_list(n, n.next)
           %
           %             local box = node.hpack(new)
           %             box.width = box.width + 1
           %
           %             head, box = node.insert_after(head, n, box)
           %             head = node.remove(head, n)
           %
           %             n = node.free(n)
           %         end
           %         n = n.next
           %     until not n
           %
           %     return head
           % end, "grow lines")
       }
   \fi

   \parindent=0pt
   \def\test#1{%
     \setbox0=\hbox{#1}
     \vbox{\hsize=\wd0 \leftskip0pt plus 1fil  #1} % emulate \raggedleft etc.
     \vbox{\hsize=\wd0 \rightskip0pt plus 1fil #1}
     \vbox{\hsize=\wd0 \leftskip0pt plus 1fil \rightskip\leftskip #1}
     \par
   }

   \font\1="[lmroman10-regular]" at 10pt \1
   \test{Dest-Addr} % ok

   \font\1="[lmroman10-regular]" at 10.95pt \1
   \test{Dest-Addr} % unwanted line breaks right after hyphen char
   % none of 10.94pt nor 10.96pt can reproduce the problem

   \font\1="[lmroman10-regular]" at 11pt \1
   \test{Dest-Addr} % ok

   \bye

Thanks,
-- Max




More information about the tex-live mailing list.