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

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

もずはっく日記(2016年3月)

2016年3月16日

Bug-org 1137572 Add some useful methods to TextEventDispatcher for native key and IME handlers 初回投稿日時: 2016年10月15日20時55分24秒
最終更新日時: 2016年10月15日21時06分23秒
カテゴリ: Events IME KeyboardEvent Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016031600
SNS: (list)

widgetのコードが、OSから送信されてくる、キーボードやIMEの入力イベントから、DOMイベントのもとになる、WidgetEventを生成する部分をできる限りプラットフォーム非依存のコードに置き換えようという修正のための準備です。

自動テストでキーボードやIMEの入力をエミュレーションする際に、現在はJavascriptから、nsITextInputProcessorを利用します。nsITextInputProcessormozilla::TextInputProcessorとして実装され、内部ではmozilla::widget::TextEventDispatcherにイベントを生成しています。

順序が逆になりますが、このTextEventDispatcherが実際のユーザの入力イベントからも利用されるようになると、自動テストがより多くのコードをテストできるようになります。しかも、これまで、widgetのコードはネイティブイベントを受け取ると、他のブラウザや、策定中のUI Eventsにあわせたイベントの生成をそれぞれ固有のコードで行っていましたが、これをプラットフォーム非依存にすれば、プラットフォーム間でのGeckoの動作がより確実に均一なものになり、動作を変更する際のコストも大きく下がります。

これを実現するためには、TextEventDispatcherにいくつか、widgetから使いやすい形のメソッドを新たに追加しておく必要がありました。それを実装したのがこのバグ修正です。

まず、TextEventDispatcherは入力のトランザクションという概念を持っています。例えば、あるオブジェクトが未確定文字列を持っている際に、他のオブジェクトが新たに未確定文字列を生成しようとしたりすると、大混乱に陥ります。そのため、イベントを発生させるメソッドを呼び出す前に、トランザクションを確立する必要があります。この際に、トランザクションのタイプを指定できるようにしました。widgetがユーザからの入力イベントを処理する際にはeNativeInputTransactionを用いることで、ユーザの入力が悪意、もしくはバグのあるアドオンによって妨害されることを阻止することができるようになっています。

次に、TextEventDispatcherのインスタンスはnsIWidgetのインスタンスごとに作成されるようになり、nsIWidget::NotifyIME()TextEventDispatcher経由で、TextEventDispatcherListenerクラスの派生クラスで受け取るように変更されました。

TextEventDispatcherListenerのインスタンスは各OSのネイティブIMEのコンテキストの数だけ存在していなければならず、nsIWidget::GetNativeTextEventDispatcherListener()nsIWidgetのインスタンスに関連付いたネイティブIMEコンテキスト用のTextEventDispatcherListenerを取得できるようにしなければいけません。

この設計により、エディタから送信されてくるコンテンツの変更に関する情報や、未確定文字列の確定や破棄のリクエストを現在、トランザクションを確立しているTextEventDispatcherListenerに通知することができるようになっており、また、フォーカスの移動といった、トランザクションが確立していなくても受け取る必要のあるものを複数のTextEventDispatcherListenerインスタンスに配信できるようになっています。

さらに、keypressイベントに"key hell"に対応するために、キーの様々なモディファイアキーの状態での入力文字列を簡単に追加できるように、TextEventDispatchereKeyPressイベントの発火直前にTextEventDispatcherListener::WillDispatchKeyboardEvent()を呼び出します。この際に、WidgetKeyboardEvent::mCharCodeWidgetKeyboardEvent::mAlternativeCharCodesを上書きできるようになっています。これにより、既存のwidgetの"key hell"対応コードを単に、このメソッド内にカット・アンド・ペーストするだけで新設計に移行できます。

他にもいくつかメソッドを追加していますが、それは実際に利用される際にヘッダファイルを参照してください。

Bug-org 1137561 Make KeyboardLayout, nsIMM32Handler and nsTextStore should use TextEventDispatcher 初回投稿日時: 2016年10月15日21時16分19秒
最終更新日時: 2016年10月15日21時16分53秒
カテゴリ: Events IME KeyboardEvent Mozilla Core Mozilla48 TSF Windows バグ修正
固定リンク: id=2016031601
SNS: (list)

Bug-org 1137572の修正にあわせて、Windowsのネイティブキーイベントをハンドリングしている、NativeKeyIMM経由でIMEを処理しているIMMHandlerTSF経由でTIPを処理しているTSFTextStoreからTextEventDispatcherを利用するように修正しました。

WindowsではネイティブのIMEコンテキストはプロセス全体でひとつのみなので、TextEventDispatcherListenerは、シングルトンクラスとしてmozilla::widget::WinTextEventDispatcherListenerに実装されています。

Bug-org 1137565 Make KeymapWrapper and nsGtkIMModule use TextEventDispatcher 初回投稿日時: 2016年10月15日21時22分35秒
カテゴリ: Events GTK IME KeyboardEvent Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016031602
SNS: (list)

Bug-org 1137572の修正にあわせて、Linux、GTK版のネイティブキーイベントハンドのKeymapWrapperと、IMEイベントハンドラのIMContextWrapperからTextEventDispatcherを利用するように修正しました。

ネイティブのIMEコンテキストは、IMContextWrapperと1対1の関係にあるので、TextEventDispatcherListenerIMContextWrapperに実装されています。

Bug-org 1137563 Make TextInputHandler use TextEventDispatcher 初回投稿日時: 2016年10月15日21時33分10秒
最終更新日時: 2016年10月15日21時33分28秒
カテゴリ: Events IME KeyboardEvent Mac Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016031603
SNS: (list)

Bug-org 1137572の修正にあわせて、Mac版のネイティブキーイベントをハンドリングしているTextInputHandlerとネイティブIMEイベントをハンドリングしているIMEInputHandler、さらにこれらの基底クラスであるTextInputHandlerBaseTextEventDispatcherを利用するように修正しました。

OS XではネイティブのIMEコンテキストはトップレベルウインドウ単位で存在している様(ドキュメントでは見つけていないものの、実際の挙動を確認しているとその模様)ですが、GeckoのはNSViewがトップレベルウインドウ内にひとつだけ存在し、フォーカスを持つという構造なので、NSViewごとに作られるnsChildViewのメンバであるTextInputHandlerBaseTextEventDispatcherListenerを実装しています。

この様な事情のため、トップレベルウインドウであるnsCocoaWindowGetNativeTextEventDispatcherListener()は常にnullptrを返すことに注意してください(ただ、クロスプラットフォームなコードからnsIWidgetのインスタンスにアクセスする際に、それがnsCocoaWindowであることは関連するコードでは無いことですが)。

Bug-org 1249184 [UI Events] Implement Dead key event on Mac OS X 初回投稿日時: 2016年10月15日21時40分24秒
カテゴリ: KeyboardEvent Mac Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016031604
SNS: (list)

Mac版のGeckoはデッドキーのイベントを正しく発火していないというバグです。

Mac版のGeckoは、IMEが有効ではない場合(MacではデッドキーはIMEとして実装されています)、他のブラウザとは異なり、デッドキーを押した時にkeypressイベントが発火していましたが、まずこれを発火しないように修正しました。

また、デッドキーが押下された際のkeydownイベントとkeyupイベントのKeyboardEvent.key値は仕様通り、"Dead"になるように修正しました。

Bug-org 1203059 [non-e10s] Keyboard events which are reserved shortcuts in chrome shouldn't be fired on web content like e10s mode 初回投稿日時: 2016年10月15日21時59分57秒
最終更新日時: 2016年10月15日22時04分56秒
カテゴリ: Events KeyboardEvent Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016031605
SNS: (list)

e10sモードではchromeが予約済みのショートカットキーのkeypressイベントはWebコンテンツ上では発火しないようになっていましたが、それを非e10sモードでもそのような動作に修正すべきであるというバグです。

私は関与していなかったのですが、すでに関係者でディスカッションが行われ、ユーザが悪意あるWebサイトによって、キーボードだけで操作不能に陥らないように、いくつかのショートカットキーはWebコンテンツで上書きできないようにする、そのためにそもそも、イベントを発火しないようにする、ということになっていました。これは、Google Chrome、Edge、Safariの動作にあわせた変更決定です。

