[Tex/LaTex] Fake small caps with XeTeX/fontspec

fontsfontspecsmall-capsxetex

Using XeTeX and fontspec, I use the Liberation font family in of my documents. Unfortunately those fonts (esp. Liberation Serif) do not natively support small caps.

Is there a way to enable fake small caps in fontspec?

Best Answer

Here I compare an alternative to Yan's approach. I label his method "fake" as he did and label this approach as "faux". I have found (see Good small caps font to use with arev?, for example) that an unequal scaling of horizontal and vertical dimension is better able to capture the proportions of small caps. For Minion Pro, shown in this example, I use 83% horizontal, and 72% vertical scaling to create faux small caps, with 100% horizontal scaling (no change) on the sc Caps. By comparison, I use 91% horizontal and 75% vertical scaling on Computer Modern, with 111% horizontal scaling on sc Caps, and on Palatino, 76% horizontal, 68% vertical scaling, with no change on the sc Caps.

In addition, my \fauxsc macro is able to automatically differentiate lower-case from upper-case arguments, and render them appropriately, which eases the input syntax.

In this MWE, I compare both "fake" and "faux" small caps to the real McCoy for Computer Modern, Minion Pro, and Palatino, respectively.

EDITED to handle UNICODE inputs in Xelatex. Previously, I detected lowercase by seeing if ˋ#1 was in the ASCII lowercase range. This, obviously does not work for UNICODE. Therefore, I adapted macro \fauxschelphelp to test for lowercase-ness using \lccode.

Result can now be seen in last line.

\documentclass{article}
\usepackage{fontspec,graphicx}
\usepackage{graphicx}
\makeatletter
\newlength\fake@f
\newlength\fake@c
\def\fakesc#1{%
  \begingroup%
  \xdef\fake@name{\csname\curr@fontshape/\f@size\endcsname}%
  \fontsize{\fontdimen8\fake@name}{\baselineskip}\selectfont%
  \uppercase{#1}%
  \endgroup%
}
\makeatother
\newcommand\fauxsc[1]{\fauxschelper#1 \relax\relax}
\def\fauxschelper#1 #2\relax{%
  \fauxschelphelp#1\relax\relax%
  \if\relax#2\relax\else\ \fauxschelper#2\relax\fi%
}
\def\Hscale{.83}\def\Vscale{.72}\def\Cscale{1.00}
\def\fauxschelphelp#1#2\relax{%
  \ifnum`#1=\lccode`#1\relax\scalebox{\Hscale}[\Vscale]{\char\uccode`#1}\else%
    \scalebox{\Cscale}[1]{#1}\fi%
  \ifx\relax#2\relax\else\fauxschelphelp#2\relax\fi}
\begin{document}
  \LARGE
{\def\Hscale{.91}\def\Vscale{.75}\def\Cscale{1.11}
  \makebox[1.2in][l]{This is fake} S\fakesc{mall} C\fakesc{aps} $\leftarrow$ other answer\par
  \makebox[1.2in][l]{This is real} \textsc{Small Caps}\par
  \makebox[1.2in][l]{This is faux} \fauxsc{Small Caps} $\leftarrow$ this answer
\par}\smallskip
  \fontspec{Minion Pro}
  \makebox[1.2in][l]{This is fake} S\fakesc{mall} C\fakesc{aps} $\leftarrow$ other answer\par
  \makebox[1.2in][l]{This is real} \textsc{Small Caps}\par
  \makebox[1.2in][l]{This is faux} \fauxsc{Small Caps} $\leftarrow$ this answer
\par\smallskip
{\fontspec{Palatino Linotype}
\def\Hscale{.76}\def\Vscale{.68}\def\Cscale{1.0}
  \makebox[1.2in][l]{This is fake} S\fakesc{mall} C\fakesc{aps} $\leftarrow$ other answer\par
  \makebox[1.2in][l]{This is real} \textsc{Small Caps}\par
  \makebox[1.2in][l]{This is faux} \fauxsc{Small Caps Œœ} $\leftarrow$ this answer
\par}
\end{document}

enter image description here