Skip to content

Instantly share code, notes, and snippets.

@k16shikano
Last active October 15, 2019 06:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k16shikano/05b8328c51729c7c155c9ad706afcbf9 to your computer and use it in GitHub Desktop.
Save k16shikano/05b8328c51729c7c155c9ad706afcbf9 to your computer and use it in GitHub Desktop.
IIJセミナー2019年5月21日

狭義のTeXと広義のTeX、それぞれの進化

  • TeXの登場は1978年で、かなり古いアプリケーション
  • クヌースが開発を凍結した年でいっても1990年なので、やはりとても古い
  • 「それから何か進歩しているの?」←当然の疑問
  • 「そんなに古いソフトだから現代のコンピューター環境にそぐわない」←どこまで本当?

今日の話の結論

細かい話は「日本人の知らないTeX」(八登崇之さんの2010年の発表)にすべて書いてある。

とはいえ、この発表が意味するところを理解するには、もう少し前提知識の共有が必要だと思う。 それを紹介する。

なにが「TeX」か

そもそも「TeXとは何か」、それほどクリアに回答できる人が少ないのでは?

  • 一般の認識はたぶん、「コマンドで実行できるアプリケーション」。具体的にはこう。

    TeXの記法で原稿を書く
     ↓
    クヌースが作ったtexで処理する
         ↓
    DVIやPDFができる
    
  • 日本だとこうかも?

    LaTeXの記法で原稿を書く
     ↓
    クヌースのTeXをアスキーが改造したplatexで処理
      ↓
    DVIができる
    

この認識でなにか問題が?

デフォルトで使う分には、何も問題ない(そのように簡単に使えるように開発されている)。

が、Unixライクな環境に馴染んでいる人が、そこでの勘みたいなものに頼ってカスタマイズしようとすると、ちょっと困るかもしれない。

  • カスタマイズがしたい!(フォントを変更したいとか、キーボードで入力した文字を出したいとか、見た目を変えたいとか)
    • MS Wordのようなメニューがないのは仕方ない
    • どこかに設定ファイルがあるのでは?
    • 内蔵のプログラミング言語で挙動を変更できるのでは?

アプリケーションっぽく見えるのは「TeX」の氷山の一角

  • 氷山全体の成り立ちを意識せずに言う**狭い意味の「TeX」**は、「アプリケーションっぽく見えてるTeX
  • テクニカルな話をするときの**狭い意味での「TeX」**は、「エンジンまわりの技術

エンジンというのは、TeXのアプリケーションを作り出す(文字通りlatexとかtexとかのバイナリを作り出す)ための核となる部分。 以降は、主に「エンジンまわりの技術」のことを、「狭義のTeX」と呼ぶことにします。

注意: 「狭義のTeX」「広義のTeX」に対する技術的な定義やコンセンサスが既にある、もしくは必要である、という意味ではありません。 こんな感じに範囲を区別しておくと、「●●という概念や実装がどうして登場したのか」といった話をするときに、見通しがよくなるであろう、ということです。

狭義のTeX、つまりエンジンの変化は、根本的なゲームチェンジをもたらす。 いずれもクヌースのオリジナルからはかなり進化していて、いま広く使われているものはこんなにある。(注:クヌースの「TeX」はほとんど使われていません)

  • ε-TeX(使われているというか、他のものに組み込まれている。pTeXのε拡張対応は2010年)
  • pdfTeX
  • XeTeX
  • LuaTeX
  • (u)pTeX

ただし、どのエンジンを使うかは、使う人が選べる話である点に注意。 実際には、エンジンだけで狭い意味の機能が決まるわけではないので、LaTeX2e(とかConTeXt)のような「フォーマット」が提供する機能による影響を受のほうが大きいかもしれない。

これらのエンジンを使って「なんとかlatex」というコマンドを作り出すための機能群(LaTeXカーネル)も、特に近年はものすごい勢いで進化を続けている。 背景には、TeX Live 2015でlatexreleaseというパッケージが導入されて、それまでよりも大規模な挙動の変化を投入できるようになったことがあげられる。

TeXの全体像(広義のTeX)

広義のTeXは、3つの層に分けると考えやすい。

  1. 文章を入力する人から見たTeX → 「マークアップを指定する仕組み」に見える(HTMLのようなもの)
  2. 文章を組版する人から見たTeX → 「スタイルを設定する仕組み」に見える(CSSのようなもの)
  3. 仕組みを開発する人から見たTeX → 「プログラミング言語」に見える(JavaScriptのようなもの)

下の層に行くほど、TeXそのものやドキュメント技術についていろいろ調査研究が…(わるい意味で、はまる)。

広義のTeXはどんな点で進化しているか

狭義のTeXの進化と並行して、アプリケーションとしての広義のTeXも進化している。

  • 入力面の進化
    • ユーザーフレンドリーなシンタックス → マクロパッケージやクラスファイルの機能強化
    • 文字をキーボードで直接入力したい → 入力エンコーディングの進化
  • 出力面の進化
    • DVIは限界 → PDFやHTMLへの出力
    • いろいろな書体を使いたい → フォントの扱いの進化
  • 機能面の進化
    • もっときれいな組版結果になってほしい → マイクロタイポグラフィ対応とか、各種パッケージの開発とか
    • 複雑な図版や飾りを組めるようになってほしい → TikZ/PGF
    • 高度な機能を直観的にプログラミングできるようにしたい → Lua、expl3
  • インストールやメンテナンスの進化
    • TeX Live
    • CTAN

狭義のTeXの進化が必須なものもあれば、そうではない話もある。 今日は、両者がからみあうのが面白いという理由から、「入力エンコーディングの進化」と「フォントの扱いの進化」について少し掘り下げてみます。

【事例1】入力エンコーディングの進化

クヌースのオリジナルのTeXは、7ビットのASCIIであった。 TeXバージョン3(1990年3月)で8ビット化したけれど、128~256("?~"FF)の文字の扱いはあいまい(『TeXブック』付録Cを読む限り)。

狭義のTeXが内部で扱える文字は、1997年のpdfTeXでも8ビット長のまま。 狭義のTeXの進化は、Unicodeを直接扱えるエンジンとしてXeTeX(2004年)やLuaTeX(2007年)の登場を待つことになる。

(参考:encTeXという、UTF-8な入力をとって256個までのTeXの内部表現やコマンドにマッピングできる拡張は提案されたことがある)

しかし、その間にも広義のTeXでは進化が続いていて、最終的にはUTF-8をはじめ、多バイトの読み込みにも対応した。

inputencパッケージ

まず、LaTeXの機能を使ってinputencパッケージが作られた。 256文字までのエンコーディングでは、8ビットめを使っている文字をひとつひとつコマンドとして定義してあげるという仕組み。 これで、欧米のアクセント付きの文字やキリル文字、ギリシア文字などが入力できるようになった。 256文字以上あるUTF-8についても、LaTeXマクロでデコードすることで読めるようになった。

TeX Live 2018では、inputencにより、ついにUTF-8がLaTeXにおける入力のデフォルトになる。

inputencは、8ビット以上の文字をすべて「TeXのコマンド」扱いにする(TeXでは文字を\defできる)。 そして、それらの「コマンド」の定義を、LaTeXが7ビットの組み合わせで表せる標準的な文字とする。

utf8の場合は、さらに、後ろの1~3バイトを「引数」としてとるコマンド、という扱いにする。 たとえば、ある文字が0xC3(195)だったら、

11000011

なので、これがUTF-8の入力であれば、2バイト長の文字(の1バイトめ)であるはず。 そこで、この8ビットを「TeXのコマンド」として、次の1バイトをその引数とみなす。

たとえば、後ろに0xA4(164)が並んでいるなら、これはUnicodeの「ä」だと考えられるので、内部では「\"a」として処理する、という具合。

CJKパッケージ

