15

This is a follow-up question to: How do I know which ligatures are used in my document?

In order to know which ligatures I might consider disabling (I have in mind microtype's \DisableLigatures command; some important notes about selective disabling of ligatures are found under this question), knowledge about which ligatures might be applied will be very useful. Which ligatures do the fonts used in my document offer?

3
  • Are you interested in .tfm based font or in OpenType ones for (Xe|Lua)TeX?
    – egreg
    Commented Apr 1, 2013 at 22:48
  • @egreg I honestly don't know; "all scenarios"? (Also let me know if writing a separate question is appropriate.) Commented Apr 1, 2013 at 22:56
  • 1
    Ligatures are realized in very different ways for the two models. However, \DisableLigatures is quite limited: if you want to disable ffl, you have to disable all f ligatures.
    – egreg
    Commented Apr 1, 2013 at 23:00

4 Answers 4

22

The following presents a solution for pdftex and Type 1 fonts. Since TeX does not offer any possibility to decompose a ligature into its constituent characters (this information is lost after they have been replaced by the ligature), we have to take the opposite approach: we loop over all glyph pairs in the fonts, typesetting them in a temporary box, and test, by way of etex's \lastnodetype, whether we have obtained a ligature. We can then write the slot numbers of the ligating characters to the log file and/or actually typeset the ligature and its parts, whereas the slot number of the ligature is only available with \showbox (see below).

\RequirePackage{fix-cm}
\documentclass[12pt]{article}
\usepackage[LY1,T1]{fontenc}
\usepackage{fixltx2e}[2006/09/13]
\usepackage[expansion=false]{microtype}
\usepackage{yfonts}
% enable microtype's no ligatures procedure, without actually disabling any ligatures
\DisableLigatures{encoding = }
\makeatletter
\showboxbreadth100
\showboxdepth100
\newcount\MT@ligcount
\newbox\MT@ligbox
\newtoks\MT@ligtoks
\def\MT@showligs{%
  \MT@info@nl{showing ligatures in font `\MT@@font'}%
  \let\lig@temp\@empty
  % loop over all glyph pairs in the font
  \MT@do@font{%
    %\iffontchar\MT@font\@tempcnta\relax  % only test those glyphs that
    \ifnum\tagcode\MT@font\@tempcnta=\@ne % have a "lig/kern program"
      \MT@ligcount\z@
      \loop
      \iffontchar\MT@font\MT@ligcount
        \setbox\@tempboxa\hbox{\MT@font
          \setbox\MT@ligbox\hbox{\char\@tempcnta\char\MT@ligcount}%
          \unhbox\MT@ligbox
          \ifnum\lastnodetype=7 % ligature
            \aftergroup\@firstofone
          \else
            \aftergroup\@gobble
          \fi
        }%
        {% info in the log file
        %\showbox\@tempboxa
         \MT@info@nl{\the\@tempcnta\space + \the\MT@ligcount}%
         % store information for later
         \edef\lig@temp{\lig@temp
             \noexpand\char\the\@tempcnta\noexpand\char\the\MT@ligcount
            $($\noexpand\char\the\@tempcnta$^{[\the\@tempcnta]}$%
               \noexpand\char\the\MT@ligcount$^{[\the\MT@ligcount]}),$ }%
         }%
      \fi
      \advance\MT@ligcount\@ne
      \ifnum\MT@ligcount < \@cclvi \repeat
    \fi
  }%
  \ifx\lig@temp\@empty
    \edef\lig@temp{\noexpand\normalfont No ligatures in `\MT@@font'.}
  \else
    \edef\lig@temp{\noexpand\normalfont Ligatures in `\MT@@font': \MT@font\lig@temp}%
  \fi
  \global\MT@ligtoks\expandafter\expandafter\expandafter
    {\expandafter\the\expandafter\MT@ligtoks\lig@temp\par}%
}

% hook into microtype to make sure that all fonts are caught
\let\MT@noligatures@orig\MT@noligatures
\def\MT@noligatures{\MT@noligatures@orig\MT@showligs}

\AtEndDocument{\par\hrule\the\MT@ligtoks}

\begin{document}

Selecting 
{\fontencoding{LY1}\selectfont various} 
\textit{(including $\mathrm{maths}$)} 
\textfrak{fonts:}

\end{document}

show ligatures output

Uncommenting the \showbox line will allow finding out, in a clumsy way, the slot number of the ligature, too, which will be presented in a form like this:

> \box12=
hbox(5.1654+0.0)x11.74713
.T1/cmr/m/n/12 ^^V (ligature ^^U-)

This shows the triple ligature — (emdash), composed of the ligature – (endash) and the character - (hyphen), normally written as ---, where ^^V = 22, and ^^U = 21 (conversion rules here). Other than that, getting the slot numbers of ligature requires leaving the pdftex realm and resort to inspecting the tfm file (see @egreg's solution), employing metapost (@AndrewKepert), or (probably) luatex.

0
11

If you have a .tfm based font, so one of the classical fonts, you can examine the file. Say you want to know about pplr8t (Palatino Roman, T1 encoded). Then you can run this shell command

tftopl pplr8t.tfm > pplr8t.pl

In the pplr8t.pl file, look for LIGTABLE; this is a big chunk near the beginning of the file. If you run a grep search such as

egrep '\(LABEL|LIG|STOP\)' pplr8t.pl

you'll get

(LIGTABLE
   (LABEL O 25)
   (LIG O 55 O 26)
   (STOP)
   (LABEL O 33)
   (LIG C i O 36)
   (LIG C l O 37)
   (STOP)
   (LABEL O 40)
   (STOP)
   (LABEL O 41)
   (LIG O 140 O 275)
   (STOP)
   (LABEL O 47)
   (LIG O 47 O 21)
   (STOP)
   (LABEL O 54)
   (LIG O 54 O 22)
   (STOP)
   (LABEL O 55)
   (LIG O 55 O 25)
   (LIG O 177 O 177)
   (STOP)
   (LABEL O 74)
   (LIG O 74 O 23)
   (STOP)
   (LABEL O 76)
   (LIG O 76 O 24)
   (STOP)
   (LABEL O 77)
   (LIG O 140 O 276)
   (STOP)
   (LABEL C A)
   (STOP)
   (LABEL C F)
   (STOP)
   (LABEL C L)
   (STOP)
   (LABEL C P)
   (STOP)
   (LABEL C R)
   (STOP)
   (LABEL C T)
   (STOP)
   (LABEL C V)
   (STOP)
   (LABEL C W)
   (STOP)
   (LABEL C Y)
   (STOP)
   (LABEL O 140)
   (LIG O 140 O 20)
   (STOP)
   (LABEL C f)
   (LIG C i O 34)
   (LIG C f O 33)
   (LIG C l O 35)
   (STOP)
   (LABEL C r)
   (STOP)
   (LABEL C v)
   (STOP)
   (LABEL C w)
   (STOP)
   (LABEL C y)
   (STOP)
   (LABEL O 200)
   (STOP)
   (LABEL O 201)
   (STOP)
   (LABEL O 210)
   (STOP)
   (LABEL O 212)
   (STOP)
   (LABEL O 217)
   (STOP)
   (LABEL O 220)
   (STOP)
   (LABEL O 224)
   (STOP)
   (LABEL O 225)
   (STOP)
   (LABEL O 230)
   (STOP)
   (LABEL O 300)
   (STOP)
   (LABEL O 301)
   (STOP)
   (LABEL O 302)
   (STOP)
   (LABEL O 303)
   (STOP)
   (LABEL O 304)
   (STOP)
   (LABEL O 305)
   (STOP)
   (LABEL O 335)
   (STOP)
      (LIG O 55 O 26)
      (LIG C i O 36)
      (LIG C l O 37)
      (LIG O 140 O 275)
      (LIG O 47 O 21)
      (LIG O 54 O 22)
      (LIG O 55 O 25)
      (LIG O 177 O 177)
      (LIG O 74 O 23)
      (LIG O 76 O 24)
      (LIG O 140 O 276)
      (LIG O 140 O 20)
      (LIG C i O 34)
      (LIG C f O 33)
      (LIG C l O 35)

The relevant chunks are those of the form

   (LABEL O 41)
   (LIG O 140 O 275)
   (STOP)

which means that character "octal 41" (that is !) followed by "octal 140" (that is `) should be changed into the character in position "octal 275" of the font.

Similarly,

   (LABEL C f)
   (LIG C i O 34)
   (LIG C f O 33)
   (LIG C l O 35)
   (STOP)

means that f followed by i becomes the character in slot "octal 34", by f becomes "octal 33" and by l "octal 35". There's also an entry for "octal 33":

   (LABEL O 33)
   (LIG C i O 36)
   (LIG C l O 37)
   (STOP)

so the combination ffi becomes first "octal 33", then "octal 36".

If you want to disable the "ffl" ligature, you have to tell microtype to remove ligatures starting with "octal 33", which can be done as

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{microtype}

\catcode`\^^[=12 % for technical reasons

\DisableLigatures[^^[]{encoding=T1}

\begin{document}
ffl ffi
\end{document}

Since "octal 33" is not printable, one has to resort to a low level trick for specifying it (^^[, because the character code of [ is "octal 133"). The \catcode trick is because LaTeX, by default, declares invalid all non printable characters.

However you have no way, with the microtype method, to disable ffl and keep ffi.

enter image description here

1
  • 3
    I am really amazed that you can disable three-character ligatures this way – I would have thought that they would only be disabled if the first two characters were themselves input as \char'33. Great to know! BTW, microtype also understands octal, decimal and hex numbers, so you can simply say \DisableLigatures['33]{encoding=T1}, omitting the catcode trickery.
    – Robert
    Commented Apr 3, 2013 at 0:54
5

Regarding the above comment

"Unfortunately, I don't know a way how to find out the slot number of the ligatures from the typeset text."

I guess I do know a way - they can be extracted from a dvi. Since dvi is not very readable, the easiest way I know of doing this is with metapost, which will quite happily generate tex files, typeset them to dvi, input the dvi, decompose the picture and analyse. This is possibly not the best way!

Here is quick and dirty version of this:

input TEX

pair pt[];
string s[],temp_fname;
picture lig[][];

string fontname;

fontname="cmbx12";
minchar:=0;
maxchar:=127;


def charcount(expr obj)=
    begingroup
    if (textual obj): 
        (length textpart obj)
    elseif (picture obj) and (length(obj)>0) :
        (for $ within obj: charcount($) + endfor 0)
    else: 0
    fi
    endgroup
    enddef;

def charcodelist(expr obj)=
    begingroup save s; string s;
    if (textual obj):
        s:=textpart obj;
        (for i=0 upto (length s)-1:
                decimal(ASCII(substring(i,i+1) of s)) & 
            endfor ""
            )
    elseif (picture obj) and (length(obj)>0) :
        (for $ within obj:  charcodelist($) & endfor "")
    else:
        ""
    fi
    endgroup
    enddef;


% quickly generate a file with all possible character pairs, then read it back in
temp_fname:=jobname&"-temp.mp";

write "verbatimtex \font\myfont="&fontname&"etex" to temp_fname;
for i = minchar upto maxchar:
    for j = minchar upto maxchar:
        write "lig["&decimal(i)&"]["&decimal(j)&"]:=btex \myfont\char"&decimal(i)&"\char"&decimal(j)&" etex;"
            to temp_fname;
    endfor
endfor
write EOF to temp_fname;
scantokens ("input "&temp_fname)



beginfig(1)
    draw TEX("Ligatures in "&fontname) shifted (0,20);
    pt0:=origin;
    for i = minchar upto maxchar:
        for j = minchar upto maxchar:
            if charcount(lig[i][j])=1:
                draw char(i) infont fontname shifted pt0;
                draw decimal(i) infont "cmr10" shifted (pt0+20right);
                draw char(j) infont fontname shifted (pt0+50right);
                draw decimal(j) infont "cmr10" shifted (pt0+70right);
                draw lig[i][j]  shifted (pt0+100right);
                draw charcodelist(lig[i][j]) infont "cmr10" shifted (pt0+120right);
                pt0:=pt0+20down;
            fi
        endfor
    endfor
endfig;

bye

Which produces output like this:

enter image description here

2

Here http://www.gust.org.pl/projects/pearls/2005p/index_html (Testing whether two characters form a ligature by Petr Olšák) we can find a beautiful solution for two characters:

\newif\ifligature
\def\testligature #1#2{\setbox0=\hbox{%
   \thickmuskip=1000mu \textfont0=\the\font
   $\mathchar`#1 \mathrel\mathchar`#2$}%
   \ifdim\wd0>500pt \ligaturefalse \else \ligaturetrue \fi}

Adding loops is easy.

3
  • 1
    As it stands, this looks like a comment rather than an answer.
    – Joseph Wright
    Commented Jun 2, 2013 at 7:14
  • @JosephWright The code included. Commented Jun 2, 2013 at 15:04
  • It's more like part of an answer together with an idea for completion. As "additional" answers are allowed to add ideas and be otherwise complementary, I think it's fine as is :-) Comments occasionally get overlooked. Commented Jun 3, 2013 at 3:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .