LuaLaTeX: Replace character “ß” in CMU fonts

The glyph for the character "ß" differs considerably between Latin Modern and the CMU fonts (CMU Serif, CMU Sans Serif etc., which use the same glyphs for ß as cm-super; see this answer):

I much prefer Latin Modern's version of ß, but I would like to use the CMU fonts because of their Unicode capabilities (they provide a lot more characters than Latin Modern). I would like to avoid editing the font file (I don't want to maintain my own versions of fonts!).

Instead, I was wondering how one would replace a single character with another font in LuaLaTeX. I've seen XeTeX solutions (e.g. this question), but nothing that works with LuaTeX. So far, I've tried the following:

\documentclass{scrartcl}
\usepackage{fontspec}
\setmainfont{CMU Serif}
\setsansfont{CMU Sans Serif}
\setmonofont{CMU Typewriter Text}

\usepackage{newunicodechar}
\newunicodechar{ß}{{\fontspec{Latin Modern Roman}ß}}

\begin{document}
ß
\end{document}


However, I have two problems with this approach:

• In the \newunicodechar definition of ß, I would need some way to detect if the font should be set in serif, sans-serif or typewriter (variants such as bold, italic etc. seem to work).
• I'm having doubts whether making ß an active character is a good idea. I've heard that hyphenation/kerning/other details in TeX can have problems under these circumstances.

What would be the best way to implement this replacement?

Update: I have extended my first attempt to detect changes in the font family. Still, there is the question whether using active characters can cause any unwanted problems.

\documentclass{scrartcl}
\usepackage{fontspec}
\setmainfont{CMU Serif}
\setsansfont{CMU Sans Serif}
\setmonofont{CMU Typewriter Text}
\usepackage{newunicodechar}

\newfontfamily{\lmodernrm}{Latin Modern Roman}
\newfontfamily{\lmodernsf}{Latin Modern Sans}
\newfontfamily{\lmoderntt}{Latin Modern Mono}
\DeclareTextFontCommand{\textlmodernrm}{\lmodernrm}
\DeclareTextFontCommand{\textlmodernsf}{\lmodernsf}
\DeclareTextFontCommand{\textlmoderntt}{\lmoderntt}

\makeatletter
\newunicodechar{ß}{%
\ifx\f@family\rmdefault\textlmodernrm{ß}%
\else\ifx\f@family\sfdefault\textlmodernsf{ß}%
\else\ifx\f@family\ttdefault\textlmoderntt{ß}%
\fi\fi\fi}
\makeatother

\begin{document}
ß \textsl{ß} \textit{ß} \textbf{ß}

\sffamily
ß \textsl{ß} \textit{ß} \textbf{ß}

\ttfamily
ß \textsl{ß} \textit{ß}
\end{document}

• You'll certainly break kerning anyway because kerning involves adjustments between characters considered pairwise and these are defined by fonts i.e. a font might say when 'v' follows 'a', move such-and-such distance to the left before placing the 'v'. No such definition will exist between a character from one font and a character from another. (Unless you define this manually for every kerning pair involving 'ß' where you want a kern, which I think might be possible using a feature file although I don't know if you could do that between fonts.) – cfr Feb 27 '15 at 1:06
• In theory it is possible to build virtual fonts which pulls glyph from various sources - there is even an example in the luatex documentation. But in practice it is difficult to do on top of luaoftload as the interface is not clear. Similar for fallbacks: imho context has them, so it is possible. – Ulrike Fischer Feb 27 '15 at 8:48
• @AndrewCashner I guess what I really want in this case is indeed a fallback for characters that are not available in a font (in this case in Latin Modern). Still, this is a special case since the two fonts in question (Latin Modern and CMU) are practically the same, so it would be possible to just use CMU instead of defining a fallback – if it weren't for the accursed ß character! The question you refer to essentially uses the same solution as I did, but "the other way around". It still has the same problems/uncertainties (no detection of font families, uses active characters). – Socob Feb 27 '15 at 15:10
• Yes, it's just the reverse of what you are doing. It depends on which range will be used more often. If the range covered by Latin Modern suffices for most of your work, then I would recommend what I put in my answer here; otherwise you reverse it, or do as you are doing. That is, until we develop that fallback system! – musarithmia Feb 27 '15 at 15:16

You could set Latin Modern as the main font if you like it for the Latin range, and then use CMU Serif as a fallback font for higher Unicode ranges. Depends on how much higher Unicode you need. I still hope someone can devise a mechanism for an automatic font-fallback system like in CSS. (Define fallback font for specific Unicode characters in LuaLaTeX)

\documentclass{article}
\usepackage{fontspec}
\setmainfont{Latin Modern Roman}
\newfontfamily{\unicodefont}{CMU Serif}
\DeclareTextFontCommand{\textunicode}{\unicodefont}
\begin{document}
Straße \textunicode{μετανοεῖτε}
\end{document}


• This seems like the "safest" solution, but (as you say) it is unfortunately not automatic (i.e. characters from different Unicode ranges cannot be entered as "plain text"). Although it might be a solution to the problem that led me to ask the question, I think we've strayed from the actual question itself ;-) – Socob Feb 27 '15 at 15:25

The Latin Modern font family is available in OpenType format as well; see The Latin Modern (LM) Family of Fonts site. Even better, it's distributed with both TeXLive and MikTeX. (Am I maybe missing something about capabilities of CMU that are not available in LM?) Thus, you could write

% !TEX TS-program = lualatex
\documentclass{scrartcl}
\usepackage{fontspec}
\setmainfont{Latin Modern Roman}
\setsansfont{Latin Modern Sans}
\setmonofont{Latin Modern Mono}
\begin{document}
ß \textsf{ß} \texttt{ß}
\end{document}


• I thought that the Latin Modern Opentype fonts were the default fonts when fontspecis loaded? – Franck Pastor Feb 27 '15 at 5:37
• @fpast - I think you're right on this, at least for the more recent versions of fontspec. I don't know which version of fontspec the OP may be using, though. – Mico Feb 27 '15 at 5:54
• @fpast: the latin modern fonts are the default. But there are loaded in a different way. This means that e.g. you can't use \addfontfeature{Color=red} together with the default fonts. So often it is quite sensible to "reload" the fonts with \setmainfont" etc. – Ulrike Fischer Feb 27 '15 at 8:13
• I do realize Latin Modern is available as OpenType font – otherwise my code example using \newunicodechar{ß}{{\fontspec{Latin Modern Roman}ß}}` wouldn't have worked. I apologize if I was unclear – by "capabilities", I meant that CMU covers a much greater range of Unicode characters than Latin Modern. (I edited the question to clarify.) – Socob Feb 27 '15 at 14:56
• It's not from me :) – musarithmia Feb 27 '15 at 20:52