この方法と同じ手法で、CJKパッケージも作られている。 これも、8ビットめを使っている文字をひとつひとつコマンドとして定義してあげて、LaTeXマクロで入力の文字列をデコードする。

ちなみに、出力に使うフォントのグリフにも256個の壁があるが、これにはサブフォント化という手段で対処しているとのこと。(参考

XeTeX/LuaTeX

狭義のTeXで入力エンコーディングが拡張されるには、XeTeXの登場を待たなければならない。

XeTeXは、完全なUnicodeとして入力の文字を読み込み、エンコーディングもUTF-8だけでなくUTF-16にも対応しており、UTF-32も選べる。

LuaTeXも、完全なUnicodeとして入力の文字を読む。エンコーディングはUTF-8。

一方日本では、日本語を入力するためにpTeXが作られ、これがUnicodeを扱えるように進化してupTeXになった(2007年頃)。

【事例2】フォントの扱いの進化

もっとも初期は、クヌースが作った12種類くらいのフォントがあり、これらをコマンドで切り替える方式だったらしい(参考)。

いまでも、TeXにおけるフォント切り替えは、基本的にはこれと同じノリ。

\font\myfont=myfont at 12pt
% myfont.tfmを自分で用意する必要がある

これで、\myfontというコマンドができて、myfont.tfmというフォントに切り替えられるようになる。

ただしこれは、「PDF上にmyfont.tfmという名前のフォント(と通常みなされているもの)で文字が表示される」ということではない。 myfont.tfmというのは、「「対応するフォント」で文字を組んだときに紙面にどれくらいの大きさの箱ができるか」という情報。 だから、PDFに表示されるべき「対応するフォント」が必要になる。

tfmから、エンコーディングに従って実際のグリフを選び出すために、dviドライバはmapファイルを使う。

さらに、TeXがtfmを参照してメトリックのみを見るのと同様に、 DVIウェアが参照する仮想的なエンコーディングを記したファイルを用意すれば、 個々のグリフとフォントのファイルが一対一に対応している必要もなくなる。 これがvf(仮想フォント)。 1990年ごろに導入された(参考)。

というわけで、狭義のTeXにおけるフォントというのは、実際のグリフを含んだファイルを呼び出して使うものではなく、 あらかじめ準備したtfmとして仮想化されたファイルを切り替える仕組みである。

LaTeXにおける抽象化

LaTeXでも、このTeXの枠組みを使う。 最初のころ(NFSSが登場する1989年より前まで)は、ほぼそのままTeXのフォント切り替えと同じことしかできなかったらしい。 つまり、同じフォントで太字にしたい、とか、フォントの大きさを変えたいとか、そういったことをするにも、そのための\myfontを逐一定義しないといけなかった。

この枠組みを抽象化して、「フォントを選ぶときの利用者の直観」にそったインターフェースを提供したのが、NFSSという仕組み(1989年に導入)。 具体的には、NFSSではフォントを次の属性の組み合わせで選べるようになった。

  • エンコーディング
  • ファミリー
  • シリーズ
  • シェイプ
  • サイズ

そして、これらをフォントごとにあらかじめ設定しておける。 具体的には、.fdという拡張子のファイルにこんなふうに指定しておけば\myfontみたいなのが定義され、さらにファイル名からエンコーディングとファミリーに対応したtfmを探してくれる。

\DeclareFontFamily{エンコーディング}{ファミリー}{}
\DeclareFontShape{エンコーディング}{ファミリー}{シリーズ}{シェイプ}{tfmとの対応}{}
...

これでドキュメント内では、LaTeX的に抽象化されたフォントファミリー名(\rmfamilyとか\sffamily)とかシリーズ名(\bfserieseとか)でフォントを選べるようになる。 また、こんなふうにしてフォントを一時的に利用したりもできる。

\usefont{エンコーディング}{ファミリー}{シリーズ}{シェイプ}

fontencパッケージ

ただしこれだけだと、入力されてきた文字のエンコーディングと、利用するフォントのエンコーディングが、一致していることが前提になってしまう。 フォントのエンコーディングが違ったら、期待していたのとは異なるグリフが出力されてしまう。

そこで、これを調整するために、通常はfontencパッケージを使う必要がある

もちろん、そのエンコーディングのフォントも必要。 たとえば、8ビットTeXのエンコーディングであるT1エンコーディングで、7ビットTeX用のOT1エンコーディングのフォントを使えば、アクセント記号などで不具合が生じることがある(この例だと、画面上では表示されるけれどコピペするとおかしくなる)。

\usepackate[T1]{fontenc}
\usepackage{lmodern}

非欧文フォントは?

ここまでの話は、あくまでも8ビットまでのエンコーディングで、かつ、フォントのエンコーディングが欧文LaTeXで標準的に用意されているものな場合。

たとえば、多バイト文字のフォントを出力するには、さらに別の仕掛けが必要になる。

もちろん、pTeXのように、狭義のTeXで多バイト文字のフォントを出せるエンジンを使っている場合なら問題ない。 そうでない、pdfLaTeXなどで多バイト文字のフォントを使うには、やはりCJKパッケージを使うことになる。

狭義のTeXにOSのフォントを使わせる

というわけで、NFSSとCJKによって、(pdf)LaTeXの利用者は狭義のTeXの利用者よりも柔軟にフォントを選べるようになった。 ただし、あくまでも「狭義のTeXでフォントが使われる仕組み」をLaTeX内で抽象化したものなので、tfm/vfやmapの準備といった、「狭義のTeXでフォントが使われる仕組み」のためのお膳立ては依然として必要である。

では、その部分を不要にすることはできないだろうか?

そのための手段として考えられるのは、

  • 狭義のTeXを改造して、OSにインストールされているフォントを直接読み込めるようにする

これをやったのが、XeTeX。

LuaTeXでも、Luaを使えるので、TeXの処理中に動的にフォントを読み込んだりOTFの機能を使ったりするフックを仕掛けられる。 そこで、これを利用したluaotfloadパッケージにより、OSにインストールされているフォントを直接利用できる。

狭義のTeXが変われば、抽象化の方法も変わる

こうして、狭義のTeXにおいてフォントの読み込み方が変わったので、それに合わせてLaTeXの抽象化のインターフェースも変更する必要が生じた。 そのために、以下のようなパッケージが利用されるようになった。

というわけで現在は、こんな感じの使い方が一般的(欧米)

  • 狭義のTeXがUnicodeに対応しているなら、LaTeXではfontspecを使う
  • 狭義のTeXがUnicodeに対応していないなら、LaTeXではNFSSとfontencを使う

日本語や中国語のフォントについては、こんな感じ。

  • LuaLaTeXなら、luatexja-fontspecパッケージ(luatexja+fontspec)
  • XeTeXなら、xeCJKパッケージ
  • (pdfTeXなら、CJKパッケージ)

ただしいずれの場合も、黙ってBXjsclsを使うのが日本語なら楽かもしれない

DVIウェアの機能を使う方法

番外として、狭義のTeXには手を入れずにDVIウェアの機能を使ってフォントをファイル名で選択できるようにする、という手もある。 これをやっているのがpxchfonというパッケージ。 基本的には、DVIウェアに最終的に使ってほしいmapファイルをTeXの処理時点で仕込んでおく、という仕組み。

まとめ

  • 広義のTeXは、近年になってむしろ開発が加速している
  • 狭義のTeXも、進化しており、さまざまなアプローチで多様化が進んでいる。統一される気配はない
    • ただし、エンジンごとにプリミティブがあったりなかったり名前が違っていたりするとLaTeX3の開発で困るので、LaTeX3チームが積極的に調整している印象
  • 「従来どおりの美しい組版を犠牲にせず、より簡単に多様な目的を実現できるツールを目指そう」というのがTeXコミュニティーに共通する開発の雰囲気
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment