Linuxのフォント

このテキストについて

このテキストは次の授業で使用されている標準化された教材です。

  • Linux基礎

実際の授業では解説が加わる上に、生徒様に合わせて教材は制作・調整されるため、 このテキストよって得られる理解がMimir Yokohamaの授業のすべてではないことを予めご理解ください。

Linuxのフォント

Linuxでのフォントの扱いはX Window Systemによって提供されています。

フォントの基礎

フォントとは

文字が何を意味するかはデータ的に確定できます。 例えばUTF-8において0xe3 0x81 0x82は「あ」を意味します。 「あ」はUnicodeにおいてU+3042 Hiragana Letter Aとして定義されています。

日本人ならば U+3042 Hiragana Letter A と言われればおおよそどのような形をしているかは想像できるでしょう。 しかしながら具体的な形は確定できません。加えて、この情報の中にはHiragana Letter Aがどのような形をしているかという情報は含まれていません。

例えば U+1F354 Hamburger はハンバーガーであることはわかりますが、どのような形をしたハンバーガーなのかは不明です。

フォントは文字ごとの具体的な字形(グリフ)を定義します。 フォントを使うことで文字を視覚的な情報として表示することができるようになります。

フォントソフトウェアの開発と配布

フォントは自動生成技術も存在はするものの、多くの場合一文字ずつ制作していかなければならない作業です。 美的感覚も関わることであることから様々なフォントソフトウェアが存在し、配布・販売されています。

欧文書体と比べ和文書体は非常に多くの文字を必要とすることから比較にならない労力がかかります。

アートワークは一般に比較的曖昧なライセンスによって配布されることの多いものですが、フォントソフトウェアの場合作業量が非常に多いこともあってそれほどの数があるわけではありません。 場合によっては「十分にフリー」なフォントソフトウェアが存在しないためにフリーソフトウェアシステムの世界全体に影響を与える場合もあります。

無料で使用できるフォントは数自体はそれなりにあります。 ただし、アートワークという性質上ソフトウェアやライセンスに詳しくない人が作成する場合が多く、「利用条件が不明瞭」「不完全なライセンス」という問題がある場合が多く、あまり安心して使用することができません。

フリーなフォントソフトウェアのライセンスとして一般的なのはSIL Open Licenseですが、これに従ったライセンスは源ノ角ゴシック/源ノ明朝/源ノ角CodeJPなどのフォントがあります。 このほか、フリーソフトウェアとして取り扱えるライセンスを持つものとしてM+フォントやIPAフォントがあります。

一方、フォントは商用ソフトウェアとして有力なものでもあります。 価格としては欧文・和文問わず数百書体数千円程度のものから、1書体4万円程度のものまで様々。 和文商用書体においては年間3万円から6万円程度のサブスクリプション制度が主流となっています。

Linuxにおいて高額な商用フォントが使われることはあまり多くありません。 これは、高額な商用フォントを個人で使うこと自体少ない上に、これらのフォントはアートワーク向け、あるいは印刷向けでを想定しているため、Linuxの用途としてあまり一般的なものではないためです。 かつてはTeXによる論文のために高額な商用フォントが使われることもありましたが、現在はそのようなこともなくなりました。

もうひとつ、商用フォントソフトウェアのライセンスが慣例的にOSを含めるものになっており、Linux上で利用すること自体が微妙な問題を含む場合が多いという理由もあります。

他環境におけるフォントソフトウェアとメトリック互換フォント

Linuxという環境は決して主流ではありません。世の中はWindowsあるいはMacシステムが圧倒的に多く、それを前提として世の中は回っています。 数としてLinuxがそこまで少ないわけではないのですが、知識に乏しい人がLinuxを知っている割合が少なく、世の中においてはあまり想定されません。 また、Linuxの環境には幅があり、特定の環境を想定できないというのもあるでしょう。

Windows及びMacのシステムに採用されている欧文フォントとして次のようなものがあります。

  • Arial
  • Hervetica
  • Courier

これらはフリーなフォントではなく、なにかしら保護されたフォントソフトウェアです。 これらのフォントは存在することが想定されており、UI部品などは部品上にこれらのフォントで文字を描画することを想定されていたりもします。

これらのフォントがないことによる最大の問題は、大きさが変わってしまうためにはみ出したり、折り返されてしまったりすることです。 そのため、各グリフのサイズが同一のフォントがあれば表面的な問題は軽減されます。

このようなフォントをメトリック互換フォントと言います。 これらの欧文フォントに対するメトリック互換フォントは次のようなものがあります。

Microsoft Postscript URW GUST Windows Liberation CrOS StarOffice
Arial Hervetica Nimbus Sans TeX Gyre Heros Liberation Sans Arimo Albany
Arial Narrow Helvetica Nallow Nimbus Sans Narrow TeX Gyre Heros Cn Liberation Sans Narrow
Times New Roman Times Nimbus Roman TeX Gyre Termes Liberation Serif Tinos Thorndale
Courier New Courier Nimbus Mono PS TeX Gyre Cursor Liberation Mono Cousine Cumberland
ITC Avant Garde Gothic URW Gothic TeX Gyre Adventor
ITC Bookman URW Bookman TeX Gyre Bonum Bookman Old Style
ITC Zapf Chancery Z003 TeX Gyre Chorus
Palatino P052 TeX Gyre Pagella Palatino Linotype
New Century Schoolbook C059 TeX Gyre Schola Century Schoolbook

欧文のメトリック互換フォントを代替フォントとして使用することを明示的に指定する必要はほとんどありません。 これらは30-metric-aliases.confとして定義されているからです。

日本語フォントとしてはWindowsにはMSフォントファミリーと呼ばれる5書体が伝統的に採用されてきました。 現在はWindowsの和文フォントとしてメイリオと游フォントファミリーが追加されています。

Macの場合古くは平成角ゴシックを中心としたフォントが構成されていましたが、Mac OS Xになって以降は字游工房制作のヒラギノフォントファミリーが収録され、こちらが有名となっています。

Macの場合フォントの変遷もあったこともあり、指定されることがあっても置き換えにより支障が出るケースは稀でした。 これは非Macユーザーにとっては非常に高価なフォントであるということもあり、文書作成でヒラギノフォントファミリーが利用されることは稀です。

一方、明暗を問わずMSフォントファミリー、特にMS Pゴシックが指定されることは非常に多く、Linux環境では支障が出る場合があります。

MSフォントファミリーに対するメトリック互換フォントとしては梅フォントファミリーがあります。 また、IPAモナーフォント、あるいはmonapoというMS Pゴシック互換フォントもあります。 名称に含まれている「モナー」とはインターネット上の掲示板サービス「2ちゃんねる」(現5ちゃんねる)のキャラクターであり、同掲示板で制作・使用されているアスキーアートがMS Pゴシックを想定していることから同アスキーアートを表示するためにはMS Pゴシックメトリック互換であることは必須であることに由来します。

Windows及びMac両方で利用可能なことから今後は游フォントファミリーが指定されてくることも想定されます。

論理名のフォント

伝統的にフォント名として次のものが認識されます。

  • Serif
  • Sans-serif
  • Monospace

これらはそれぞれの形状に対するデフォルトのフォントとして使用されるフォントであり、他のフォントに対するエイリアスになっています。

実際にどのようなフォントが使用されるかは非常に多くの要素に左右されます。 場合によっては適切なグリフを持たないフォント(空グリフの多いフォントやシンボルフォントなど)が使用され、文字が正しく表示されなくなる場合もあります。

明示的にこれらのフォントで何を使用するかを指定したい場合はFontconfigのユーザー設定で(エイリアスではなく)フォントの置き換えによって指定するか、(できるのであれば)デスクトップ環境によって指定すると良いでしょう。

これらのフォントの置き換えは非常に幅広く影響を及ぼします。 メトリックサイズや判読性などを考慮して選択しましょう。

ウェブにおけるフォント

ウェブにおいてはCSSあるいはHTML属性によってフォントを指定することができますが、 伝統的理由により次のフォントが広く指定されています。

  • Arial
  • Hervetica
  • MS Pゴシック
  • ヒラギノ角ゴシック (各種, ばらつきあり)
  • メイリオ
  • Osaka

これらの指定は ほとんどの場合意味がありません 。つまり完全に無視しても問題は発生しないはずです。 ただし、Arial/Hervetica(両者はメトリック互換)に関してはUI部品に使われることがあり、特徴的なメトリックであることから表示が崩れる場合があります。

これらは望ましいこととは言えません。 意味のないフォントの固定はユーザーの設定の自由を剥奪することになるためです。 しかし現実にはほとんどのサイトでこのような指定がなされています。

また、Windows及びMacにおいてはSans-serifやSerifを設定する正規の方法がないため、あまり望ましくないフォントがデフォルトフォントとして使用される傾向があります。 そのために、一般的なウェブブラウザではSans-serifやSerifをアプリケーションにおいて設定できるようになっており、これはLinuxにおいても同様です。さらに、ウェブブラウザは例えLinuxであってもデフォルトのSans-serifをsans-serifに設定するといったことをしていません。 あまり、一般的なウェブブラウザにおいては、ウェブでsans-serif, serif, monospaceが指定された場合でもデフォルトではシステム(Fontconfig)の設定を尊重しません。 ただし、フォントリストには存在することから、設定することでシステム由来とすることはできます。

ただし、この場合でもChromium系ウェブブラウザはフォントリストSans-serifではなくSansというエントリを追加しており、実際にFontconfigに対してSansを要求します。 FontConfigはSansを暗黙にSans-serifと解釈することはしません。

端末におけるフォント

端末は仮想のマス目を持っています。 このマス目の大きさは完全に固定されている(ピクセル単位で決まっていて、同ピクセルサイズのフォントを要求する)か、フォントのサイズに基づいて決まります。

このために端末のフォントは等幅フォントであることが完全な要求となっています。

もしフォントのメトリックが一定でない場合、フォントの位置はマス目からずれてしまいます。 このようなケースにおいて起きる問題は2つに分かれます。

ひとつはフォントを常にボックス上に配置するケースです。 これは幅が足りなければ間があき、すぎれば重なります。 もうひとつは表示はフォントに任せるもののカーソルはボックスを維持するケースです。 この場合、文字とカーソルの位置関係はどんどんずれていきます。

より難しい問題は文字の幅の定義です。 ASCII文字の場合、文字の幅は常に一定です。 しかし、日本語の場合は「半角」と「全角」の2種類の幅があります。

基本的に「2倍幅の文字」を持つのは東アジア言語のみとされています。 ところが、フォントとしては東アジア言語でなくても通用する文字、というのがあります。典型的には「☆」や「♠」などの記号です。

このような記号はヨーロッパでも通用しますが、その場合通常の文字の倍の幅を取る意味がありません。そのため、ヨーロッパ言語のフォントでは一般的にこれらの記号は文字と同一幅です。

このような「プロポーショナルでないフォントでもフォントによって幅の定義が異なる」文字は「ambiguousな文字幅」として定義されています。 これをどのように扱うかは現代的な端末では設定できるようになっています。 一般的にはフォントメトリックに従うように設定されていることでしょう。これは正しく判定されないこともありますが、おおよそ期待したように動作します。あるいは、半角/全角に固定することもできます。

しかしこのようなambiguousな文字の扱いで難しいのは削除です。 バックスペースによる文字削除は内部的には^H(0x08)という文字を送信しています。この文字は幅が-1であり、カーソルを1文字分戻します。 ところが、この「1文字分」が問題です。ambiguousな文字幅の文字をバックスペースで消したとき、バックスペースの大きさが半角なのか全角なのかが適切に処理されないことがあるのです。 結果、「値としては文字は削除されているけれど、グリフの幅は全角なので半分だけ消えてカーソル位置がずれる」という状況が発生する場合があります。

Serif, Sans-serif, Monospace, Dualspace

Serifと明朝体

Serif体(セリフたい)とは文字のストロークの端にある飾りであるserifを持つフォントです。ローマン体ともいいます。

日本語においては類似の明朝体というものがあります。 明朝体は横線のストロークの右端(左から右にストロークし、右端が留めである場合)に鱗と呼ばれる三角を持つのが特徴であり、この特徴はSerifとよく似ています。

このことから、和文フォントにおけるSerif体を求められると明朝体を意味するものとして扱うようになっています。

どちらも印刷文書の本文書体としては親しまれてきました。 現在も印刷物の本文書体としてはSerif体/明朝体が一般的です。

線幅に差があり、細めに見え、また形が把握しやすいことから識別コストが低く、長文を読むのには適しています。 一方、現代では明朝体、あるいはSerif体であるだけで「古臭い」と感じて嫌厭される傾向があり、印刷物でもゴシック体を採用する傾向が強まっています。

Sans-serifとゴシック体

Sans-serif体(サンセリフ体)とはセリフをもたないフォントです。 sans serifとはラテン語で「セリフがない」という意味であり、グロテスク体とも呼ばれます。

日本語においてはSans serif体と同等に扱われるものとしてゴシック体があります。 ただし、ゴシック体の場合単に鱗がないということを意味しておらず、ゴシック体はフォントを構成する線の太さが一定である、という特徴があります。

ただし、実際にはSans serif体でも線の太さは一定である傾向があり、ゴシック体といいつつも線幅が変化するものもあります。

太さが一定で太く見えることからインパクトがあり、印刷物の見出し用に使われてきました。

しかし、現代においてはウェブではほとんどの場合ゴシック体、Sans-serif体が使われることからこちらのほうが馴染み深く、本文書体としてもゴシック体を使用する傾向が強まっています。

なお、欧文書体でゴシック体というと全く異なる装飾的なものを指すため注意が必要です。

Monospace / Dualspace

Monospaceは単一幅のフォントで日本語では「等幅フォント」(とうはばふぉんと)と言います。

このフォントは固定幅でなければならない端末での表示や、文字の厳密な識別が重要になるコーディング用のフォントとして使用されます。 このためにグリフがより識別しやすい(例えばl(小文字エル), I(大文字アイ), 1(数字いち), |(バーチカルバー)が明確に識別できる)ものになっているフォントが多くあります。

実際に等幅フォントというときは一般的には和文フォントです。 しかし和文フォントには「全角」「半角」という区別があり、日本語の多くのグリフは2倍幅になっています。

そのため、実際には2種類の幅があります。このようなフォントをDualspaceフォントと言います。

フォントがどのようなメトリックを持っているかはspacingという値によって示されます。0がプロポーショナル、100がmonospace、90がdualspaceです。

Qtは端末フォントなどmonospaceフォントを必須とするとき、リストするフォントは>=100であるという条件を持っています。 そのためにQtでは等幅フォントの指定にdualspaceフォントを指定できないという問題が発生する場合があります。

Linuxにおけるフォントの仕組み

古のUnix

かつてUnixでは主に点描であるビットマップフォントを扱っていました。

早い時期に線で書かれたアウトラインフォントが採用されましたが、 基本的にはビットマップを中心とした考え方はかわらず、 「フォントサイズごとにビットマップフォントを指定する」という仕組みを採用していました。

PCFビットマップフォントはX Serverの実装であるX11によってサポートされているビットマップフォントです。 これは次のような論理名を持っていました。

-adobe-courier-bold-o-normal--14-100-100-100-m-90-iso8859-1

これは

  • adobe: 提供者
  • courier: フォント名
  • bold: フォントの太さ
  • o: フォントの傾き
  • normal: フォントの幅
  • 14: ピクセルサイズ
  • 100: ポイントサイズ
  • 100: X解像度
  • 100: Y解像度
  • m: スペーシング
  • 90: 平均フォント幅
  • iso8859-1: 文字集合

となっています。

アウトラインフォントではないため、どう考えてもピクセル数とポイント数が釣り合いませんが、 そもそもUnixではビットマップフォントをスケーリングすることはできなかったため、 「14ピクセルで表示するときは14ピクセルのフォント、16ピクセルなら16ピクセルのフォント」が必要でした。

なお、画面上の点を示す“Pixel”という言葉は“Picture Element”または“Picture Cell”に由来すると言われています。

Unixでのアウトラインフォントは.pfaという拡張子でしたが、これはPostScriptフォントであり、 Windowsで採用されていたpfbフォントと同様のものです。 ただし、アウトラインフォントを使用する場合でも、ピクセル数ごとに指定する必要がありました。

表示するに当たっては必ずなんらかのフォントが指定されている必要があったのですが、例えば長く日本語対応のターミナルエミュレータとして親しまれてきたktermでのフォント指定においては

kterm -fn '-*-fixed-*--16-*' -fk '-*-fixed-*--16-*'

のようにして指定していました。この場合、16ピクセルの任意のフォントのうち、Xが列挙するフォントで最初に出現する ものを使用します。

フォントを要求するプログラムはそれぞれデフォルトで、あるいは設定ファイルによって要求すべきフォントが定められており、プログラムの起動時に常に指定する必要はありません。

この機能は“XCore”というフォントシステムです。

ちょっと昔のLinux

フォント周りに関しては乱立していた時代があります。

優勢だったのはクライアント/サーバーシステムをとるXftというフォント管理システムを利用することです。 XftのフォントサーバーはXfsといい、各プログラムはXfsにフォントを要求し、そうするとXfsがXftを利用してフォントを得る仕組みです。得てきたフォントはFreeTypeフォントレンダリングエンジンによって描画されます。

ただし、実際はこんなに単純な話ではありません。極めて複雑な仕組みでした。 Linuxのフォント設定は

  • Xfsの設定
  • アウトラインフォントのためのFreetypeの設定
  • ビットマップフォントのためのXCoreの設定

の3つがあり、高機能な分、非常に専門的な情報を扱う必要がありました。

このような仕組みは無駄だと考えられ、X向けのグラフィックスライブラリであるcairoはXftを使用せず、直接FreeTypeでのレンダリングを行うようになりました。

このことから、「Xfsを使うものと使わないものがあり、Xfsを使うものはXfsのフォント設定が反映されるが使わないものには反映されない」という状況がありました。

現在のLinux

Xfsは廃止に向かっています。

FreeTypeはFreeType2となりました。 今や、GtkあるいはQtで書かれたソフトウェアを扱う限りはFreeType2のことだけを考えていれば良いでしょう。 Cairo, Pango, QtのいずれもWaylandに対応しており、その上でFreeType2もWaylandに対応しているため、 もし仮にX window systemが使われなくなる日がきたとしても問題ありません。

むしろ、「X window systemに依存しない、FreeType直接の取り扱い」というのはWaylandにつながる道だとも言えます。

ではその内容を見ていきましょう。

まず、Cairoとはクロスプラットフォームでデバイスに依存しないベクトルベースの2D描画ライブラリです。 Cairoを使うことでプログラムは様々な事情を気にせずベクトルベースのグラフィックスを描画できます。

PangoはGtk用のテキスト組版ライブラリです。 ここでいう組版は画面上の話であり、行列を持って文字を並べる、という機能があります。 Pangoには縦書き機能もあります。1

QtはPangoを利用しておらず、独自にテキストレイアウトを行っています。

さらに、FLOSSにおけるテキスト標準化の取り組みとしてHarfBuzz2があり、HarfBuzzの成果はPangoとQtの共通ライブラリとして採用され、現在はPango, Qtの共通ライブラリとして使用されています。

現在、描画やフォントに関することでX window systemの存在を気にする必要はありません。 気にする必要があるのはこのようなライブラリであり、 もしこれらのライブラリが変更されることがあれば劇的な違いとなって現れるでしょう。

しかし、PangoやCairoをユーザーが意識することはありません。 FreeTypeですらあまり気にする必要はなく、FreeTypeのフォント設定ライブラリであるFontConfigだけを気にすることになるでしょう。

ここまで言葉のおさらいです。

名前 現用 機能
FreeType yes フォントレンダリングエンジン(大抵は2のこと)
FreeType2 yes フォントレンダリングエンジンの新しいバージョン
Xft/Xfs no FreeTypeを使ったフォントサーバー
XCore no X window system本来のフォント機能
Cairo yes グラフィックス描画用のライブラリ
Pango yes Gtkでテキストをレイアウトするためのライブラリ
Qt yes GUIツールキット。テキストレイアウト機能もある
HarfBuzz yes テキストレイアウトエンジン。PangoとQtで使われている
FontConfig yes フォント設定用ライブラリ

PangoとHarfBuzzの関係ですが、QtとPangoはHarfBuzzをベースにしつつ、 それぞれが従来もっていてHarfBuzzにない機能を追加したものになっており、 例えばPangoでは縦書きができますが、HarfBuzzではできません。 そのため、Pango, QtともにHarfBuzzを使っていますが、縦書きが可能なのはPangoを使用するGtkだけです。

FreeTypeとフォントレンダリング

他環境とLinuxのフォントの美しさについて

ここではフォントレンダリングエンジンの話をしますが、フォントレンダリングエンジンと、フォントレンダラ、そしてフォントラスタライザという言葉は全て同じものを指しています。

レンダリングとは描画することをいいます。 ラスタライズとはベクターグラフィックスをラスター(点描)に変換することをいいます。

Linuxのフォント表示は美しいと言われています。 これはFreeType採用によってアンチエイリアス機能が採用されたためです。

アンチエイリアスとはなんでしょうか。 ディスプレイの特性上、表示されているものは点描であり、ピクセルよりも小さな単位で表示することができません。 そのため、アウトラインフォントを使ってもどうしてもギザギザに見えることとなり、特に小さなフォントではそれが目立ちます。 そこで本来描画すべき点の周囲に淡い色で描画を行い、視覚上「にじませる」ことでギザギザを目立たなくするものです。

美しいフォントレンダリングといえば、Core Textを採用するMac OS Xがあります。 アンチエイリアスが美しいとされ、現在においても表示の最高峰となっています。 ごく一時期リリースされていたWindows版SafariにはCore Textが搭載され、話題となりました。 Linuxで使われているFreeTypeは、Core Textに倣ったものです。

線数の多い和文においては可読性が求められる一方で、醜さも目立ちます。 アンチエイリアスのにじみによってアルファベットが解読不能になるのはよほど小さな文字であるときだけなのに対し、日本語であれば簡単に読めなくなります。 ところが、アンチエイリアスを有効にし、求めてきたのは日本人です。

一方で実用主義者はこれに賛同しません。ビットマップフォントはそもそもが点描であり、サイズも固定です。ビットマップフォントが適切なサイズで表示される限りはそもそも変換する必要がなく、そのサイズで可読性が確保されるように制作されており、どれほど小さい文字であっても(美しさはさておき)判別可能となっています。

そのため、実用主義者はディスプレイでの日常的サイズではビットマップフォントを使えば良いし、大きな文字を表示させるときにはアウトラインフォントを使えば良いのだ、と考えています。現在は高解像ディスプレイが普及し、ピクセルサイズで固定されたビットマップフォントは物理的に小さく表示されて読めないという問題がありますが、実用主義者は「物理的にピクセルが小さいのであればアンチエイリアスなどいらない」と主張しています。3

GDIというフォントレンダラを使うWindowsのフォントレンダリングはかつてはひどいの一言でした。

ClearTypeはWindowsの新しいフォントレンダリングエンジンです。 WindowsはWindows 7でDirectWriteというテキストレンダリングAPIを用意しました。 これは、レンダリング自体はDirectXによって行うのですが、これがClearTypeが機能するための条件でした。

GDI++というライブラリがあり、これはフォントにこだわるWindowsユーザーの間で流行したものです。 GDI++はWindowsのフォントレンダリングエンジンを置き換え、割り込んでWindowsの標準レンダラーに変わって描画します。

GDI++やMacTypeのようなWindows向けのサードパーティのフォントレンダリングエンジンはWindows 10で排除されましたが、Windowsのフォントレンダリングは、Windows 7でClearType採用にも関わらずひどいままだったものの、これについては改善の方向にあります。

「Windowsのフォントレンダリングが汚い」ということはMicrosoftも認めており、 しかし一部のソフトウェアはWindowsに頼らずフォントレンダリングをしていることから(例えば一時期のSafariや、現在のSlaipnirブラウザなど)システムレベルでのフォントレンダリングの変更は古いアプリケーションで支障をきたす可能性があるために変更できない、ということです。

ただし、実際はMicrosoft内部にフォントの改善に否定的な勢力がいることが大きな理由であることは間違いありません。 実際のところ、ウェブブラウザなど利用頻度の高いソフトウェアが独自にフォントレンダリングを行っており、新しいプログラム、特に「Windowsアプリ」として提供されているプログラムは表示が改善していることから改善の見通しに乏しい状況でもあります。

そもそもWindowsのフォントが汚かったのは、記帳なコンピュータリソースをフォント表示に割いてしまわないためで、意図的なものでした。 現在は比較的新しい環境で作られたプログラムはClearTypeが美しく機能するようになっている。この修正は2016年に行われ、さらに現在はアンチエイリアスの調整もできるようになっている。

MacTypeはWindows向けに移植されたFreeTypeを利用するプログラムです。 MacTypeは開発凍結ののち、現在は再始動していますが、Windows 10があまりシステムに関わるプログラムを受け入れないため、難しいところです。

アンチエイリアスの問題は、そもそも「物理的に点が小さくなれば問題自体が縮小する」というものであり、高解像ディスプレイが普及しつつある現状においては目立たなくなりつつあるのも事実です。 しかし、300ppiを越える高解像度液晶においてさえ、依然としてアンチエイリアスは有効です。

ビットマップフォント

ビットマップフォントは規定のマスの中に点描によって書かれたフォントです。

ビットマップフォントは基本的に設計されたサイズでしか描画することができません。 ただし、FreeTypeの機能によって本来のビットマップサイズ以外のビットマップを表示することができます。1 この設定は/etc/fonts/conf.avail/10-scale-bitmap-fonts.confとして用意されています。

ビットマップフォントはアンチエイリアス(サブピクセルレンダリング)が有効になっている場合でもサブピクセルレンダリングは行われません。 ビットマップフォントを拡大すると点描になっていることが確認できるでしょう。

埋め込みビットマップのさざなみゴシック(16px, 4倍に拡大)

ビットマップフォントはフォント自体がビットマップになっているものです。 この有効/無効を切り替えるには70-yes-bitmap.conf及び70-no-bitmap.confを利用します。

アウトラインフォントの中には埋め込みビットマップを持つものもあります。 これはビットマップを持つサイズの場合のみビットマップを使用し、そうでない場合アウトラインフォントを使用します。 これは「ビットマップフォントが理想的であり、そうでない場合補助的にアウトラインフォントを使用する」という考え方に基づいていることを意味します。

埋め込みビットマップを無効にするには次のように設定します。

<?xml version="1.0" ?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <match target="font">
    <edit name="embeddedbitmap">
      <bool>true</bool>
    </edit>
  </match>
</fontconfig>

埋め込みビットマップが表示されるサイズはUIスケーリングによって物理的ピクセルと1:1でない場合でも論理的ビットマップサイズに依存します。 もしUIスケーリングで1.5倍になっており、12pxで描画したときに実際には18pxで描画される場合、フォントは12pxで描画したあとUIスケーリングによって18pxに伸長されます。 この場合、12pxの埋め込みビットマップがあり、18pxの埋め込みビットマップは存在しない場合、12pxフォントで1.5倍UIスケーリングされている場合は12pxの埋め込みビットマップで描画し、18pxで表示されます。

スケーラブルフォントとアンチエイリアス

スケーラブルフォントはフォント自体にサイズは設定されておらず、要求されたフォントサイズに拡大・縮小して表示します。

しかし、実際は常に十分に書けるわけではありません。 「書」という字は横線で8本あり、さらに上は突き抜けています。 そのため、この8本の線の上側に空きが必要になりますが、そのためには16ピクセルなければ書くことができません。

しかしフォントサイズは16pxよりも小さく設定できます。その場合正しく表示できないことになります。 線がくっつく場合には線を分けて書かずに濃淡で表現します。また、場合によってはフォントを変形させ、線を省略します。 フォントを変形する機能はヒンティングといいます。ヒンティングの情報はフォントに含まれています。 ヒンティングは特許保護されており、以前はFreeTypeにおいてはフォントのヒンティング情報を利用せず、グリフから推測して利用するautohinterを利用していました。

autohinterはあまり品質が高くなく、ガタガタになりがちです。 現在はFreeTypeにおいてもヒンティング情報を利用した描画が可能です。

9pxで描画し10倍にしたもの
12pxで描画し8倍にしたもの
24pxで描画し4倍にしたもの
48pxで描画し2倍にしたもの
96pxで描画したもの

実際に描画されたフォントは描画されたサイズであれば例え小さなフォントであっても文字として読めるように表示されていますが、描画されたものを拡大するとあまり文字としての形を保っていないことがわかります。

アンチエイリアスが有効である場合、線の描画がスムーズになるように加工します。サブピクセルレンダリングはより解像度が高く見えるようにさらなる加工を加えます。この両方を有効にしていると濃淡を利用して表現するようになります。これはサブピクセルレンダリングが「拡大して描画して縮小する」という仕組みであるために、拡大して描画したものを縮小するときにどれくらいの点が描かれているかで濃淡となるためです。 十分な大きさで描画されたものほど縮小時に縮小対象になるピクセルの中に複数の線が入ることがなくなり、くっきりと見えます。

アンチエイリアスを無効にすると(付随してサブピクセルレンダリングも無効となり)線を圧縮していることがわかります。 十分に描くことができない場合は線が減っています。

12pxで描画し8倍にしたもの (アンチエイリアスなし)
48pxで描画し2倍にしたもの (アンチエイリアスなし)

一般的に実用的フォントサイズと呼ばれるのは9px-16px程度です。 これは日本語を表示するには不十分なサイズです。 このためにグリフは濃淡で表示されることが多く、これを「ぼやけてみづらい」と考える人が少なくありません。 これがアンチエイリアスの是非に関する意見を分けるところになるのでしょう。十分なフォントサイズを持つ場合、アンチエイリアスが行われることが好ましいと感じる傾向が強まります。 一方、アンチエイリアスがなくても不満に感じる傾向も減り、フォントサイズが上がることはレンダリングに関する不満を大きく低減させることになります。

また、CRTモニターにおいては画面が光によってにじむため、アンチエイリアスは過剰なにじみを発生し判読性を低下させます。 アンチエイリアスはピクセルが明瞭に表示される液晶ディスプレイにおける要求だと考えても良いでしょう。

画面密度が上がるとこうした問題は結果的に緩和されます。 9px-16pxとが望ましいというのはあくまで従来の一般的ディスプレイ上でのことです。高密度ディスプレイにおいては16pxではあまりにも小さな文字になってしまいます。 Retinaクラスのディスプレイではおよそ倍の密度があるため、通常の16pxと同等のサイズの文字を表示するために32pxを確保できることになります。 UIスケーリングの機能により必ずしも単純に32pxのフォントサイズで描画できるわけではありませんが、正しく設計されていればアウトラインフォントの描画は論理サイズではなく描画サイズに対して行われます。

Inifnality

InfinalityはFreeTypeにおけるレンダリングを改善するためのパッチです。 Mac OS Xのレンダリングをエミュレーションし、美しい見た目を得ることができます。

フォント表示を改善するテクニックとして「Infinalityパッチの当たったFreeTypeを使う」という手法は長く親しまれてきましたが、 FreeType 2.7においてInfinality相当の機能が取り込みとなりました。

これにより、Infinalityパッケージはobsolateとなり、 /etc/profile.d/freetype.shにおいて

truetype:interpreter-version=38

とすることでInfinality相当のサブピクセルレンダリングを行います。

しかしこれは不十分であると考えられており、別の人によってFreeType 2.7以降に対応するInfinalityパッチが作成されました。 現在はAURにfreetype2-infinality, fontconfig-infinalityとして存在します。 また、以前のFreeType InfialityのUltimate5設定を別実装で実現したArch Linux向けのfreetype2-ultimate5も存在します。 freetype2-ultimate5は特別な設定も必要なく、パッチを当てる範囲も小さいことから扱いやすいでしょう。

FontConfig

FontConfigの役割

FontconfigはLinuxのフォント設定ライブラリです。

Fontconfigはフォントを使用するアプリケーションに対して「何のフォントを」「どのように表示すべきか」という情報を提供します。

この大きな意味としてはフォントの物理名のほかに論理名を与えることができるということです。 代表的なものとして、以下の論理フォント名が使われています

  • sans-serif
  • serif
  • monospace

これらはフォントの形状の名前であり、フォントの名前ではありません。 例えばmonospaceは等幅フォントを意味しており、monospaceという名前のフォントが存在しているわけではないのです。 しかし、アプリケーションは予めどのフォントを選択すべきかという情報を与えられなくても適切に表示できるよう、このような論理フォント名によるアクセスを行います。

筆者の環境でmonospaceフォントは次のように選択されています。

$ fc-match monospace
VL-Gothic-Regular.ttf: "VL ゴシック" "regular"

つまり、アプリケーションがmonospaceを要求すると、FontConfigはVL-Gothic-Regular.ttfファイルに定義されているVL ゴシックを表示するように指示するわけです。

また、Yahoo Japanのページを見ると、表示フォントとして次のような指定がなされています。

font-family: MS PGothic,Arial,Hiragino Kaku Gothic ProN,Osaka,sans-serif;

MS PGothicはMicrosoft WindowsにバンドルされているMS Pゴシックフォント、 Hitagino Kaku Gothic ProN及びOsakaはMacにバンドルされているフォントです。

最終的にはsans-serifが指定されていますから、ウェブブラウザは当該論理名のフォントがなければ最終的にsans-serifを使用します。 では、sans-serifの指定がなかったらどうなるのでしょうか?4 この場合、ウェブブラウザはFirefoxでもChromeでもウェブブラウザが当該要素におけるデフォルトのフォントを要求します。 これは通常の段落内のフォントであるため、Firefoxはserifを、Chromeはsans-serifを要求します。

このフォント選択においては、ウェブブラウザは論理名があるかどうかだけを確認しており、その論理名のフォントを要求していません。 実際にFontConfigに対して要求するのはsans-serifあるいはserifということになります。 では、アプリケーションがMS PGothicを要求した場合はどうなるのでしょう。

その場合、FontConfigは「それっぽいフォントを適当に見繕って」返します。 明示的に指定されている場合は、sans-serif, serif, monospaceのいずれかのフォントを返すことがほとんどです。 ただし、Courier Newを要求したときに、当該フォントがなければCourierを返す、といった挙動を示す場合もあります。

もちろん、FontConfigの設定によって、特定の論理名に対して特定のフォントを返すようにすることもできます。

FontConfigがどのようなフォントを選択するかについては、fc-matchコマンドで確認することができます。

$ fc-match Courier
NimbusMonoPS-Regular.otf: "Nimbus Mono PS" "Regular"

また、fc-listコマンドによってFontConfigが認識しているフォントを列挙することもできます。

FontConfigの設定

概要

FontConfigの設定は多くの場合、/etc/fonts/conf.availディレクトリにインストールされています。 有効な設定は/etc/fonts/conf.dです。

/etc/font/conf.d内に/etc/font/conf.availディレクトリ内のファイルへのシンボリックリンクを張ることでその設定を有効化することができます。 また、/etc/fonts/conf.dからリンクを削除することで設定を無効化できます。

日本語の場合は65-nonlatin.confを有効にするほうが良いでしょう。 また、ビットマップフォントを嫌うのなら70-yes-bitmaps.confを無効化し、70-no-bitmaps.confを有効化します。