nsXBLWindowKeyHandlerは、XULのdocumentノードにイベントリスナを設置し、キャプチャフェイズで真っ先に、keypressイベントが予約されたキーコンビネーションのものかどうかを確認します。そこで、今回の修正では、この時に予約されていることが分かると、WidgetKeyboardEvent::mFlags::mOnlySystemGroupDispatchInContenttrueにします。これがtrueの場合、その名前の通り、そのイベントはWebコンテンツのノードではシステムグループに登録されているイベントリスナしか実行しなくなります(つまり、デフォルトグループのchrome、システムグループのchrome、システムグループのcontentのリスナでのみ実行されます)。

このため、Webコンテンツから見ると、予約済みのショートカットキーのkeypressイベントは全く発火されないように見えることになります。

ちなみに予約済みショートカットキーは、Firefoxのソースコードをreserved="true"で検索すると、XULの<command>要素か<key>要素がヒットしますので、これを参考にしてください。

2016年3月24日

Bug-org 1154183 nsXBLWindowKeyHandler shouldn't fire keydown events in content when following keypress event is "reserved" by XUL <command> element 初回投稿日時: 2016年10月15日22時14分26秒
最終更新日時: 2016年10月16日10時28分20秒
カテゴリ: Events KeyboardEvent Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016032400
SNS: (list)

Bug-org 1203059の修正により、予約済みのショートカットキーにマッチするkeypressイベントはWebコンテンツ上では発火されなくなりました。しかし、keydownイベントは引き続き発火されるままなので、keydownイベントのpreventDefault()を呼び出すことにより、相変わらず、予約されているショートカットキーを無効化できてしまいます。

この修正では、予約されているショートカットキーは、keydownイベントの段階で処理ハンドリングされるように修正しました。このため、chromeスクリプト内といえども、予約されているキーコンビネーションではそもそもkeypressイベント自体が発火しなくなっています。

この修正では、予約されているショートカットキーのkeydownイベントも、nsXBLWindowKeyHandlerによって、Webコンテンツ上ではデフォルトグループのリスナを実行しないように修正されました。また、副作用を抑えるために、keydownはそのまま流し、keypressイベントを従来通りに処理するように修正しています。

また、"key hell"に対応するため、各widgetのTextEventDispatcherListener::WillDispatchKeyboardEvent()を修正し、eKeyDownイベントの場合もmAlternativeCharCodesに様々なモディファイアキーの状態の際に入力される文字の情報をセットするようにし、また、その最初に、続いて発生するeKeyPressイベントのmCharCode値にあたるものをセットするようにしています(この修正のために、Bug-org 1137572の修正や、それに付随した各OS向けのwidgetの変更が必要だったわけです)。

Bug-org 1256589 Some methods of dom::Event should be implemented in WidgetEvent 初回投稿日時: 2016年10月15日22時23分28秒
カテゴリ: Events Mozilla Core Mozilla48 バグ修正
固定リンク: id=2016032401
SNS: (list)

WidgetEventには何故か以前からフラグを適切にセットするヘルパーメソッドが用意されておらず、各フラグの意味を知らないと、複数のフラグを同時に設定しないといけない場合にバグが混入しやすい状況になっていました。そこで、このバグではいくつかのヘルパーメソッドを追加することで、その処理をカプセル化しています。

追加されたのは以下のメソッド達。

  • WidgetEvent::StopPropagation()
  • WidgetEvent::StopImmediatePropagation()
  • WidgetEvent::StopCrossProcessForwarding()
  • WidgetEvent::PreventDefault(bool aCalledByDefaultHandler = true)
  • WidgetEvent::PreventDefaultBeforeDispatch()
  • WidgetEvent::DefaultPrevented()
  • WidgetEvent::DefaultPreventedByContent()
  • WidgetEvent::IsTrusted()
  • WidgetEvent::PropagationStopped()

