SUBMENU

dvioutのフォント検索の仕組み

このドキュメントでは、あるフォントを使うときに、TeXで組まれてdvioutで出力されるまでの流れについて説明しています。少なくとも現時点で基本的と広く考えられている範囲の使用においては、ここに記した情報は必要ありません。なお、ここに記した情報の一部は、2001年1月17日以降のdvioutの動作に基づいています。

TFMファイル

TeXで文書を組むときの基本は、当然ながら文字配置です。文字を適切に配置するために、TeXはTFM(TeX Font Metric)ファイルというTeX用の配置情報ファイルを参照します。このTFMファイルには、一般に欧文の場合、それぞれの持つ文字の字幅、特定の文字の組み合わせに応じたツメやアキの量、あるいは特定の順序で文字が現れたときの置き換え規則(合字)、さらには単語間や文間の基本的なアキ量などが記されています。ただし、この単語間のアキ量などは実際にはTeX側のマクロと連動して動作し、実際にどのような値が採用されているかなどはわかりません。より細かくいえば、単語間のアキ量などは厳密にはそのフォントのメトリック情報ではなく、TFMファイルの参考値として記載されているだけです(これは、フォントパラメータと呼ばれます)。

一方、和文の場合は、いくつかの「文字クラス」に分類が行われます(pTeXの実装に限定した議論を行います)。大雑把には、一般の文字類や、約物と呼ばれる括弧類、句読点類などの同じ規則で組まれる文字の集合が定義され、それらの文字ごとに文字の大きさが記載されています。和文フォントの文字クラス間にはリガチャーといった量は定義することはできませんが、カーンやグルーを記載することができます。これら両者の違いは、通常のTeXでの動作と同じく、カーンであれば行分割は禁止であり、グルーは伸縮可能かつ行分割可能ということです。ところが、pTeXが和文用のTFMファイルを参照して組み版処理を行い、一旦DVIファイルを出力すると、そのDVIファイルをいくら見ても、各文字クラス間のグルー値としてそのTFMファイル内になにが設定されていたかは決して判断できません(十分な精度で推測をしようと思えば不可能ではありませんが)。その意味で、和文TFMファイルに記されている文字間に挿入するグルー量は厳密にはフォントのメトリックではありません。つまり、それらのグルー量を勝手に変更されたTFMファイルを見ても、DVIウェア側は(チェックサムをのぞけば)pTeXの組み版処理時に参照されていたTFMファイルかそうでないかを判定する方法はなく、また何の矛盾も発生しないというわけです。たとえば、よく知られているmin10フォントにおける拗促音符間のグルー量を適切に修正したとしても、既存のドライバ類はいっさいの変更を受けることなくその修正されたmin10でそれまでと全く同じ出力を行います。

以上に見たように、同じTFMファイルといっても欧文用のものと和文用のものは本質的に異なる概念です。また、文字コードをUnicodeで統一したOmegaシステムにおいても、日本・韓国・中国系の組み版処理を実現するにはpTeXと同じような方法を採用することが現実的だとみなされるようになってきており、OmegaシステムにはpTeXモードが搭載されるという旨の表明も行われています。そこで、本稿では単にTFMファイルといった場合には和文と欧文の区別を問わずに用いることにします。和文専用のTFMファイルについて言及するときには、「和文TFM」と明記するか、あるいは「JFM」と記述します。さらに、特に欧文フォント用のTFMファイルについてのみ言及する際には「欧文TFM」と記述します。

TeXの組み版処理

TeXの組み版処理の中でもっとも大きな部分は、いうまでもなく文字を適切に並べる部分です。そしてこれは、TFMファイルに記されたメトリック情報によって行われます。すなわち、TFMファイルに記された文字幅や文字間のアキ量の規則に従ってただ文字を並べるだけです。もちろん、行末を適切にそろえるために、欧文の場合には単語間のアキ量を、和文の場合には各文字間のアキ量を適切に調整しなければなりません。いずれにせよ、TeXでの組み版処理の命は、文字配置情報を記したTFMファイルということになります。また、文字の配置に関してはTeXはTFMファイル以外の情報を参考にしません。つまり、そのTFMファイルが何らかの形式のビットマップフォントを想定したものであるのか、TrueTypeフォントであるのか、PostScript用のフォントであるのか、はたまたWifeman(Windows Intelligent Font Environment Manager, TrueTypeフォント出現以前のWindows3.0などで用いられていたもの)フォントであるのかなどはいっさい問題にしません。実際にその組み版結果にグリフ(文字の字形データ)を当てはめて画面やプリンタに出力するのはDVIウェアの作業となるからです。TeXが組み版できるのは任意の形式のフォントであり、TFMファイルが準備されたすべてのフォントです。ただし、それを出力できるのは、意図したフォントに対応したDVIウェアが存在する場合に限られます。

すべてのフォントは何らかの形でその文字のデザイナーが決めた適切な配置情報を持っています。それらは一般にはTFM形式ではありません。TFM形式で配置情報を出力するフォントシステムとしては、代表的なものにMETAFONTシステムがありますが、多くのものはTFM形式ではメトリック情報を保持していません。しかしながら、その配置情報をTFM形式に変換することは可能です。一般にTFM形式は非常に細かな情報を記録しておくことができるので、TFMに変換することで元々のデザイナーが意図した配置情報の精度が失われたりすることはないといってよいでしょう。一旦そうしてTFMファイルができあがると、そのフォントはTeXで組むことができます。

この文書ではDVIファイルの詳細な構造についてはいっさい議論しませんが、foo.tfmというTFMファイルを参照して組み版処理を行うと、TeXはその部分について"foo"というフォントで組み版を行ったということが記載されます。注意してください。「"foo.tfm"を参照した」と記載されるのではなく、「"foo"を用いた」と記載されているのです。そうしてDVIファイルには用いられたフォント名の一覧表が付加されます。たとえばあるDVIでは「1:cmr10, 2:cmtt10, 3:cmr10 scaled 1095, 4:min10」のように使われたフォントの一覧表が作成されます。注意してください。1番と3番は共に元々は同じフォントですが、拡大率が異なるので当然メトリックも異なるものとして扱われ、別々のフォントとして記録されます。実際のDVIファイル中では、「1番のフォントの125番目の文字」のような情報が記載されています。DVIウェアの仕事は、この情報が記された位置に、実際にcmr10フォントの125番の文字を当てはめて出力することになります。

そこで、ここから以降はdvioutの動作について述べていきます。

TEXPKパラメータ

dvioutがDVIファイル内に記されているフォントに対して、それらを実際の物理的なファイルと対応させる情報は、主にTEXPKパラメータに記されています。つまり、TEXPKパラメータはDVIファイルを実際に出力するために最も重要な設定項目です。TEXPKはたとえば次のように記されています。

TEXPK=^r\\^s.^dpk

ここで"^r"はTEXROOTというパラメータの値で、これはフォントが格納されている場所の起点を表わす量です。"^s"は最も重要なもので、DVIファイル中に記されているフォント名です。すなわち、"cmr10"や"wnsr8t"、"min10"のような文字列が対応します。"^d"はそのときのdvioutに対して設定されている出力解像度です。通常は300,360,600などの値です。"\\"という指定は、そこより下位のディレクトリを再帰的に検索することを意味します。ディレクトリとはフォルダの元になる概念で、ディレクトリに対してOLEと呼ばれる「メソッド」が定義されたオブジェクトをフォルダと呼んでいます。最近はフォルダの方が一般に通用する概念であるため、フォルダからファイルのドラッグアンドドロップやメニューのような機能を取り除いたファイルの実体が格納されているものをディレクトリと呼ぶと考えてください。ここであえてこの区別を行うのは、「フォルダ」で表示されるファイルの名前というのはあくまでもOLEを介するものであるため、「ディレクトリ」で表示されるファイルの名前と異なることがあるからです。たとえば、Windowsのフォントが格納されている「フォントフォルダ」のファイルの実体はたとえば「c:\windows\font」ディレクトリに格納されていますが(このディレクトリは、たとえばエクスプローラで参照するとフォント「フォルダ」です)、このディレクトリにおそらくtimes.ttcという名前で存在するファイルは、このディレクトリをフォルダとして参照すれば、"Times New Roman"という名前です。ディレクトリを操作するコマンドである"copy"コマンドを使用してあるTrueTypeフォントをc:\windows\fontsディレクトリにコピーしてもそのフォントはWindowsシステムでは使用可能になりませんが、エクスプローラを利用してc:\windows\fonts「フォルダ」にコピーすれば、そのフォルダのOLEのコピーメソッドが呼び出され、Windowsへの登録作業も行われるという具合です。この違いをここで強調するのは、dvioutはあくまでもディレクトリとしてTEXPKのパスを解釈するためです。Windowsのシェルであるエクスプローラが提供している(実際には"shell.dll"というプログラムが動いている)フォルダ機能は利用することができません。

dvioutはDVIファイル中に記されているフォント名をTEXPKパラメータの^sに代入しながら、実際に使用すべきファイルを検索します。TEXPKには複数の指定をセミコロンで並べて記述することができます。たとえば次のような記述を考えましょう。

TEXPK=c:\fonts\^s.pk;c:\fonts\^s.tfm

そして、DVIファイルにたとえば"cmr10"とあったとします。すると、dvioutはTEXPKの記述に従い、まずc:\fonts\cmr10.pkの存在を確認します。存在すれば、それをcmr10用に用いるべきものとして記録します。存在しなければc:\fonts\cmr10.tfmファイルの存在を確認します。存在すれば、やはりその位置を記録しておきます。もし存在しなければ、一般にdvioutは"gen"の設定に従ってフォントを生成しようとします。ここで別のパラメータであるTEXFONTSパラメータなどが関与してくることもありますが、複雑となるので省略します。一般的には"gen"が設定されていることと思われますので、TEXFONTSは参照されません。"gen"に従ってフォント生成が試みられると、再びTEXPKの設定に従って使用すべきファイルを探し、記録します。ここで見つからなければ、エラーとなり、探そうとしたファイルの一覧と共にメッセージが出力されます。一般にTEXPKは複数のパスが記されていますし、dvioutは^dには若干のゆとりを持たせていますので、エラーメッセージには複数の探そうとしたフォント名が記されていますが、実際に必要となるのはそのうちの(当然ながら意図した)1つのものです。

ただし、仮想フォントの場合だけはやや動作が異なります。仮想フォントの場合、多数のフォントを組み合わせることもあり、そしてある特定のユーザをのぞいて現実に使用されることがないフォントへの参照が入っていることもあります。そのため、dvioutはTEXPKの検索時、仮想フォントに関してはそのフォントを展開して検索することはありません。従って、仮想フォントファイルさえあれば、その中で実際に使われているフォントの存在は、TEXPKの確認時には調べられません。つまり、仮想フォントに関してだけは、実際のフォントの存在は、そのフォントが実際に用いられようとしたときになって初めて確認されます。たとえば2ページ目で初めて仮想フォントが現われるとすると、1ページ目表示の時には仮想フォントの存在だけが確認され、2ページ目を表示しようとしたときに初めて仮想フォントが実体のあるフォントと結びつけられるようになり、必要ならば実際にフォントを作成するなどをしたのちに出力が行なわれます。もし存在しなければ、空白が出力されます。

dviout内蔵フォントの検索

実は、dvioutはTEXPKよりも前にフォントファイルの検索を暗黙に行います。それは、dviout自身が内蔵しているmin系、jis系などの和文TFMファイル群です。もしDVIファイル中にmin10などが見つかると、dvioutは内蔵されているフォントで該当するものがないかを探します。min10の場合、dvioutの内蔵フォントが有効となっていればそれが用いられるため、TEXPKは検索されません。

TFMファイルが見つかった場合の動作

さて、TEXPKが次のように記述されているとしましょう。

TEXPK=^r\tfm\\^s.tfm;^r\pk\\^s.^dpk;^r\vf\\^s.vf
これはかなり一般的な設定です。

まずTFMファイルを探し、見つからなければPKファイルを探し、それでも見つからなければVFファイルを探します。それでも見つからなければ、"gen"パラメータに従って自動生成を試みます。見つかったら、それが出力に用いられるものとして記録されます。実際にそのファイルが読み込まれるのは、そのフォントが実際に初めてDVIファイル中で使用されたときです。

と、このように書くと読者は大いなる疑問にさらされます。一般に、TeXがインストールされている環境では、たいていのTFMファイルはシステム中に存在するはずです。従って、上記のようなTEXPKの設定では、現実問題として、dviout内蔵でないすべてのフォントがTEXPKの先頭に記されたTFM検索で見知され、それが記録されるはずです。決してPKやVFの検索が行われないように見えます。

この問題がdvioutのフォント検索におけるもっとも複雑な点です。dvioutはtfmファイルを見つけると、実際には補助的な作業を行って、そのTFMファイルを使用すべきものとして記録してよいのかどうかを確認します。それはdvioutのプロパティシートの[WinJFont]ページで設定されています。dvioutはTFMファイルを見つけると、まず"ftt"パラメータを参照して、必要ならばフォント名の変換を行います。"ftt"は(おそらく)Fontname Translation Tableの略で、「フォント名変換表」です。

その後の確認作業は、和文TFMと欧文TFMで動作が異なります。欧文TFMならば、[WinJFont]ページでそのフォント名に対して使用すべきフォントが指示されているか、あるいはedefaultパラメータが定義されているならば、そのフォント名がWindowsのシステムに登録されているかどうかを確認します。もし存在すれば、その時点で初めて「TFMが存在した」と判定され、使用すべきファイルとして記録されます。一方和文TFMの場合には、とにかくそのTFMファイルは使用すべきものとして記録されます。実際に使用する段になって実は未定義であったということになれば、"default"や"tdefault"が出力に使用されるということになります。

注意してください。この設定では、和文VFは参照することができません。なぜなら、和文VFを参照する意図があったとしても、そのVFに対応するTFMが必ず存在するので、そのTFMは常に使用されるものとして記録されてしまうからです。ただし、例外として"ftt"パラメータにおいて、フォント名を"-"に変換するように指定した場合、そのTFMは記録されずに次のステップに進みます。

これは、欧文TFMと和文TFMで動作が異なるので、違和感を与えます。このような仕様になっているのは、和文TFMは対応するフォントが存在しなくても原則として文字のメトリックは同一(全角基準)であるため、全く異なる書体で代用してもそれほど問題にならないという事情があります。つまり、[default], [tdefault]で代用することを想定しているので、和文TFMはとにかくTFMが存在した時点で出力可能と判定しているのです。もしも和文TFMについても欧文TFMのように、定義が存在するかシステムに登録されているときに限りそれを使用するようにしたければ、"^s.tfm"ではなく、"^s^tfm"と記述しておきます。いずれにせよTFMファイルは検索されなければ出力できないので、TEXPK検索中にTFMファイルを検索させるという作業は必要です。"^s^tfm"と書くと、和文用であれ欧文用であれ、そのTFMに対応する定義(あるいは[edefault]経由でのシステムフォント)が見つからなければTEXPKの次のステップに移ります。つまり、[default]や[tdefault]は見つからなくなります。つまり、

TEXPK=^r\tfm\\^s^tfm;^r\pk\\^s.^dpk;^r\vf\\^s.vf

のようにしておきます。これで、和文VFを使用することができるようになります。(もちろん、最初の設定のまま"ftt"でTFMを参照したくないフォント名を"-"に置換してもかまわない。)ただし、これでは定義されていない和文TFMはエラーとなるので、

TEXPK=^r\tfm\\^s^tfm;^r\pk\\^s.^dpk;^r\vf\\^s.vf;^r\tfm\\^s.tfm

としておけば、最後の指定で[default]と[tdefault]が参照されるようになります。

min10.vf

ところで、min10.vfは通常の設定の枠内では、どのようにしても参照されず、従ってrml.tfmファイルはdvioutのTEXPKの検索で見つかることはありません。それは、dvioutはminというフォントメトリックを内蔵しており、それはTEXPK検索よりも先に実行されるからです。もちろん、どのフォントが使われるかは、通常のTEXPKでTFMファイルが見つかった場合と同一の動作を行います。PostScriptプリンタでの出力を考えている場合、min10.vfを経由してrmlを参照しなければならないのでそれとの統一を持たせたいと考える人もいるかと思いますが、そのようには考えないでください。もちろんオプションで切り替えることができますが、dvioutの標準の動作は、min10.vfを参照してrmlを出力用に用いた場合、dvipsとは異なる出力を行います。(これを試すには、dvioutの内蔵TFMを無効にし、minへのフォント定義を無効にし、rmlの出力フォントを定義すればよい。minを無効にする代わりに、min10.tfmよりも前にmin10.vfが見つかるようにしてもよい。)同じ出力をしたければ前期の作業に加えて、[Adjust baseline]を無効にします。この理由については、別ドキュメント「min10について」を参照してください。

Fontname Translation Table

現在、"ftt"パラメータはTFMが見つかったときにフォント名を変換するために用いられています。これは、そのような変換を行った後、[edefault]に従ってシステムにフォントの存在を問い合わせるために用いられます。たとえばwnsr8tというフォント名は、wnsr8t.vfによってwnsr8rに変換され、wnsr8r.tfmはfttパラメータによって"Times New Roman"に変換されるようになっています。そして、これはシステムに問い合わせが行われ、"Times New Roman"というシステムフォントが使用されるようになっています。これは事実上見つかったtfmファイルに対して使用するTrueTypeフォントを対応させる表として機能するものだと理解すれば十分ですから、"ftt"パラメータには"ttfonts.map"のようにTrueTypeフォントへのマッピング規則を記述したファイルを書いておくようになっています(一番最初の例からそうなっています)。

しかしながら、フォント名変換は他の箇所でも必要な場合があります。TEXPKに記載されるのは、TFM, PK, VF あるいはそのアーカイブ形式(FLIやGTHなど)だけではなく、たとえば、TTCも可能です。すなわち、TrueTypeフォントのファイル実体を指示することも可能です。TrueTypeフォントの配布ファイル名は、TeXで直接用いることができない形式であることも多く、システムに登録しないで使用しようと思えば、この機能を利用するしかありませんが、ファイル名の差異は大きな問題になり得ます。たとえばTT0088.ttfというTrueTypeフォントに対しては、わかりやすさなどの点からも、TeXではもっと意味ある、たとえばBerry則に従った名前に変えることが通常です。しかしながら、TT0088.ttfをリネームしてコピーしておかなければならないのでは煩雑です(TrueTypeキットの作成ツールでは一旦自動的にリネームするようになっているので、個人用途で自分の環境で閉じたものを作成するならそれで対応は可能)。しかしながら、fttパラメータを拡張してこれに対処することはできません。すなわち、TrueTypeフォントのフォント名はファイル名とは一般に無関係ですから、あるTFMファイルを、システムに登録されているフォント名と、その実体であるファイル名との両方にマップする事はできないからです(もちろん文法を拡張すれば不可能ではありませんが、煩雑になります)。

そこで、フォント名を変換してからそれに対して検索をかけるような仕組みが必要となるであろうと想像されます。この機能はまだ実装されていませんが、本来最初に意図したようなfttパラメータの使い方となるであろうと考えられます。