ユーザーごとの設定ファイルは$XDG_CONFIG_HOME/fontconfig/fonts.conf、あるいは$XDG_CONFIG_HOME/fontconfig/conf.d/*にあります。 設定ファイルはXML形式で、

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

  <!-- settings go here -->

</fontconfig>

という形式になっています。

conf.dディレクトリに配置する場合はNN-*.confとします。NNには数値が入ります。 FontConfigは 同列に読み込まれた設定ファイルは常にこの番号が小さいものを優先します

エイリアスと置換え

FontConfigを使うことで要求されたフォント名とフォントが持っている物理フォント名を1:1で結びつけたものではない名前を使うことができます。

最も典型的には「存在しないフォントに対して代わりのフォントを提供する」です。 例えばLinuxにはMSフォントファミリーは含まれていないはずです (MSフォントファミリーをLinuxにインストールすることはEULAに違反します。ただし、同一コンピュータ上にあるMSフォントファミリーをコピーせずに使用することに関しては不明瞭です)。

そこで広く使われるMS Pゴシックを要求された場合、梅ゴシックS5に置き換えるようにするには次のようにします。

<alias>
  <family>MS Pゴシック</family>
  <prefer>
    <famly>Ume P Gothic S5</family>
  </prefer>
</alias>

この設定は「MS Pゴシック」という物理名を持つフォントがないことを前提としています。 このようなことを実現する方法としてフォント名に対して適用されるフォントを置き換えることができます。

 <match target="pattern">
  <test qual="any" name="family">
   <string>MS Pゴシック</string>
  </test>
  <edit name="family" mode="prepend" binding="same">
   <string>Ume P Gothic S5</string>
  </edit>
 </match>

test要素によって要求されたフォントとの比較を行います。 ここではフォント名がMS Pゴシックであるとき、適用されるフォントのリストの最も手前にUme P Gothic S5を追加します。

ウェブにおいてOsakaやMS PGothicを要求されるとぐちゃぐちゃなフォントが表示される場合があるため、置き換えておいたほうが良いかもしれません。

フォントの置き換えは必ずしも1:1でおこなうものではありません。つまり、要求されたフォントに対して複数のフォントをリストすることができます。 例えこのようなことをしなくてもFontConfigは序列を持ったフォントのリストを返します。 これを利用して、欧文フォントに対して和文グリフのために和文フォントを追加することようなこともできます。 次の例ではFira Sansに対してFira Sansの次にMigu 1Cを追加しています。この場合、Fira Sansにあるグリフの場合はFira Sansが使われますが、グリフがない場合Migu 1Cのものが使われます。また、Fira Sansが存在しない場合もMigu 1Cのものが使われます。

 <match target="pattern">
  <test qual="any" name="family">
   <string>Fira Sans</string>
  </test>
  <edit name="family" mode="prepend" binding="same">
   <string>Fira Sans</string>
   <string>Migu 1C</string>
  </edit>
 </match>

すべてのアプリケーションが常にFontConfigのリストを利用するわけではないことに注意してください。 例えばLibreOfficeは指定したフォントと同じ物理名を持つフォントが存在する場合、それを優先します。

また、一般的なウェブブラウザなどFontConfigのリストのうち最初ものしか利用しないアプリケーションもあります。 例えばウェブにおいて次のように指定されていたとします。

font-family: "Fira Sans", "Arial";

このケースにおいてウェブブラウザはFontConfigにFira Sansを要求し、Fira Sansを適用します。しかし、Fira Sansは和文グリフをもたないため、和文を表示する必要がある場合これでは十分ではありません。 FontConfigのリストには次にMigu 1Cがありますが、ウェブブラウザはMigu 1Cを使用することはなく、「Fira Sansで利用できなかった」という結果を以て次のArialでの表示を試みます。しかし、Arialでも表示することはできません。その場合、ウェブブラウザのデフォルトフォントとして指定されているフォントで表示しようとします。

DilloやTeXは代替フォントを探すこともしません。 指定されたフォントと同じ物理名を持つフォントがなければ表示できない状態になりますし、指定したフォントに含まれないグリフがある場合は表示不能となります。

FontConfigのリストを使うのであれば、「最初のフォントだけを使う」ことを利用していくつかの問題を解決できる場合があります。 例えば、「UIは日本語化されているもののフォントはArialに固定されており、リストを利用しない」アプリケーションです。 このようなアプリケーションに対してはArialを和文フォントで置き換えることによりUIの文字化けを解消することができます。

 <match target="pattern">
  <test qual="any" name="family">
   <string>Arial</string>
  </test>
  <edit name="family" mode="prepend" binding="strong">
   <string>VL PGothic</string>
  </edit>
 </match>

このような指定はウェブブラウザにおいても有効です。 ArialもしくはHerveticaを和文フォントより前に指定しているウェブサイトは非常に多いため、Arialを置き換えることにより好ましいフォントを使用させることができます。

しかしArialを置き換えるのはリスクが高いと言えます。 なぜならば、ArialはUI部品として使われることが多く、そのようなケースにArialのメトリックを前提としていることが珍しくないからです。

このような場合においては環境変数$FONTONFIG_FILEを利用すると良いでしょう。 これを使用すると/etc/fonts/font.confの代わりに指定されたファイルを使用することができます。 標準の設定ファイルはとても多岐にわたっているため、これを使わないのは問題が発生する可能性が高く、すべてを網羅したファイルを作り直すのは大変です。

そこで、ここで指定するファイルから標準の設定ファイルを読み込むようにすると良いでしょう。

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
    <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
  </its:rules>

  <description>Replace Arial</description>

  <match target="pattern">
    <test qual="any" name="family">
      <string>Arial</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>VL PGothic</string>
    </edit>
  </match>

  <!-- Load default settings -->
  <include ignore_missing="yes">/etc/fonts/fonts.conf</include>
</fontconfig>

フォントファミリーにはFira Sansのboldのように共通のファミリー に対してstyleが設定されている場合と、Fira Sans Boldのような名前が設定されている場合があります。 ウェイトを含むフォント名が正しく動作しない場合、ウェイトを含むフォント名を定義し、共通のフォントファミリーにウェイトを含んで指定することで解消することができます。

<match target="pattern">
  <test qual="any" name="family">
    <string>Fira Sans Bold</string>
  </test>
  <edit name="family" mode="prepend" binding="strong">
    <string>Fira Sans</string>
  </edit>
  <edit name="weight" mode="assign" binding="strong">
    <const>bold</const>
  </edit>
</match>

逆にフォントファミリ名が異なるものの同一のファミリであるようにstyleにbold体を指定された場合に異なるフォントを使うようにするには条件にウェイトを含めます。

<match target="pattern">
  <test qual="all" name="family">
    <string>MotoyaAporo-W1</string>
  </test>
  <test qual="all" name="weight" compare="more_eq">
    <const>bold</const>
  </test>
  <edit name="family" mode="prepend" binding="strong">
    <string>MotoyaAporo-W3</string>
  </edit>
</match>

前述の通りフォントの置き換えでは存在しないフォントの名前を要求されたときにも置き換えることができます(例えばMSフォントファミリーがインストールされていなくてもMS Pゴシックを要求されたときに置き換えることができます)。

しかし、FontConfigによって設定したフォントは フォントにリストに登場することはありません 。つまり、架空のフォントを指定したとして

  <match target="pattern">
    <test qual="any" name="family">
      <string>My Special Font</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Input Sans Condensed</string>
      <string>Migu 1C</string>
    </edit>
  </match>

このMy Special Fontをフォント選択のリストに含ませることはできません。ただし、明示的にMy Special Fontを要求すればこの設定が適用されます。

これは値を変更した結果も同様で、spacingが100でないフォントに対してspacing=100を設定しても選択時点でmonospaceフォントとして扱われることはありません。

アンチエイリアスとサブピクセルレンダリング

アンチエイリアスを有効にするには次のようにします。

<match target="font">
  <edit name="antialias" mode="assign">
    <bool>true</bool>
  </edit>
</match>

サブピクセルレンダリングを有効にするには次のように設定します。

<match target="font">
  <edit name="rgba" mode="assign">
    <const>rgb</const>
  </edit>
</match>

指定しているのはレンダリングモードであり、液晶の光源の並びに合わせた設定を行います。 定数noneを指定するとサブピクセルレンダリングは行われなくなります。

これらの設定は条件付きマッチの中で指定できますから、特定のフォントに対して有効・無効を切り替えることもできます。

サブピクセルレンダリングを行う場合、色縁を減らすLCDフィルタを使うことが推奨されています。

<match target="font">
  <edit name="lcdfilter" mode="assign">
    <const>lcddefault</const>
  </edit>
</match>

利用できる定数はlcddefault(多くの場合に最適), lcdlight(明るくくっきりしたフィルタ), lcdlegacy(オリジナルのCairoのフィルタ), lcdnone(無効)です。 ほとんどのケースではlcddefaultを使い、にじみが強く感じる特定のフォントに対してlcdlightを使うのが良いでしょう。

ヒンティング

普通はフォントに含まれるバイトコードインタプリタヒンティングを利用するのが望ましいでしょう。

<match target="font">
  <edit name="hinting" mode="assign">
    <bool>true</bool>
  </edit>
</match>

故にautohinterは無効にしたいはずです。5

<match target="font">
  <edit name="autohint" mode="assign">
    <bool>false</bool>
  </edit>
</match>

ヒントスタイルはヒンティングをどのように適用するかを制御します。hintslightはグリフ形状の維持を、hintfullはピクセルグリッドへの整列を優先し、hintmediumはその中間です。 デフォルトはhintslightであり、現在はこの設定が好まれます。

<match target="font">
  <edit name="hintstyle" mode="assign">
    <const>hintfull</const>
  </edit>
</match>
設定例

実際に私が使用している$XDG_CONFIG_HOME/fontconfig/conf.d以下の設定です。

10-syslocal.conf

Gitによる共有の対象外としている、マシン固有の設定。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>System local user config.</description>

    <match target="pattern">
        <edit name="dpi" mode="assign">
            <double>96</double>
        </edit>
    </match>
    <match target="font">
        <edit mode="assign" name="rgba">
            <const>rgb</const>
        </edit>
    </match>
</fontconfig>
30-override.conf

Fontconfigオプションなどの設定

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Override system settings</description>

    <!-- ########## RENDERING OPTIONS ########## -->
    <match target="font">
        <edit name="autohint" mode="assign">
            <bool>false</bool>
        </edit>
    </match>
    <match target="font">
        <edit name="lcdfilter" mode="assign">
            <const>lcddefault</const>
        </edit>
    </match>
    <match target="font">
        <edit mode="assign" name="hinting">
            <bool>true</bool>
        </edit>
    </match>
    <match target="font">
        <edit mode="assign" name="hintstyle">
            <const>hintslight</const>
        </edit>
    </match>
</fontconfig>

MS Pゴシックなどの置換え。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Substitude popular Japanese fonts</description>

    <match target="pattern">
        <test qual="any" name="family">
            <string>MS Pゴシック</string>
        </test>
        <test qual="any" name="family">
            <string>MS PGothic</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume P Gothic S5</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>MS P明朝</string>
        </test>
        <test qual="any" name="family">
            <string>MS PMincho</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume P Mincho</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>MS明朝</string>
        </test>
        <test qual="any" name="family">
            <string>MS Mincho</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume Mincho</string>
        </edit>
    </match>
</fontconfig>
70-basicfonts.conf

sans-serifserifに対する設定。

sans serif体の正式な名称はsans-serifですが、一部sansを指定するアプリケーションもあります。例えばChromiumはSans Serifを指定した場合sansフォントを使用しようとします。 そのため、sans-serifだけでなくsansも設定しています。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Re-define sans-serif, serif and monospace.</description>
    <match target="pattern">
        <test qual="any" name="family">
            <string>sans-serif</string>
        </test>
        <test qual="any" name="family">
            <string>sans</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Sen</string>
            <string>MotoyaLCedar</string>
            <string>NfMotoya Cedar Std</string>
            <string>MMCedar P</string>
            <string>Source Han Sans JP</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>serif</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Overlock</string>
            <string>Mizuki Mincho S</string>
            <string>Source Han Serif JP</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>monospace</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Mono Narrow</string>
            <string>MotoyaLCedar</string>
            <string>MMCedar</string>
            <string>Migu 1M</string>
        </edit>
        <!--
        <edit name="weight" binding="same" mode="prepend">
            <const>light</const>
        </edit>
        -->
    </match>
</fontconfig>
80-complete-kanaonly.conf

かなだけグリフを持つ和文フォントの補完用。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Complete kana only Japanese fonts.</description>

    <match target="pattern">
        <test qual="any" name="family">
            <string>imagine YOKOHAMA</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>imagine YOKOHAMA</string>
            <string>Source Han Serif JP</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>UtsukushiMinchotai</string>
        </test>
        <test qual="any" name="family">
            <string>うつくし明朝体</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>うつくし明朝体</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>FlopDesignFont</string>
        </test>
        <test qual="any" name="family">
            <string>フロップデザインフォント</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>FlopDesignFont</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>

</fontconfig>
80-complete-latin-monospace.conf

欧文等幅フォントのための和文設定。

monospaceフォントはスペーシング100(monospace)になっていますが、和文フォントを使うことで常に単一幅であるとみなすことができなくなるため、spacingに90(dualspace)を設定しています。

<?xml version='1.0'?>
80-complete-latin-sans.conf

欧文sans-serifフォントに和文フォントを補完するための設定。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Complete Japanese fonts for latin sans-serif fonts</description>

    <match target="pattern">
        <test qual="any" name="family">
            <string>Josefin Sans</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Josefin Sans</string>
            <string>MotoyaLMaru</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Raleway-v4020</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Raleway-v4020</string>
            <string>NfMotoyaAporo</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>

    <!-- Input Sans -->
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Sans Condensed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Sans Condensed</string>
            <string>MotoyaLMaru</string>
            <string>MMCeder P</string>
            <string>Migu 1C</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Sans Compressed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Sans Compressed</string>
            <string>MotoyaLMaru</string>
            <string>MMCeder P</string>
            <string>Migu 1C</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Sans Narrow</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Sans Narrow</string>
            <string>MotoyaLMaru</string>
            <string>MMCeder P</string>
            <string>Migu 1C</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Sans</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Sans</string>
            <string>MotoyaLMaru</string>
            <string>MMCeder P</string>
            <string>Migu 1C</string>
        </edit>
    </match>

    <!-- Fira sans -->
    <match target="pattern">
        <test qual="any" name="family">
            <string>Fira Sans</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Fira Sans</string>
            <string>GenEi Antique Pv4</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Fira Sans Condensed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Fira Sans Condensed</string>
            <string>GenEi Antique Pv4</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Fira Sans Compressed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Fira Sans Compressed</string>
            <string>GenEi Antique Pv4</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>


</fontconfig>
80-complete-latin-serif.conf

欧文serifフォントの和文フォントの補完。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Complete Japanese fonts for latin serif fonts</description>

    <!-- INPUT -->
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Serif</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Serif</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Serif Narrow</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Serif Narrow</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Serif Condensed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Serif Condensed</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Input Serif Condensed</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Input Serif Compressed</string>
            <string>Mizuki Mincho S</string>
        </edit>
        <edit binding="strong" name="spacing" mode="assign">
            <int>0</int>
        </edit>
    </match>
</fontconfig>
85-metric.conf

標準設定にないWindowsフォントのSegoe UIのメトリック互換設定です。

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Metric compatibility</description>
    <match target="pattern">
        <test qual="any" name="family">
            <string>Segoe UI</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Selawik</string>
        </edit>
    </match>
</fontconfig>

フォントのインストール

システムのフォントは/usr/share/fonts以下にインストールされます。 再帰的に検索されるため、ディレクトリを作っても構いません。

あるいはサイトローカルなフォントを全ユーザー向けにインストールしたい場合、/usr/local/share/fontsが標準で検索されるディレクトリとして含まれています。

ユーザーのフォントディレクトリは$HOME/.fontsです。 システムにない独自のフォントを使用する場合はこのディレクトリに放り込むことになります。

フォントソフトウェアはWindowsやMacのTTF/TTC/OTFファイルが利用できます。 ただしWindows向けフォントではフォント名がShift JISで書かれている場合があるため、問題を避けるには可能であればMac向けフォントを利用したほうが良いでしょう。

Linuxにおける欧文・和文フォントファミリー

和田研フォント

和田研漢字分科会が開発したフォントファミリーです。 アウトラインの自動生成技術を用いたアウトラインフォントです。

1995年と古くから存在するため、Linux以前のUnix環境では重用されてきました。

東雲フォント

古川泰之氏が開発したビットマップフォントです。

ビットマップフォントが主流だった時代にWindowsにおけるMSフォントのように標準的にUnix環境で使用されていたフォントです。

東風フォント

古川泰之氏が開発し、2000年から2003年にかけて使われていたアウトラインフォントです。

様々なフォントを基に開発されており、そのうちひとつである渡邊フォントがタイプバンク明朝のグリフを流用したことが発覚し、この問題から配布停止となりました。

グリフに少し癖があり、あまり美しくないとされています。

さざなみフォント

東風フォントの公開停止に伴って、問題のあるグリフを差し替えたフォントです。 一時期は東風代替フォント(kochi-subst)と呼ばれていました。

Linuxで利用できるフリーなフォントを確保することが第一目的だったため、差し替えられたグリフの完成度はあまり高くありません。

現在も標準日本語フォントとして使われる場合もありますが、日本語をネイティブにサポートするディストリビューションにおいてはグリフの美しさの問題から標準和文フォントとしてはそれほど採用されていません。

VLゴシック

Vine LinuxをリリースするVine Projectによって開発されている丸ゴシック体です。 非常に人気が高く、海外ディストリビューションでも標準の和文フォントとして採用される傾向があります。

等幅のVLゴシックはコーディングフォントとしても人気です。

IPAフォント / Takaoフォント

IPAによってリリースされているフォントファミリーで、制作はタイプバンクが担当しています。

日本語の文書を作成するために開発されたフリーなフォントであり、日本語の文書作成流儀に従ったexフォントや、名前や地名のための代替文字を含むmj明朝も含んでいます。

Takaoフォントはライセンス上の理由からUbuntu Japaese Teamが派生・公開しているものです。

M+フォント

森下浩司氏が開発する丸ゴシック体フォントです。

ビットマップフォント、カーソルフォント、アウトラインフォントが用意されています。 ディストリビューションに標準で採用されることは稀ですが、VLゴシックのベースとなっていることから比較的見かける機会はあり、日本人のLinuxユーザーには人気もあります。

Migu / MigMix

itouhiro氏によって開発されている、M+フォントにIPAフォントを合成させたフォントです。

Miguはより積極的に調整されており、「半濁点が大きい」「1cフォントは和文プロポーショナル」「グリフが非常によく似た和文グリフの区別」などがあります。

Migu 1M/2MフォントはコーディングフォントとしてLinuxに限らず非常に人気が高く、オリジナルのM+より広く使われています。

Ricty

M+フォントとInconsolataを合成したフォントです。

コーディングフォントとして人気が高く、Windowsユーザーにも広く使われています。

Noto Sans/Serif CJK, Source Han Sans/Serif JP

AdobeとGoogleが共同開発するフォントです。 Googleの「世界中の文字をサポートするフォント群を開発」という目標に沿って開発されており、GoogleはNoto Fontフォントファミリーとして、AdobeはSourceフォントファミリーとして公開しています。

和文はAdobeが中心となって新規に開発しており、欧文はAdobeのオープンソースフォントであるSource Sans Pro及びSource Serif Proフォントを採用しています。

これまでLinuxの世界ではなかったほど商業フォント的な高品位フォントであり、急激にシェアを伸ばしています。

また、Source Han Code JPフォントはSource Han Sans JPの和文グリフにコーディングフォントとして非常に人気の高いSource COde Proフォントを公式に組み合わせたもので、「日本語2文字に対してアルファベット3文字」という幅設定と広い行間が特徴です。

梅フォント

蓬莱和多流氏が開発したフォントファミリーです。

Windowsで標準採用されているMSフォントファミリーとメトリック互換になっています。 オープンなライセンスを採用しているものの、標準採用されることは稀です。

明朝体の漢字グリフは花園明朝のものを使用しており、極めて多くのグリフを保持しています。

さわらびフォント

戸越フォントの作者あるmshio氏が開発するフォントです。

フリーな和文フォントは現在IPAフォントあるいはM+フォントをベースにしているフォントが多い中、完全にオリジナルのグリフとなっています。 収録グリフ数はやや少なめです。

ゴシックより明朝のほうがグリフ数が少なく、さわらび明朝の収録グリフは20180515で2759となっています。 この欠点を補う派生フォントとしてみずき明朝(さわらび明朝とIPA明朝を合成)がありますが、こちらはあまり知られていません。

Googlefontsで配布されている和文フォントでもあります。

モトヤLマルベリ3等幅 / モトヤLシーダ3等幅

商用フォントベンダーであるモトヤがAndroid向けにApache Licenseで提供したフォントです。

モトヤが商用フォントとしてリリースするマルベリ及びシーダを基にしています。

現在はAndroidはNoto fontを採用しており、入手もやや難しくなっていますが、 Googlefontsで「小杉ゴシック」及び「小杉丸ゴシック」として配布されています。 これらのフォントもfont family nameはMotoyaLCedar W3及びMotoyaLMaru W3となっています。

Javaにおけるフォントレンダリング

Javaの標準ツールキットであるAwtが独自にフォントレンダリングを行うため、 アンチエイリアス設定が反映されません。

Awtでアンチエイリアスを有効にするにはJavaのオプションとして

-Dawt.useSystemAAFontSettings=lcd -Dawt.useSystemAAFontSet

tings=on -Dswing.aatext=true -Dsun.java2d.opengl=true

を渡します。 これを環境変数$_JAVA_OPTIONS_に設定するのが一般的です。

DPIとスケーリング

DPI

1inchあたり(平方インチではなく)にいくつのドットがあるか、ということを指してDPI(Dot Per Inch)あるいはPPI(Pixel Per Inch)といいます。

長年、Macでは72dpi, Windowsでは96dpiという暗黙の了解がありましたが、現在は実際はそのような値からはかけ離れています。

一般的なモニタのおおよそのDPIは次のようになっています。6

ディスプレイサイズ FWXGA (1366x768) FullHD (1920x1080) WQHD (2560x1440) 4k (3840x2160)
4.7 333 469
5 313 441 587 881
5.5 285 401 534 801
6 261 367 490 734
10.1 155 218 291 436
12.1 130 182 243 364
13.3 118 166 221 331
14.0 112 157 210 315
15.6 100 141 188 282
21.5 73 102 137 205
24 65 92 122 184
27 58 82 109 163
31.5 50 70 93 140

Linuxシステムでは設定されていなければ96DPIであるとみなします。 フォントサイズ「ポイント」は物理的な大きさであり、いくつ点があればその物理的な大きさに達するかはDPIを元に計算します。

1ポイントは0.0138889インチです。 10ポイントは0.138インチ、1インチで96の点を描くのですから、10ポイントの領域には13.248個の点、ピクセルは半端な数は書けないので13個のピクセルを描くことになります。 この計算によって、DPIが設定されていない限り、物理的にどのようなモニターを使用していたとしても13ピクセルを描画します。

さて、あなたがDell XPS13の4kモデルを使用していたとします。DPIは331です。 「10ポイント」と思って描いた13ピクセルは、実際は0.04インチまで縮小してしまいます。 0.04インチとは2.88ポイントです。 10ポイントの文字ならば小さいものの読める文字ですが、2.88ポイントは虫眼鏡が必要かもしれません。 これは、誤ったDPI設定の結果「10ポイント」と指定して描画した文字は2.88ポイントで描画されるということです。

これを修正するために、最近のデスクトップ環境ではフォントのDPIを設定することができるようになっています。 これは、FontConfigの設定に反映する形で行います。

しかし、実のところ問題は決して文字だけではありません。 実際のDPIが設定されたDPIの倍になれば、アイコンもボタンもその面積は1/4になるということです。 これはとても不便です。120DPI程度までであればそれほど苦労しませんが、140DPIにもなると「明らかに小さい」と感じます。

DPIの設定はX.Orgも保有しています。 X.OrgサーバーはDDC(VESA Display Data Channel)によって正しい画面サイズを自動検出しますが、できていない場合も多々あります。

$ xdpyinfo | grep -B2 resolution

ひとつの方法として、X.Orgの設定ファイルとしてディスプレイのサイズを記述するという方法があります。

Section "Monitor"
    Identifier             "<default monitor>"
    DisplaySize            286 179    # In millimeters
EndSection

あるいは、Xrandrツールを使用できる環境であれば、これを使う方法もあります。 (永続化するためにはXProfileとして記載します。)

$ xrandr --dpi 331

GtkやQtなどにおいて物理的な寸法で記述されているパーツはこのDPI変更によって自動的にスケールされます。 Qtにおいてはこれだけで問題を解決することができます。

Gtk3は$GDK_SCALE及び$GDK_DPI_SCALE環境変数で調整できますが、あまりうまくいきません。 しかも、UIコンポーネントを設定する$GDK_SCALEは2倍、3倍という単位でしか調節できません。

さらにデスクトップ環境によってはFontConfigで明示的にDPIを指定する必要がある場合もあります。

このようなHiDPIサポートはWindowsよりMacより先にLinuxが行っているにも関わらず、あまり快適に動作しません。 最も良い解決方法は(GTKアプリケーションを使う場合であっても)KDE Plasmaを使用するという方法です。

KDE Plasmaを使用する場合は次の方法でほとんどの環境で良い動作を得られます。

  • ディスプレイサイズを設定する
  • KCMから明示的にフォントのDPIを設定する

ただし、この場合でもlightdm greeterのサイズは別問題となります。 greeterの設定を変更してこの問題を改善できます。 gtk-greeterを使用している場合は、

/etc/lightdm/lightdm-gtk-greeter.conf

xft-dpi=331

のように記述を追加します。

未来

HarfBuzzはHarfBuzz-NGとして再構築を行っています。

X window systemを廃止してWaylandに移行する動きがあります。

Waylandはディスプレイへの描画を管理するものであり、ウィンドウの位置や重なりを管理し、適切に重って表示されるようにします。 WaylandはX window systemのようなものではなく、あくまでディスプレイ上での表示の管理しか行いません。 ウィンドウマネージャがグラフィックスハードウェアとのやりとりや、アプリケーションとのやりとりをする際にXを介する構造ではなく直接やりとりをするようになります。 キーボードなどの入力ハードウェアの管理もWaylandは行いません。

WaylandはX window systemのようなロスがなく、優れた応答性と低負荷が期待されています。 その仕組み自体はWindowsに近いものです。 しかし、大部分を外部に頼る仕組み上、入力処理やハードウェアリソースの管理においてライブラリが乱立してしまうと、 まともに機能せず、設定も散らばってしまう可能性があります。

また、X window systemの便利な機能は使えなくなります。


  1. Pangoという名前はギリシャ語で「全て」を表すPanに、日本語の「語(Go)」を組み合わせたものです。↩︎

  2. こちらはペルシャ語です。↩︎

  3. これはある程度正しい主張です。判別しやすさはアンチエイリアスがない方が良好であり、300ppiあるようなディスプレイではアンチエイリアスはないほうが読みやすく疲れにくいという主張があります。一方、300ppiあってもアンチエイリアスは有効であるほうが美しく感じるということも分かっています。↩︎

  4. 日本語のページであるにも関わらず、欧文フォントであるArialを指定しているのは、非常に「悪い」ことだと考えられます。↩︎

  5. ヒンティング情報を持たないフォントがあれば、局所的に有効にしたいことはあるかもしれません↩︎

  6. “網膜の解像度は300DPIなので、300DPIに達するとドットを視認できなくなる”という説があります。しかし、実際はディスプレイと目の距離もありますし、そうはいきません。しかし300DPI前後に到達すると非常になめらかに見えるのは事実です。↩︎