# OpenType 'rand' (Randomize) feature not correct implemented in XeTeX?

If XeLaTeX (v3.14159265-2.6-0.99996) compiles

\documentclass{article}
\usepackage{fontspec}
\setmainfont[Letters=Random]{punknova-regular.otf}
\begin{document}
bananes et ananas
\end{document}


it will output a document with just one fixed variant per glyph (every "a" is the same picture):

Omitting Letters=Random shows that XeLaTeX indeed is able to use variants but is not able to pick them randomly:

In contrast, LuaLaTeX compiles the same document correctly:

The question is, whether this is a bug in XeLaTeX or if there is a possibility to force XeLaTeX cycling through the random variants (e.g. by adding an option to fontspec)?

I don't think +rand is supported however you can access all the variants by name (a.1 to a.31 in the case of "a") and then randomise in TeX eg using the PGF random function.

\documentclass{article}
\usepackage{fontspec}
\setmainfont[Letters=Random]{punknova-regular.otf}
\usepackage{pgf}
\begin{document}

\XeTeXglyph\XeTeXglyphindex "a"
\XeTeXglyph\XeTeXglyphindex "a.1"
\XeTeXglyph\XeTeXglyphindex "a.2"
\XeTeXglyph\XeTeXglyphindex "a.3"
\XeTeXglyph\XeTeXglyphindex "a.4"
\XeTeXglyph\XeTeXglyphindex "a.5"
\XeTeXglyph\XeTeXglyphindex "a.6"

\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"
\pgfmathparse{random(31)}\XeTeXglyph\XeTeXglyphindex "a.\pgfmathresult"

\end{document}


Putting it all together, you can make a table with the glyph names and number of variants and then:

\documentclass{article}

\def\pntable#1#2#3{%
\expandafter\def\csname pn\number"#1-name\endcsname{#2}%
\expandafter\def\csname pn\number"#1-max\endcsname{#3}%
}
\pntable{0021}{exclam}{7}
\pntable{0022}{quotedbl}{7}
\pntable{0023}{numbersign}{7}
\pntable{0024}{dollar}{7}
\pntable{0025}{percent}{7}
\pntable{0026}{ampersand}{7}
\pntable{0027}{quotesingle}{7}
\pntable{0028}{parenleft}{7}
\pntable{0029}{parenright}{7}
\pntable{002A}{asterisk}{7}
\pntable{002B}{plus}{7}
\pntable{002C}{comma}{7}
\pntable{002D}{hyphen}{7}
\pntable{002E}{period}{7}
\pntable{002F}{slash}{7}
\pntable{0030}{zero}{7}
\pntable{0031}{one}{7}
\pntable{0032}{two}{7}
\pntable{0033}{three}{7}
\pntable{0034}{four}{7}
\pntable{0035}{five}{7}
\pntable{0036}{six}{7}
\pntable{0037}{seven}{7}
\pntable{0038}{eight}{7}
\pntable{0039}{nine}{7}
\pntable{003A}{colon}{7}
\pntable{003B}{semicolon}{7}
\pntable{003C}{less}{7}
\pntable{003D}{equal}{7}
\pntable{003E}{greater}{7}
\pntable{003F}{question}{7}
\pntable{0040}{at}{7}
\pntable{0041}{A}{15}
\pntable{0042}{B}{15}
\pntable{0043}{C}{15}
\pntable{0044}{D}{15}
\pntable{0045}{E}{15}
\pntable{0046}{F}{15}
\pntable{0047}{G}{15}
\pntable{0048}{H}{15}
\pntable{0049}{I}{15}
\pntable{004A}{J}{15}
\pntable{004B}{K}{15}
\pntable{004C}{L}{15}
\pntable{004D}{M}{15}
\pntable{004E}{N}{15}
\pntable{004F}{O}{15}
\pntable{0050}{P}{15}
\pntable{0051}{Q}{15}
\pntable{0052}{R}{15}
\pntable{0053}{S}{15}
\pntable{0054}{T}{15}
\pntable{0055}{U}{15}
\pntable{0056}{V}{15}
\pntable{0057}{W}{15}
\pntable{0058}{X}{15}
\pntable{0059}{Y}{15}
\pntable{005A}{Z}{15}
\pntable{005B}{bracketleft}{7}
\pntable{005C}{backslash}{7}
\pntable{005D}{bracketright}{7}
\pntable{005E}{asciicircum}{7}
\pntable{005F}{underscore}{7}
\pntable{0060}{grave}{7}
\pntable{0061}{a}{31}
\pntable{0062}{b}{31}
\pntable{0063}{c}{31}
\pntable{0064}{d}{31}
\pntable{0065}{e}{31}
\pntable{0066}{f}{31}
\pntable{0067}{g}{31}
\pntable{0068}{h}{31}
\pntable{0069}{i}{31}
\pntable{006A}{j}{31}
\pntable{006B}{k}{31}
\pntable{006C}{l}{31}
\pntable{006D}{m}{31}
\pntable{006E}{n}{31}
\pntable{006F}{o}{31}
\pntable{0070}{p}{31}
\pntable{0071}{q}{31}
\pntable{0072}{r}{31}
\pntable{0073}{s}{31}
\pntable{0074}{t}{31}
\pntable{0075}{u}{31}
\pntable{0076}{v}{31}
\pntable{0077}{w}{31}
\pntable{0078}{x}{31}
\pntable{0079}{y}{31}
\pntable{007A}{z}{31}
\pntable{007B}{braceleft}{7}
\pntable{007D}{braceright}{7}
\pntable{00A1}{exclamdown}{7}
\pntable{00A8}{dieresis}{7}
\pntable{00AF}{macron}{7}
\pntable{00B4}{acute}{7}
\pntable{00B8}{cedilla}{7}
\pntable{00BF}{questiondown}{7}
\pntable{00C6}{AE}{15}
\pntable{00D8}{Oslash}{15}
\pntable{00DF}{germandbls}{31}
\pntable{00E6}{ae}{31}
\pntable{00F8}{oslash}{31}
\pntable{0131}{dotlessi}{31}
\pntable{0152}{OE}{15}
\pntable{0153}{oe}{31}
\pntable{0237}{uni0237}{31} %dotlessj
\pntable{02C6}{circumflex}{7}
\pntable{02C7}{caron}{7}
\pntable{02D8}{breve}{7}
\pntable{02D9}{dotaccent}{7}
\pntable{02DA}{ring}{7}
\pntable{02DC}{tilde}{7}
\pntable{02DD}{hungarumlaut}{7}
\pntable{0391}{Alpha}{15}
\pntable{0392}{Beta}{15}
\pntable{0393}{Gamma}{15}
\pntable{0394}{Delta}{15}
\pntable{0395}{Epsilon}{15}
\pntable{0396}{Zeta}{15}
\pntable{0397}{Eta}{15}
\pntable{0398}{Theta}{15}
\pntable{0399}{Iota}{15}
\pntable{039A}{Kappa}{15}
\pntable{039B}{Lambda}{15}
\pntable{039C}{Mu}{15}
\pntable{039D}{Nu}{15}
\pntable{039E}{Xi}{15}
\pntable{039F}{Omicron}{15}
\pntable{03A0}{Pi}{15}
\pntable{03A1}{Rho}{15}
\pntable{03A3}{Sigma}{15}
\pntable{03A4}{Tau}{15}
\pntable{03A5}{Upsilon}{15}
\pntable{03A6}{Phi}{15}
\pntable{03A7}{Chi}{15}
\pntable{03A8}{Psi}{15}
\pntable{03A9}{Omega}{15}
\pntable{2013}{endash}{7}
\pntable{2014}{emdash}{7}
\pntable{2018}{quoteleft}{7}
\pntable{2019}{quoteright}{7}
\pntable{201C}{quotedblleft}{7}
\pntable{201D}{quotedblright}{7}

\makeatletter

\def\rndpn#1{\xrndpn#1\relax}

\def\xrndpn#1{%
\ifx\relax#1%
\else
\expandafter\ifx\csname pn\number\expandafter\noexpand#1-name\endcsname\relax
#1%
\else
\pgfmathrandominteger\pgfmathresult
{1}%
{\csname pn\number\expandafter\string#1-max\endcsname}%
\XeTeXglyph\XeTeXglyphindex
"\csname pn\number\expandafter\string#1-name\endcsname.\pgfmathresult"\relax
\fi
\expandafter\xrndpn
\fi}

\usepackage{fontspec}
\setmainfont[Letters=Random]{punknova-regular.otf}
\usepackage{pgf}

\begin{document}

\rndpn{bananes\ et\ ananas}

\end{document}

• Great to see the TeX using modern font technology out-of-the-box! – cfr Feb 21 '17 at 23:28
• I have reported this HarfBuzz bug here. The workaround of David Carlisle may be useful for a specific Punk Nova package but depends on the font. I thank you anyway, David. – Linus Romer Feb 22 '17 at 10:46
• @LinusRomer sure, the numbers depend on the font but the general approach would work for any font, so might be usable until harfbuzz suports this (and xetex uses that version), you just need to use fontforge or similar to extract list of variants. – David Carlisle Feb 22 '17 at 10:51
• You can also use rand=0 to rand=31 as font features and avoid hard-coding glyph names. – Khaled Hosny Feb 22 '17 at 14:10
• @KhaledHosny Hi nice to see you here! I'm sure the above isn't the best possible interface I was just playing to see if I could get something working. I'm not sure I know exactly how that translates to a fontspec interface (Perhaps I'll ask Will to translate:-) Or you could post an answer as well? – David Carlisle Feb 22 '17 at 14:35

This is expanding on David Carlisle’s answer. Instead of using glyph names, we can treat rand feature as a simple multiple alternate feature and try to access those alternates randomly:

\documentclass{article}
\usepackage{fontspec}
\setmainfont{punknova-regular.otf}
\usepackage{pgf}
\begin{document}

\makeatletter
\def\randomalt#1{%
\pgfmathparse{random(31)}%
}
\def\randomtext#1{\@tfor\next:=#1\do{\randomalt{\next}}}
\makeatother

% XXX: the spaces are eaten by the loop unless escaped!
\randomtext{bananes\ et\ ananas}

\end{document}


There are some caveats, though:

• Due to the way \addfontfeature{} is implemented, font features between the characters will not work (kerning, ligatures, etc.) since each alternate will be using a different font. This is not an issue for Punk Nova though as it does not have any such features IIRC.
• There is currently no way to get the number of alternates supported by the feature (the 31 above), one will need to examine the font externally or just use an arbitrary number.
• The spaces need to be escaped in the macro above, but that is probably because of my poor TeX skills (I just copied the macro from https://tex.stackexchange.com/a/253205/729).

A version that doesn't need to escape spaces

\documentclass{article}
\usepackage{fontspec}

\newfontfamily{\punk}{punknova-regular.otf}
\usepackage{pgf}

\ExplSyntaxOn
\NewDocumentCommand{\randomtext}{m}
{
\group_begin:
\punk
\seq_set_split:Nnn \l_khaled_randomtext_seq { ~ } { #1 }
\seq_map_inline:Nn \l_khaled_randomtext_seq
{
\khaled_random_word:n { ##1 }~
}
\unskip % remove the last space
\group_end:
}

\seq_new:N \l_khaled_randomtext_seq
\cs_new_protected:Nn \khaled_random_word:n
{
\tl_map_inline:nn { #1 }
{
\group_begin:
\pgfmathparse{random(31)}
\group_end:
}
}
\ExplSyntaxOff

\begin{document}

Normal text

\randomtext{bananes et ananas}

Normal text

\end{document}
`