なお、ttcなどのファイルをTEXPKでヒットさせた場合、TEXFONTSパラメータに対応するTFMファイルを記さねばなりません。(記さなければそのTrueTypeに記されているメトリックを利用します。)これはまたTTCの名前と異なり、TeXで用いられたものですから、あるフォントに対して異なる名前での検索が必要ということになり、かなりやっかいな処理が必要となるでしょう。将来的にも実装されることがあるかどうかは定かではありません。現状ではTrueTypeフォントを利用するときには必ずTEXPKのTFM経由でシステムのフォントを用いるようにし、使用したいTrueTypeフォントをシステムに登録する方が無難でしょう。(Computer Modernではこのような仕組みは必要ありませんが、それでもシステムに登録するよう推奨しているのは、dviout内蔵のTrueTypeラスタライザよりもシステムのものの方が性能が高いからです。特に解像度が低い場合に顕著になります。)それでなくてもTEXFONTSパラメータの動作はややこしいので、あまり立ち入らない方がよいように思います。

dviout のフォントキャッシュ

一般にシステムの中にインストールされている TeX 用のフォント、特に TFM, PK, VF 類はきわめて多数になります。dviout は TEXPK の設定に従って目的のフォントを探しますが最悪の場合、一つのフォントについてすらシステムにあるこれら全ファイルを探す必要が生じます。これは莫大な作業となります。しかしながら、特に1つの原稿を扱っている場合には(また実際に多くのユーザの使用法では)用いられるフォントは限定されたものです。従って、ほとんどすべての場合において、TEXPK は「万一使われているdviファイルを受け取った場合」、「将来使うかもしれないという希望」などのために不必要に汎用的な設定になっています。しかしながら逆に、ほとんどのユーザにとって、自分がどのフォントを使うつもりか、あるいは使っているのかを把握するのは困難なことで、TEXPK の設定は汎用的なものとせざるを得ない実状もあります。そこで、可能な限りはやくフォントを見つけるための努力が必要です。そこで、dviout は最近使用したフォントに関して、その位置をおぼえるようになっています。莫大な数を使っていて、しかもそれらに共通部分のほとんどないようなファイルを交互に表示しているような場合、このキャッシュは効きません。キャッシュというのは、高速化のために既読のデータを保存する場所のことを一般にそのように呼びますが、キャッシュ検索の結果そこになかったファイルに対してあまり速度を低下させるわけにいかないので、キャッシュは大きければよいというものではないからです。dviout は原則として自動的に最近使用されたフォントをキャッシュに格納します。そのため、ユーザは一般的にこれを意識する必要がありません。ただし、ディスク上の位置を確認しなくてもよくするためのメカニズムがキャッシュですから、当然ながらキャッシュに格納された情報と実際とが矛盾していた場合にはおかしな動作を引き起こすおそれがあります。特にキャッシュは一般ユーザの目に触れられないような情報で格納されているので、ファイルの位置をいくら確認しても原因不明の問題に悩まされる可能性があります。そのような場合、キャッシュを「フラッシュ」する、つまりキャッシュした内容を総て忘れ去るようにdvioutに指示する必要があります。それには、[Font2]ページの[Flush]ボタンを押します。さて仮想フォントを扱う場合、フォントキャッシュのメカニズムは以上では自明でありません。なぜなら、仮想フォントはそれ自身が他のフォントを呼び出すからです。たとえばある仮想フォントが莫大な(数十個以上の)フォントをさらに呼び出していたとしましょう。すると、その仮想フォントを呼び出した瞬間、キャッシュがあふれてしまいます。dviout 3.11ではこのフラッシュの機構に重大な不具合があり、自分自身の所在すら失う可能性がありました。そのため、Omega-jで使用されているような莫大な数のフォントを呼び出す仮想フォントをdvioutが探そうとすると、キャッシュが完全に無効な状態で無数のフォント検索が行なわれることがありました。dviout 3.12ではここは改善されており、その種の仮想フォントを呼び出したときにも検索の速度が著しく低下するということはなくなりました。(この種の検索アルゴリズムの不具合は莫大な時間を消費してしまいます。)なお、dviout 3.12ではフォントの所在は、そのフォントが使用された時点で初めて決定されるようになりました。([Font2]ページの[Fod]パラメータ)