w3m - Unicode の曖昧な文字幅問題 その1

ふと思いついて、作業環境(Debian sarge)の文字コードEUC-JP から UTF-8 へ移行することにした。Debian の次期 stable (etch) では UTF-8 が標準になるそうだし。
ほとんどのソフトウェアは locale の設定を変えるだけで問題なく移行できたんだが*1PuTTY 上で起動した w3m で、罫線などの表示が崩れるという問題に遭遇した。
最初は PuTTY の問題かと思ったんだが、いろいろと調べた結果、問題の原因は、Unicode の Eastern Asian Ambiguous Character Width*2にあることが分かった。つまり、Unicode では罫線や一部の記号(☆とか□とか)の文字幅が曖昧であり、文脈に応じて半角(half-width)になったり全角(full-width)になったりするんだが、どうやら w3m ではこれらの文字は全てまとめて半角として扱われるようだ。
一方、PuTTY (ISO-2022 パッチ付き)では文字セットに "UTF-8 (CJK)" を指定した場合は全角扱いに、"UTF-8" を指定した場合は半角扱いになるらしい*3。ほとんど全ての日本語文書では罫線文字などは全角だと想定しているし、emacs を端末内で動かした時もそれらの文字は全角として扱われるので*4、俺は PuTTY の設定として "UTF-8 (CJK)" を使っているんだが、そうすると w3m が想定している文字幅と齟齬が起こって表示が崩れる、という寸法。
で、解決法を調べてみたんだが、これがなかなか難しい。
最初に作ったのは、以下のパッチ。

--- symbol.c.orig	2003-09-23 06:02:21.000000000 +0900
+++ symbol.c	2006-09-30 21:10:38.000000000 +0900
@@ -35,5 +35,5 @@
 static symbol_set big5_symbol_set  = { WC_CES_BIG5,     2, big5_symbol,  NULL };
 #ifdef USE_UNICODE
-static symbol_set utf8_symbol_set  = { WC_CES_UTF_8,    1, utf8_symbol,  NULL };
+static symbol_set utf8_symbol_set  = { WC_CES_UTF_8,    2, utf8_symbol,  NULL };
 #endif
 static symbol_set cp850_symbol_set = { WC_CES_CP850,    1, cp850_symbol, NULL };

このパッチで table や hr は崩れなくなったけど、これは実は対処としては不完全。というか、間違いに近い。内部で使っている文字幅取得マクロ(wtf_width())は罫線や記号文字の幅を 1 として返すままだし、何よりポータビリティが無い。また、フォームの select のメニューでの表示が崩れたままだった。どうやら libwc の中身をいじらないといけないようだ。
で、そこら辺を考えていた時に、ようやく w3mメーリングリストに「East Asian Ambiguous文字を全角でも表示できるようにする」というパッチが投稿されていることに気づいた*5。その w3m-cvs-1.914-ambwidth.patch を当てて、オプションで "Use double width for some Unicode characters" を有効にしてみたところ、table や hr の表示は崩れなくなった。でも、フォームの select メニューの表示は崩れたままだった。
ここで、とりあえず時間切れ。問題はいまだ解決せず。
mlterm や xterm ではどうなってるのかなあ。

追記1 mlterm と xterm で試してみた

mlterm で試してみたところ、w3m の表示は全く崩れなかったけど、罫線や記号文字が半角で表示されるし、Emacs の表示も崩れた。xterm では、-cjk_width 無しだと mlterm と同様で、-cjk_width 有りだと罫線表示は崩れるけどフォームのメニュー表示は崩れなかった。
フォームのメニュー表示が崩れるのは PuTTY の問題なのかも。

追記2 メニュー表示が崩れる原因が判明 (10/1)

実は原因は GNU screen だった。詳細は10月1日の日記に。

*1:zsh だけは backports.org に頼った。

*2:http://unicode.org/reports/tr11/

*3:なお、xterm の場合は -cjk_width というオプションを付けた場合に全角扱いになる。

*4:emacs21 + mule-ucs。"(set-language-environment 'Japanese)" を指定している。

*5: w3m-dev 4013w3m-dev 4049 より。