Hi,
in LuaTeX node.ligaturing should return the head and the tail of the
list after ligatures got applied. But in the case that the tail of the new
list is a discretionary the current code returns the passed in tail
instead, assuming that it didn't change. This breaks if the
discretionary node wasn't the tail before the ligature pass:.
Take for example
\directlua{
local b = token.scan_list()
local h = b.head
local t = node.tail(h)
local post_h, post_t = node.ligaturing(h, node.tail(t))
print(node.tail(post_h), post_t)
}\hpack{a\discretionary{}{f}{f}f}
\bye
Here the `f`s in the discretionary form ligatures with the `f` after the
discretionary, so after node.ligaturing the list if effectively
`a\discretionary{}{ff}{ff}` and therefore `post_t` should point to the
discretionary node. But as the output shows, post_t instead is a glyph
node while node.tail(post_h) is the expected disc node.
This is caused by `handle_lig_word` in luafont.c. `handle_lig_word` is
used in `handle_ligaturing` as
while (cur != null) {
if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
cur = handle_lig_word(cur);
}
prev = cur;
cur = vlink(cur);
}
so it is expected that handle_lig_word returns the last node already handled
so that afterwards the loop can continue at vlink(cur). But if the handled
segment ends with a discretionary `handle_lig_word` returns the node `after`
the last already handled node instead. This is fine if the last node is a
non glyph/non boundary node, but if the discretionary ends the segment passed
to handle_ligaturing than this means that `handle_lig_word` returns null,
therefore settings `prev` to `null` instead of tracking the tail.
Also this relies on `vlink(null)` being null, causing issues if this
ever gets corrupted (see my next mail for an example...).
It can be fixed by making sure that handle_lig_word always returns the
last handled node, e.g. using
diff --git a/source/texk/web2c/luatexdir/font/luafont.c b/source/texk/web2c/luatexdir/font/luafont.c
index 2e08facb1..c33037244 100644
--- a/source/texk/web2c/luatexdir/font/luafont.c
+++ b/source/texk/web2c/luatexdir/font/luafont.c
@@ -2242,6 +2242,7 @@ static halfword handle_lig_nest(halfword root, halfword cur)
static halfword handle_lig_word(halfword cur)
{
halfword right = null;
+ halfword last = null;
if (type(cur) == boundary_node) {
halfword prev = alink(cur);
halfword fwd = vlink(cur);
@@ -2481,9 +2482,10 @@ static halfword handle_lig_word(halfword cur)
} else {
/*tex We have glyph nor disc. */
- return cur;
+ return last;
}
/*tex Goto the next node, where |\par| allows |vlink(cur)| to be NULL. */
+ last = cur;
cur = vlink(cur);
}
return cur;
--
Best regards,
Marcel