2017-10-22

Emacsでイタリック(斜体)が表示されないのを何とかした(Windows Emacs25.3)

org-modeを使っていて、ふと斜体が表示されないのに気がつきました。

私の最近のフォント設定は前回の通り次のような単純な物でした。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)
;; デフォルトはASCII用のフォントでなければダメっぽい。
(set-face-attribute 'default nil :family "Inconsolata" :height 120)
;; ASCII以外を指定する。
(set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "MS Gothic"))

ASCII部分はプログラミング用フォントとして有名なInconsolataを使っています。 それ以外は基本的にMS ゴシック。私はMS ゴシックの低解像度ディスプレイ下でのシャープさをとても評価しているのです。

それでまず試したのはマニュアル(Bold and italic - GNU Emacs FAQ For MS Windows)にもあるこの設定。

(setq w32-enable-synthesized-fonts t)
(set-face-font 'italic "-*-Courier New-normal-i-*-*-11-*-*-*-c-*-iso8859-1")
(set-face-font 'bold-italic "-*-Courier New-bold-i-*-*-11-*-*-*-c-*-iso8859-1")

んー、確かに斜体になります。でもCourier Newは嫌なのでこれをInconsolataなどにしてみてもうまく行きません。MS Gothicなどでもダメです。Consolas等あらかじめ斜体が用意されているフォントならうまくいきます。

ひょっとしたら計算で傾かせている場合はダメなのでしょうか。でも昔は傾いたと思うのですが……。 w32-enable-synthesized-fonts を調べてみましたが、これ現在はobsoleteで何の効果も無いみたいです。ソースを過去に遡って追ってみましたが、Emacs23になってからはどこからも使われていないみたいです。 色々試してみてもどうあがいても斜体がないフォントを斜体にすることができませんでした。

仕方が無いので斜体がある等幅フォント(日本語あり)ということで、Ricty Diminishedを使ってみました。

(set-face-font 'italic "Ricty Diminished:italic")

うん、斜体になります。……でも、日本語は斜体になっていません。あれー????

日本語部分はMS Gothic(非斜体)のままです。ASCII部分は設定の通りRicty Diminishedの斜体。上のフォントセットの設定が優先されているのでしょうか?

斜体専用のfontsetを作ってASCIIもそれ以外もRicty Diminishedにし、italicフェイスのfont属性に設定してみましたが、やはり日本語(非ASCII)はMS Gothic(非斜体)です。

諦めかけたところでふと (describe-face 'default) のfontset:の項目が目に付きました。あれ、faceの属性にもfontsetってあるんですね。試しに (set-face-attribute 'italic nil :fontset "fontset-standard") とやってみるとエラーが出ません。もしかして……と思い、Ricty Diminishedだけのfontsetを:fontset属性に設定してみると、無事日本語も含めて斜体はRicty Diminishedになりました。

なるほどー、italicフェイスのfontset属性がunspecifiedだとデフォルトのfontset(defaultフェイスのfontset属性?)が使われて上で設定したMS Gothicが使われてしまうんですね。だからitalicフェイスのfontset属性で再度非ASCII用のフォントを指定してあげれば良いわけですか。

というわけで、最終的な設定は次のようになりました。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)

(defun my-font-available-p (name) (find-font (font-spec :name name)))
(cond
 ;; ASCII用のフォントを設定する。
 ;; Inconsolataを優先する。理由:
 ;; - 等幅プログラミング用フォント
 ;; - Windows上でのhintingが良いのでRictyより文字がぼやけない
 ((my-font-available-p "Inconsolata") (set-fontset-font nil 'ascii "Inconsolata-12") (setq-default line-spacing 0.0))
 ((my-font-available-p "Ricty Diminished") (set-fontset-font nil 'ascii "Ricty Diminished-12") (setq-default line-spacing 0.2))
 ((my-font-available-p "Consolas") (set-fontset-font nil 'ascii "Consolas-12")))
;; ASCII以外のフォントを設定する。
(set-fontset-font nil '(#x80 . #x3fffff) "MS Gothic")
;; 斜体フォントを設定する。
;; faceのfontset属性を設定するところがミソ。そうでないと上で設定した非ASCII用フォントが優先されてしまう。
(cond
 ;; Ricty Diminishedを使う。理由:
 ;; - ASCIIにも日本語文字にも斜体バージョンがある(実際には独自にFontForgeで少し角度を増やした物を使っています。その際フォント情報も調整しました)
 ;; - 日本語も等幅である
;;  - Inconsolataと同じプログラミング用フォント
 ;; - Inconsolataには斜体バージョンがない
 ;; - hintingや文字の高さの違いは斜体に限り諦められる
 ((my-font-available-p "Ricty Diminished")
  (create-fontset-from-fontset-spec "-*-*-*-italic-*-mono-*-*-*-*-*-*-fontset-myitalic")
  (set-fontset-font "fontset-myitalic" '(#x80 . #x3fffff) "Ricty Diminished")
  (set-face-attribute 'italic      nil :fontset "fontset-myitalic")
  (set-face-attribute 'bold-italic nil :fontset "fontset-myitalic"))
)

本当は日本語部分はMS Gothicの斜体にしたかったのですが、どうあがいても出来なかったので仕方がありません。日本語の斜体を使う機会は多くはありませんし諦めます。

script slant フォント
ascii normal Inconsolata
非ascii normal MS Gothic
ascii italic Ricty Diminished
非ascii italic Ricty Diminished

という組み合わせで使いたいという人はあまりいないかもしれませんが、ひとまずこんな感じで。

それにしても set-face-attribute の説明に :fontset のことが書いていないのですが大丈夫なのでしょうか。実際常に変更できるわけではないようで、少なくともdefaultフェイスに対する:fontset属性の変更は何故かうまくいきませんでした。defaultフェイスはフレームパラメータと結びついているので制約があるのでしょうか?

一番最初にASCII用のフォントを設定するところですが、同じ事を次のようにも書けます。

(set-face-attribute 'default nil :font "Inconsolata-12")
defaultフェイスのフォント関連属性を変更することで、フレームのfontパラメータも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。 :family "Inconsolata" :height 120 のような指定をするとfontset-auto1とfontset-auto2の二つが作られたりします。
(set-frame-font "Inconsolata-12") または (set-frame-parameter nil 'font "Inconsolata-12")
フレームのfontパラメータを書き換えるとdefaultフェイスも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。
(set-fontset-font "fontset-startup" 'ascii "Inconsolata-12")
今回採用した方法とほぼ同じです。起動直後はfontset-startupがフレームに設定されているため、"fontset-startup"と書いてもnilと書いても同じです。余分なfontsetは自動的に作られません。

フレーム、フレームのdefaultフェイス、フレームに現在設定されているfontsetのいずれを修正しても同じような挙動になります。

いやはや、Emacsのフォントまわりは本当に難解ですね。

(2021-07-29追記:現在はFontForgeで自分で斜体に加工したフォントを使っています)