Bug-org 1258153 Alt codes to input unicode is broken 初回投稿日時: 2016年10月15日22時39分36秒
最終更新日時: 2016年10月15日22時40分49秒
カテゴリ: KeyboardEvent Mozilla Core Mozilla48 Windows バグ修正
固定リンク: id=2016032402
SNS: (list)

日本ではあまり有名な機能では無いように思うのですが、Windowsでは、Altキーを押しながら、テンキーでUnicodeのコードポイントを4桁で入力して、Altキーを離すと、そのコードポイントの文字が入力されます。しかし、これが、regressionにより機能しなくなっているというバグです。

Bug-org 1137561の修正によるregressionと思われますが、はっきりはしません。

この入力を行ったときに以下のようにメッセージが発行されます。

  1. WM_SYSKEYDOWN (wParamVK_MENU)
  2. WM_SYSKEYDOWNWM_SYSKEYUPが4セット
  3. WM_SYSKEYUP (wParamVK_MENU)
  4. WM_CHAR (wParamは入力されたUnicode文字、lParamのスキャンコードはAltキーのもの)

そして、最後のWM_CHARがスキャンコードから、"Alt"キーとして処理されていました。このため、何の文字も入力されていませんでした。

今回の修正では、NativeKeyWM_CHARの受信によって生成されていた場合、KeyboardLayout::InitNativeKey()はキーボードレイアウトの情報を利用せず、WM_CHARの内容でNativeKeyを初期化するようにしました。

2016年3月25日

Bug-org 1257761 [Linux][GTK] windowed plugins shouldn't consume reserved shortcut keys of chrome 初回投稿日時: 2016年10月16日11時24分56秒
カテゴリ: Flash GTK KeyboardEvent Mozilla Core Mozilla48 plugin バグ却下
固定リンク: id=2016032500
SNS: (list)

Linux版で、windowedプラグインにフォーカスがある時に、Firefoxのショートカットキーが使えないというバグです。

windowlessプラグインしか存在しないMacや、windowedプラグインでも、Geckoのプラグインプロセスが先にイベントを処理できるWindowsでは、先にGeckoがショートカットキーをハンドリングすることが可能です。しかし、問題はこのLinux、GTK版です。

GTKでは、イベントを受け取るために、各プロセス内でシグナルを受け取るように関数をAPIを使って登録します。さらに、キーボードイベントを処理する前に、一旦、IMEにキーボードイベントを渡し、IMEが必要としていないキーイベントかどうかを知る必要があります(これはテストだけではなく、IMEがその時点で必要なキーイベントならハンドリングしてしまいます)。

このことから、明らかに大きな問題が二つあることが分かります。ひとつめは、どうやって、プロセス外からイベントを先に取得するのか。ふたつめは、どうやってプラグインプロセスの中にあるIMEにキーイベントを渡すのか。この二つを解決するには、プラグイン側から一旦イベントを渡してもらう必要があります。しかし、Linux版のNPAPI版 Flash Playerは既に開発を停止して久しいです。また、MozillaもFlash Playerへの対応を縮小していく方向で動いています。

これらの外的な事情と、技術的に解決が困難という点から、このバグは修正しないという結論に至りました。

2016年3月28日

Bug-org 1257760 [Mac] plugins shouldn't consume reserved shortcut keys of chrome 初回投稿日時: 2016年10月16日10時31分06秒
カテゴリ: Flash KeyboardEvent Mac Mozilla Core Mozilla48 plugin バグ修正
固定リンク: id=2016032800
SNS: (list)

Macでプラグインにフォーカスがある時、Firefoxのショートカットキーがプ動作しないというバグです。Macでは、Cmd + Qでアプリを終了しますが、プラグインにフォーカスがあると、これが利用できないというのが非常に不便だという話です。

よくよく調査してみると、e10sモードでの文字列入力のバグを抑制するために、プラグインがフォーカスを持っている際にTextInputHandlereKeyPressイベントを発火しないようにされていました。

NSResponderinterpretKeyEventsにキーイベントを渡してしまうと、IMEがプラグイン外で動いてしまうので、それは行わないように条件を追加しつつ、eKeyPressイベントを通常通りに発火するように修正しています。