この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2013年2月)

2013年2月7日

Bug-org 835280 IME shouldn't be committed at activating composing window 初回投稿日時: 2013年02月07日19時03分50秒
カテゴリ: Mozilla Core Mozilla19 Mozilla20 Mozilla21 バグ修正 バグ却下
固定リンク: id=2013020700
リンク元: 0件
SNS: (list)

Bug-org 805766の修正によるregressionです。

designModeエディタでは、フォーカスイベントがどの要素でも発生しないため、nsIMEStateManager::OnChangeFocus()が呼び出されないことが問題だったため、ドキュメントでフォーカスイベントが発生するタイミングでもnsIMEStateManager::OnChangeFocus()を呼び出すようにしました。

しかし、ここに何の制限も加えていなかったため、エディタにフォーカスがある状態でFirefox以外のアプリをアクティブにし、その状態でFirefoxのウインドウをアクティブにすると、まず、ドキュメントがフォーカスイベントを受け取る直前に、nsIMEStateManagerは、エディタが一端、ドキュメント内でもフォーカスを失った(DOMで言うなら、アクティブな要素ではなくなった)と誤解し、その直後、そのエディタでフォーカスイベントが発生する際に、再びフォーカスを得た誤解していました。もちろん、実際には、アクティブな要素はエディタの要素のままで、一度も非アクティブにはなっていませんので、nsIMEStateManagerの状態把握が誤っていることになります。ですが、この誤解のため、ドキュメントのフォーカスイベントの直前でnsIMEStateManagerがIMEを強制確定してしまっていました。

この修正では、designModeエディタ以外のエディタがフォーカスを持っている場合には、Bug-org 805766の修正が必要ありませんので、Bug-org 805766の修正である、nsIMEStateManager::OnChangeFocus()の新しい呼び出しを、そのドキュメントがdesignModeの場合にのみ行うように制限しています。

このバグは、今月リリースされるFirefox 19から発生していますが、Firefox 19での修正は、リスクとユーザへの影響のバランスから、見送られることになりました。異論がある場合、つまり、修正しなければならない、深刻な理由があると考える場合はバグの方へ直接コメントをお願いします。

既に、Firefox 20 (Aurora)以降では修正が完了しています。

Bug-org 838001 Input Method can't be opened to type to input fields in a panel on Firefox 19+ 初回投稿日時: 2013年02月07日19時33分28秒
最終更新日時: 2013年02月07日23時18分57秒
カテゴリ: Firefox Mozilla Core Mozilla19 Mozilla20 Mozilla21 バグ修正
固定リンク: id=2013020701
リンク元: 0件
SNS: (list)

Firefox 19以降では、Add-on SDKで生成した"panel"上にある<input type="text">や、<textarea>等ではIMEが利用できない、というバグです。重大なIMEのregression報告をえむけいさんが発見し、私をCCしてくれたのが不幸中の幸いでした。本当に感謝、感謝です。

このregressionの発生経緯が少しややこしいのですが、まず、Bug-org 705057の修正で、IMEに強制確定をリクエストする際に仲介するnsIWidgetnsPresContextから取得するメソッドを、nsEditor::GetWidget()や、nsDOMWindowUtils::GetWidget()パクり参照し、nsPresContext::GetNearestWidget()というメソッドを作成しました。その内容は名前の通り、nsPresContextの管理しているnsIPresShellのルートフレームを持つ、もっとも近い親のnsIWidgetを返すようにしていました。

次に、これは便利なメソッドで読みやすい、ということで、Bug-org 802896の修正で、nsIMEStateManager::GetWidget()を削除し、IMEの管理コードは全て、nsPresContext::GetNearestWidget()を利用して、IMEと仲介してくれるnsIWidgetを取得するようにしました。

さらに、nsIMEStateManager::GetWidget()と同じ方法でnsIWidgetを取得していたコードがnsTextStateManagerの生成箇所にもあったので、Bug-org 805306の修正時に、nsPresContext::GetNearestWidget()を利用するようにしていました。

しかし、Bug-org 802896の修正時に疑問だったのですが、nsIMEStateManager::GetWidget()nsPresContextのトップレベルのnsIWidgetを返していました。違いは気になっていましたが、異なる値を返すパターンをwidget removalの成果もあったおかげで発見できませんでしたので、問題はないと判断しましたが、このケースが発見された訳です。

