Fontconfig (9日目) - sans-serif =============================== .. post:: Dec 09, 2022 :tags: fontconfig CSS同様にFontconfigもsans-serif、serif、monospaceといった総称ファミリー名を扱えるのはこれまで見てきたとおりです。 ただ、DEのフォント設定画面で選択したフォントは各種GUIツールキットの設定ファイルに保存されてFontconfigには伝わっていないのも見てきました。 今日は ``fc-match 'sans\-serif'`` に対して狙ったフォントを返せるようにしましょう。 総称ファミリー名とは -------------------- 総称ファミリー名とは `CSSでは `_ ブラウザのデフォルトフォントやユーザーが設定したフォント、環境ごとのUIフォントを明示的に選択するためのものです。 Fontconfigでは……ただの、存在していないフォントファミリー名というだけです。 ソースコードをgrepしても */usr/bin/fc-match* や */usr/lib/x86_64-linux-gnu/libfontconfig.so.1* を ``strings`` コマンドにかけても総称ファミリー名らしきものは出てきません。 何ら特別扱いはされていません。 特定の名前を多数の設定ファイルが色々と取り回して意味のある名前にしているだけなのです。 順番に見ていきましょう。 sans-serifが実在するフォントで置き換えられる理由 ------------------------------------------------ 現在、sans-serifは英語ではNoto Sans、日本語ではNoto Sans CJK JPに置き換えられます。 :: $ LANG=en_US fc-match 'sans\-serif' NotoSans-Regular.ttf: "Noto Sans" "Regular" $ LANG=ja_JP fc-match 'sans\-serif' NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" ということはどこかでフォントパターンの ``family`` 属性にこのような操作を行っている設定ファイルがあるはずです。 KDE neonでは `/etc/fonts/conf.d/56-neon-noto.conf `_ がそうです。 .. code-block:: xml :caption: /etc/fonts/conf.d/56-neon-noto.conf sans-serif Arimo Noto Sans Noto Sans CJK SC Noto Sans Arabic Noto Sans Thai Noto Sans Devanagari Noto Sans Tamil Noto Sans Hebrew Noto Sans Bengali Noto Sans Telugu Noto Sans Kannada Noto Sans Malayalam Noto Sans Gurmukhi Noto Sans Gujarati Noto Sans Oriya Noto Sans Armenian Noto Sans Georgian Noto Sans Khmer Noto Sans Lao Noto Sans Ethiopic Noto Sans Myanmar Noto Sans Sinhala Jomolhari Noto Sans Coptic Noto Sans Deseret Noto Sans TaiTham Noto Sans CanadianAboriginal Noto Sans Yi Noto Sans Tifinagh Noto Sans Adlam Noto Sans Cherokee Noto Sans Chakma Noto Sans Osage Noto Color Emoji Noto Sans Symbols Noto Sans Symbols2 DejaVu Sans ja sans-serif Noto Sans CJK JP +++++++ ```` タグは説明していませんでした。 これは ```` 〜 ```` 〜 ```` の省略記法です。 .. code-block:: xml XXX YYY は次と同じです。 .. code-block:: xml XXX YYY ```` はprepend、 ```` はappend、 ```` はappend_lastと同じです。 あくまで上から下に実行される命令であって、エイリアス宣言なんかではないです。 従って順番が非常に大切です。 sans-serifだけの状態から最初にXをprependするとX, sans-serifの順番になるので、そこで次にYをprependしてもX, Y, sans-serifとなってXが優先されます。 一番先だった *56-neon-noto.conf* はKDE neon固有ですが、他にも 57-dejavu-sans.conf_\ 、 58-dejavu-lgc-sans.conf_\ 、 60-latin.conf_\ 、 61-urw-gothic.conf_\ 、 61-urw-nimbus-sans.conf_\ 、 65-droid-sans-fallback.conf_\ 、 65-fonts-ipafont-gothic.conf_\ 、 65-fonts-persian.conf_\ 、 65-nonlatin.conf_\ 、 69-unifont.conf_\ 、 70-fonts-noto-cjk.conf_ が次々とsans-serifの前後に推しフォントファミリー名を追加しようと手ぐすね引いています。 .. _57-dejavu-sans.conf: https://salsa.debian.org/fonts-team/fonts-dejavu/-/raw/master/fontconfig/57-dejavu-sans.conf .. _58-dejavu-lgc-sans.conf: https://salsa.debian.org/fonts-team/fonts-dejavu/-/raw/master/fontconfig/58-dejavu-lgc-sans.conf .. _60-latin.conf: https://gitlab.freedesktop.org/fontconfig/fontconfig/-/raw/main/conf.d/60-latin.conf .. _61-urw-gothic.conf: https://salsa.debian.org/fonts-team/fonts-urw-base35/-/raw/master/fontconfig/urw-gothic.conf .. _61-urw-nimbus-sans.conf: https://salsa.debian.org/fonts-team/fonts-urw-base35/-/raw/master/fontconfig/urw-nimbus-sans.conf .. _65-droid-sans-fallback.conf: https://salsa.debian.org/fonts-team/fonts-android/-/raw/master/debian/local/65-droid-sans-fallback.conf .. _65-fonts-ipafont-gothic.conf: https://git.launchpad.net/ubuntu/+source/fonts-ipafont/plain/debian/65-fonts-ipafont-gothic.conf .. _65-fonts-persian.conf: https://gitlab.freedesktop.org/fontconfig/fontconfig/-/raw/main/conf.d/65-fonts-persian.conf .. _65-nonlatin.conf: https://gitlab.freedesktop.org/fontconfig/fontconfig/-/raw/main/conf.d/40-nonlatin.conf .. _69-unifont.conf: https://gitlab.freedesktop.org/fontconfig/fontconfig/-/raw/main/conf.d/69-unifont.conf .. _70-fonts-noto-cjk.conf: https://salsa.debian.org/fonts-team/fonts-noto-cjk/-/raw/master/debian/70-fonts-noto-cjk.conf 結果 ``fc-pattern -c 'sans\-serif'`` は膨大なリストとなり ``fc-match 'sans\-serif'`` は何れかの存在するフォント名となるわけです。 sans-serifがパターンに含まれるようになる理由 -------------------------------------------- ``fc-match ''`` と ``fc-match 'sans\-serif'`` は同じ結果を返します。 ということはどこかで ``family`` 属性にsans-serifを追加している設定ファイルがあるはずです。 `/etc/fonts/conf.d/49-sansserif.conf `_ がそうです。 ``family`` 属性が持つリストにsans-serif、serif、monospaceのいずれも含まれていない場合sans-serifを追加してくれています。 この設定ファイルが実は困り物で、フォントパターンに実際に存在するフォント名を指定したとしてもsans-serifが追加されてしまうため、次のようにNoto Serifのフォールバック先がNoto Sans CJK JPになったりします。 Noto Serif CJK JPであって欲しいですよね。 :: $ fc-match -s 'Noto Serif' | head NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" NotoSansArabic-Regular.ttf: "Noto Sans Arabic" "Regular" NotoSansThai-Regular.ttf: "Noto Sans Thai" "Regular" NotoSansDevanagari-Regular.ttf: "Noto Sans Devanagari" "Regular" NotoSansTamil-Regular.ttf: "Noto Sans Tamil" "Regular" NotoSansHebrew-Regular.ttf: "Noto Sans Hebrew" "Regular" NotoSansBengali-Regular.ttf: "Noto Sans Bengali" "Regular" NotoSansTelugu-Regular.ttf: "Noto Sans Telugu" "Regular" NotoSansKannada-Regular.ttf: "Noto Sans Kannada" "Regular" ``family`` 属性は Noto Serif → Noto Serif, sans-serif → Noto Serif, Noto Sans CJK JP, sans-serif みたいな感じで先頭のNoto Serifを除けば空文字列を指定したのと似たようなものになってしまうわけです。 (正確には49より前の分は反映されませんが。) この対策は後日行います。 設定 ---- では実際にsans-serifを設定してみましょう。 */etc/fonts/conf.d/* にある設定ファイルでsans-serifを置き換えようとするものは56以降ですのでユーザーの設定ファイルで先んずることができます。 .. code-block:: xml :caption: ~/.config/fontconfig/conf.d/50-generic.conf sans-serif Ubuntu さて。 :: $ LANG=en_US fc-match 'sans\-serif' Ubuntu-R.ttf: "Ubuntu" "Regular" $ LANG=ja_JP fc-match 'sans\-serif' NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" ``strong`` として追加されているNoto Sans CJK JPに負けていますね……。 ``binding`` アトリビュートのデフォルトがweakなのが原因です。 ``same`` か ``strong`` にしましょう。 .. code-block:: xml どうでしょうか。 :: $ LANG=en_US fc-match 'sans\-serif' Ubuntu-R.ttf: "Ubuntu" "Regular" $ LANG=ja_JP fc-match 'sans\-serif' Ubuntu-R.ttf: "Ubuntu" "Regular" 無事にUbuntuとなりました。 sans-serifの意味 ---------------- KDEの設定画面では本文用のフォントとUI用のフォントが分けられていましたが、それはKDEライブラリを使用しないアプリケーションには伝わりません。 そして多くのアプリケーションは(個別設定等を行わなければ)sans-serifを本文とUIの両方に使用します。 さて私は本文用にDejaVu Sans、UI用にUbuntuを設定しました。 ではsans-serifはどちらにするべきでしょうか? これは、Ubuntuにせざるを得ないと思います。 つまりsans-serifはUI用フォントとみなすということです。 UI用フォントはsans-serifを通じてしか設定できなくても本文用フォントは別に設定できるアプリケーションもありますし。 CSSでしたらUI用はsystem-uiとして分離されていますのでこんな悩みは無いのですけれどもね。 (system-uiや-apple-systemを本文に使うクソサイトが結構あったり……。)