# Context sensitive glyph appears even when hyphenation removes the context

The Alegreya font has a pretty clever feature by which it substitutes the regular f glyph with a variant that has a longer cross stroke when the f is followed by t. The result is that the two cross strokes in f and t join, so that the sequence ft looks like a ligature. I like this feature.

BUT, the glyph variant of f with a longer cross stroke is also selected when an end-of-the-line hyphen removes the context by splitting ft into f-t. Now the f variant looks just plain wrong and weird.

\documentclass{article}
\usepackage{fontspec}
\setmainfont{Alegreya}%
[Path = /usr/local/texlive/2015/texmf-dist/fonts/truetype/huerta/alegreya/,
UprightFont = Alegreya-Regular.ttf]
\begin{document}
\parbox{0pt}{\hspace{0pt}for after}
\end{document}


The first word for illustrates how the f should look when not followed by t. Clearly what's happened here is that the substitution of f with the font's f.t variant occurs first, and then later LaTeX breaks the sequence by introducing a hyphen, and now it's apparently "too late" for the f character to revert to its regular glyph variant.

So now the question is: Is there a way of telling LaTeX to choose the regular f glyph variant whenever it is followed by a line-breaking hyphen?

I've used lualatex to compile the example above, and I intend to stick to that engine if possible.

I don't know how is this feature implemented in the font, but I guess that Luaotfload is missing support for it. The following code is just quick fix for this issue, it should be fixed in Luaotfload ideally.

The full code follows, some explanation is provided bellow:

\documentclass{article}
\usepackage{fontspec}
\usepackage{luacode}
\begin{luacode*}
local hlist_id = node.id "hlist"
local glyph_id = node.id "glyph"
local utfchar = unicode.utf8.char
local hyphen_char = 45
local break_subtype = 0

charreplaces = {}

local function get_char(c)
local x = tonumber(c)
if not x then
return string.byte(c)
end
return x
end

function char_replace(old, new)
local old = get_char(old)
local new = get_char(new)
print(old, new)
charreplaces[old] = new
end

local function get_next(n)
if n and n.id == glyph_id then
return n
elseif n then
return get_next(n.prev)
end
end

return get_next(last)
end

if n.id == hlist_id then
if last and last.subtype == break_subtype and last.char == hyphen_char then
local prev = get_next(last.prev)
local c = prev.char
print("Last char: ", c)
if charreplaces[c] then
print("Replacing", c)
prev.char = charreplaces[c]
end
end
end
end
end

\end{luacode*}

\newcommand\CharReplaceAtEnd[2]{
\luaexec{char_replace(\luastring{#1},\luastring{#2})}
}

\CharReplaceAtEnd{983056}{f}
\setmainfont{Alegreya}%
[Path = /usr/local/texlive/2015/texmf-dist/fonts/truetype/huerta/alegreya/,
UprightFont = Alegreya-Regular.ttf]
\begin{document}
\parbox{0pt}{\hspace{0pt}for after}

for after
\end{document}


Node processing callback is used to fix the characters. Because we need to apply the fix after linebreak, we need to use post_linebreak_filter.

local hlist_id = node.id "hlist"
local glyph_id = node.id "glyph"
local utfchar = unicode.utf8.char
local hyphen_char = 45
local break_subtype = 0


there we define some constants, in the callback, we need to process node list. In post_linebreak_filter this list contains hlist nodes, each containing one line. We need to get the last glyph from the line, to test whether it is linebreak hyphen, if it is, then we get the previous glyph, we print it to the standard output and test it whether it is in the table with replacements. If it is, we can replace the bad character with the right one.

local function fix_end_f(head)
if n.id == hlist_id then
if last and last.subtype == break_subtype and last.char == hyphen_char then
local prev = get_next(last.prev)
local c = prev.char
print("Last char: ", c)
if charreplaces[c] then
print("Replacing", c)
prev.char = charreplaces[c]
end
end
end
end
end


In order to make the interface more user friendly, one LaTeX macro is provided:

\newcommand\CharReplaceAtEnd[2]{
\luaexec{char_replace(\luastring{#1},\luastring{#2})}
}


it can be used in this way:

\CharReplaceAtEnd{983056}{f}


how we found the value 983056? Search the LaTeX output for Last char. It will print all characters preceding linebreak hyphen.

• So would you say this qualifies as a luaotfload bug/issue that I should report? Aug 28 '15 at 12:24
• @Sverre probably yes. I've tried to Algreya in LibreOffice and it handles this feature correctly. Aug 28 '15 at 14:47
• Bug report here. Is this something you perhaps would be able to help them with? I believe this is essentially the same bug as one reported three years ago, and which still hasn't been fixed. Sep 22 '15 at 13:35
• @Sverre I've posted some comment on luaotfload tracker. I think I've found the culprit, but I don't know a solution Sep 24 '15 at 22:37

Another solution of sorts is to use Renderer = Basic:

\documentclass{article}
\usepackage{fontspec}
\setmainfont{Alegreya}[Renderer = Basic]
\begin{document}
\parbox{0pt}{\hspace{0pt}for after}
\end{document}


Renderer = Basic will, however, lead to incorrect kernings in the font, as this option prevents luaotfload from interpreting class based kernings: https://github.com/khaledhosny/libertine/issues/3#issuecomment-133849174