Add-on SDKの作る"panel"は、フォーカスを失うと自動的に閉じてしまうために、デバッグしにくく、その正確な正体を掴めていませんが、デバッガで様子を見ている限りは、そのアドオン用に独立したnsPresContextを作り、さらに、子ネイティブウイジットを"panel"用に生成して、その上にコンテンツを配置しているようです。ですが、実際にフォーカスをもつネイティブウイジットはその親にあたる、トップレベルウイジットの用な症状です。

そこで、nsIMEStateManager::GetWidget()と同じ値を返す、nsPresContext::GetRootWidget()を作成し、IME関連のコードは全てこれを利用するようにしたところ、バグを修正できました。

これらの結果からすると、パクった参考にしたnsEditor::GetWidget()と、nsDOMWindowUtils::GetWidget()はIME関連で利用されるのは間違ってると言えます。前者は強制確定を行うために使われていましたが、各プラットフォームで、子ウイジットで呼び出された強制確定の処理は、同一のコンテキストを持つ、他のウイジット上でも機能しますし、後者は自動テストでの偽Compositionイベント生成用ですので、間違ったnsIWidgetからイベントが生成されても行き着く先は同じなので問題になりません。

今回のバグはFirefox 19以降で発生していますが、こちらは、かなり深刻ですので、Firefox 19以降、全てのブランチで修正が行われています(なんと、マージのタイミングの問題から、mozilla-centralよりも先にbetaで修正されてしまいました)。

2013年2月19日

Bug-org 674739 Implement DOM3 KeyboardEvent types for audio 初回投稿日時: 2013年02月19日11時55分51秒
最終更新日時: 2013年02月19日11時56分08秒
カテゴリ: Events Mozilla Core Mozilla21 バグ修正
固定リンク: id=2013021900
リンク元: 0件
SNS: (list)

バグのサマリが良くないんですが、このバグの修正で、オーディオのボリュームに関するkeyCode値が新たに定義されました。

  const unsigned long DOM_VK_VOLUME_MUTE    = 0xB6;
  const unsigned long DOM_VK_VOLUME_DOWN    = 0xB7;
  const unsigned long DOM_VK_VOLUME_UP      = 0xB8;

という感じで値が割り当てられ、現在、Windowsではマッピングされています。Windowsで実際にこれらのキーが利用されているキーボードドライバは知りませんが……

レガシーなkeyCode値を新たに定義したのは、内部処理で必要だから、ということです。

Bug-org 833719 Some function keys are not working since Firefox Version 15 初回投稿日時: 2013年02月19日13時08分55秒
最終更新日時: 2013年02月19日13時09分37秒
カテゴリ: Events GTK Mozilla Core Mozilla21 Windows バグ修正
固定リンク: id=2013021901
リンク元: 0件
SNS: (list)

Firefox 14までは、Windows/Linux/Macで、キーボードレイアウトとプラットフォームによってはほとんどのキーがkeyCode値が0になっていたり、同じキーボードレイアウトの同じキーがプラットフォーム毎に違う値を返すことがあったりするバグが長年、問題になっていたので、Firefox 15では、Bug-org 630810 (Windows)の修正Bug-org 677252 (Mac)の修正Bug-org 447757 (Linux)の修正で、ほぼ、これらの問題を一掃しましたが、その際に今まで、Windowsでは、ネイティブのvirtual keycode値でDOM keyCode値が定義されていないものに関してはそのままの値をセットするというのを取りやめ、マッピングできないもの、つまり、一般的なWebアプリで処理されるべきではないキーに関しては、keyCode値が0になるようになりました。

このバグは、特定の顧客に向けたWebアプリを提供する報告者の視点からすると、IEやWindows版のWebKitと同じkeyCode値が来ないのは困るというのものでした。

まず、上記バグで新たに定義したkeyCode値は今更動かすとさらに混乱が増すので、これらと重なる値については断念せざるを得ません。しかし、幸い、報告者が問題にしているkeyCode値はこれらとかぶっているものがありませんでした。

しかし、報告者が必要とするkeyCode値にはいくつか問題がありました。まず、顧客の利用している特殊なキーボードの実際のキーの刻印に反して、適切なvirtual keycode値が利用されておらず、OEM specificキーの値を多用している、さらに、Windows SDKで未定義、もしくは予約されているvirtual keycode値も利用している、複数のキーで同じvirtual keycodeを利用している(scan code値は異なっている)、というものです。

OEM specificキーは特殊なハードウェアにWindowsを組み込む際に内部利用用に予約されているようなものですので、本来はWebアプリから見える必要すらありません。その値から、キーの意味を知ることができないからです(つまり、Windows以外の環境ではマッピングしようがないので、非Windows環境でアクセシビリティ上、問題のあるものしか作れない)。しかし、上述のように、特定の顧客に向けたソリューションでは決め打ちで利用することに価値がありますので、これらの値をWindowsでのみ、Webアプリから利用可能にしました。以下がその一覧(定義)です。

  // OEM specific virtual keyCode of Windows should pass through DOM keyCode
  // for compatibility with the other web browsers on Windows.
  const unsigned long DOM_VK_WIN_OEM_FJ_JISHO   = 0x92;
  const unsigned long DOM_VK_WIN_OEM_FJ_MASSHOU = 0x93;
  const unsigned long DOM_VK_WIN_OEM_FJ_TOUROKU = 0x94;
  const unsigned long DOM_VK_WIN_OEM_FJ_LOYA    = 0x95;
  const unsigned long DOM_VK_WIN_OEM_FJ_ROYA    = 0x96;
  // OEM specific virtual keyCode of Windows should pass through DOM keyCode
  // for compatibility with the other web browsers on Windows.
  const unsigned long DOM_VK_WIN_ICO_HELP    = 0xE3;
  const unsigned long DOM_VK_WIN_ICO_00      = 0xE4;
  const unsigned long DOM_VK_WIN_ICO_CLEAR   = 0xE6;
  const unsigned long DOM_VK_WIN_OEM_RESET   = 0xE9;
  const unsigned long DOM_VK_WIN_OEM_JUMP    = 0xEA;
  const unsigned long DOM_VK_WIN_OEM_PA1     = 0xEB;
  const unsigned long DOM_VK_WIN_OEM_PA2     = 0xEC;
  const unsigned long DOM_VK_WIN_OEM_PA3     = 0xED;
  const unsigned long DOM_VK_WIN_OEM_WSCTRL  = 0xEE;
  const unsigned long DOM_VK_WIN_OEM_CUSEL   = 0xEF;
  const unsigned long DOM_VK_WIN_OEM_ATTN    = 0xF0;
  const unsigned long DOM_VK_WIN_OEM_FINISH  = 0xF1;
  const unsigned long DOM_VK_WIN_OEM_COPY    = 0xF2;
  const unsigned long DOM_VK_WIN_OEM_AUTO    = 0xF3;
  const unsigned long DOM_VK_WIN_OEM_ENLW    = 0xF4;
  const unsigned long DOM_VK_WIN_OEM_BACKTAB = 0xF5;
  // OEM specific virtual keyCode of Windows should pass through DOM keyCode
  // for compatibility with the other web browsers on Windows.
  const unsigned long DOM_VK_WIN_OEM_CLEAR  = 0xFE;

実際に、これらの値がどれほど変なものかというと、身近なJISキーボードにある特殊なキーを押してみると分かります。以下の表を見てみて下さい。

JISキーボードレイアウトの特殊キーと、virtual keycode値、DOM keyCode値の対応表
キーvirtual keycodeDOM keyCode
半角/全角VK_OEM_AUTO (WM_KEYUP)、VK_OEM_ENLW (WM_KEYDOWN) (もう一度押すと、逆になる)KeyboardEvent.DOM_VK_WIN_OEM_AUTO (keyup)、KeyboardEvent.DOM_VK_WIN_OEM_ENLW (Keydownkeypress)
漢字(Alt + 半角/全角)VK_KANJI (WM_SYSKEYDOWNWM_SYSKEYUP)KeyboardEvent.DOM_VK_KANJI (keydownkeypresskeyup)
英数VK_OEM_ATTN (WM_KEYDOWNのみ)KeyboardEvent.DOM_VK_WIN_OEM_ATTN (keydownkeypressのみ)
CapsLock (Shift + 英数)VK_CAPITALKeyboardEvent.DOM_VK_CAPS_LOCK (keydownkeyup)
カタカナ ひらがなVK_OEM_COPY (WM_KEYDOWNのみ。VK_OEM_ATTNWM_KEYUPが先に発生することもあり)KeyboardEvent.DOM_VK_WIN_OEM_COPY (keydownkeypressのみ。VK_OEM_ATTNが先行した場合は、KeyboardEvent.DOM_VK_WIN_OEM_ATTNkeyupが先行する)
ローマ字 (Alt + カタカナ ひらがな)VK_ATTN (WM_SYSKEYUP)、VK_OEM_BACKTAB (WM_SYSKEYDOWN) (もう一度押すと逆になる)KeyboardEvent.DOM_VK_ATTN (keyup)、KeyboardEvent.DOM_VK_WIN_OEM_BACKTAB (keydownkeypress)

と、このような感じです。VK_OEM_AUTOVK_OEM_ENLWが特に複雑で、どちらかが半角を意味し、どちらかが全角を意味していて、どちらかが押されっぱなしの状態を作り出していることがうかがえます。とてもではないですが、Webアプリからすると、JISキーボードのハンドリングとしては使えたものではない挙動です。

これ以外にも、以下のkeyCodeが副作用も考えられないので定義されました。

  // Following keys are not used on most keyboards.  However, for compatibility
  // with other browsers on Windows, we should define them.
  const unsigned long DOM_VK_ATTN           = 0xF6;
  const unsigned long DOM_VK_CRSEL          = 0xF7;
  const unsigned long DOM_VK_EXSEL          = 0xF8;
  const unsigned long DOM_VK_EREOF          = 0xF9;
  const unsigned long DOM_VK_PLAY           = 0xFA;
  const unsigned long DOM_VK_ZOOM           = 0xFB;
  const unsigned long DOM_VK_PA1            = 0xFD;

DOM_VK_ZOOM以外は、昔のIBMのコンピュータのキーボードに存在したキー向けと思われるので、Linuxでも同等のものをマッピングしています。ちなみに、VK_ZOOMを利用するキーボードは私は知りません。

これら以外の未定義や、予約済みのvirtual keycode値はWebアプリに渡す予定はありません。これらの値が将来定義され、他のプラットフォームでマッピングが必要になるかもしれないからです。

2013年2月28日

Bug-org 708936 Remove hack for bug 262894 and bug 28852 初回投稿日時: 2013年02月28日19時11分41秒
カテゴリ: Events Mozilla Core Mozilla21 Windows バグ修正
固定リンク: id=2013022800
リンク元: 0件
SNS: (list)

Windows版のGeckoに古くからあった、ハッキーなコードの削除を行いました。

Alt+半角/全角キーでIMEをオンオフする際に、Altキーのkeyupイベントで、メニューバーがフォーカスされてしまう、というのがBug-org 28852で、この際には、Altkeydownイベントと、keyupイベントの間で、IMEのオン/オフが切り替わった場合に、ダミーのキーイベントを生成することで、メニューバーが動かないようにするという修正が行われていました。

また、Altキーと何らかのキーの組み合わせがシステム、もしくは他のアプリで利用された場合に、そのAltkeyupイベントでメニューバーがフォーカスされてしまう、というのがBug-org 262894で、この際には、Altキーがショートカットキーとして利用された場合に、WM_SYSKEYUPではなく、WM_KEYUPAltキーのkeyup時に利用されることを利用し、Altキーのkeyupイベント自体を生成しないように修正が行われていました。

以前、Bug-org 749563の修正により、defaultPreventedtrueの場合には、メニューバーがフォーカスを奪わないように修正していたので、今回の修正はこれを利用し、まず、前者のダミーのキーイベントの生成を削除、次に、後者のケースで、defaultPreventedtrueAltキーのkeyupイベントを生成するようにしました。

Bug-org 840409 Implement IMEHandler which hides nsIMM32Handler and nsTextStore from non-IME handlers 初回投稿日時: 2013年02月28日19時25分23秒
カテゴリ: Mozilla Core Mozilla22 TSF Windows バグ修正
固定リンク: id=2013022801
リンク元: 0件
SNS: (list)

WindowsのIMM用のモジュールである、nsIMM32Handlerと、TSF用のモジュールであるnsTextStoreへのアクセスをnsWindow等から個別に行っていましたが、ここで、片方の状態だけを確認したり、TSFモードでもIMMのコードが呼ばれていたりと、色々とバグが多いという問題がありました。

こういった問題を解決するために、mozilla::widget::IMEHandlerというクラスを作成し、nsWindow等、IMEのハンドラ以外からはこのクラスを経由してIMEの処理を行うように改善しました。

widget::IMEHandlerは、自動的にnsIMM32Handlerを呼び出すべきなのか、nsTextStoreを呼び出すべきなのかを判断し、原則としてどちらかのみで動作します。

このバグの副作用により、TSFモードでは、ATOK 2013の候補ウインドウの位置が、ATOK 2012と同様に、奇妙な位置に表示されることがあるという現象が確認されています。オーナーがあるウインドウ上、例えば設定ダイアログ上では問題が一切無かったり、他のIMEでも問題はありません。また、TSFの仕様では座標位置はウインドウに対する相対位置ではなく、スクリーン座標で返している、また、問題が出ないケースもあるので、Gecko側の問題ではないように思えますが、なんとも不思議な状況ではあります。