2013年8月31日
CSS3のtext-decorationは、-line、-color、-styleのshorthandプロパティに変更になりますが、text-decoration: blink;をlonghandプロパティだけで表現することが、以前のドラフトではできない状況でした。そこで、さらに古いドラフトに存在していたtext-blinkを一時的に実装し、blink値の入れ物として使っていましたが、その後のドラフトではtext-decoration-lineにblink値も含めるように変更されました(この表記だと、装飾線が点滅するようにしか見えないので、個人的には嫌いですが)。
このバグで、最新の仕様にあわせ、text-blinkプロパティを削除し、text-decoration-lineがblink値を許容するように修正しています。仕様の安定度からしてもそろそろ、-moz-プレフィックスを削除したいところですが、未だに他のブラウザエンジンは実装してきていないので、まだ外すのは危険なのかもという気もします。
自動テストで、擬似的に生成されたネイティブキーイベントをハンドリングしている最中に、デッドキー処理中にクラッシュする、というバグです。
詳しいコードの履歴は覚えていないのですが、私が、WM_CHARの処理にも、widget::NativeKeyを使用するようになったのがそもそもの原因でした。ただ、その修正は24以前で行ったものなので、何が原因で25からクラッシュするようになったのかは分かっていません。ただ、攻撃には使えなさそうなクラッシュなので、クラッシュする25以降でのみ修正しました。
GeckoのWindowsのキーイベント処理はメッセージキューを見て、ちょっと特殊なことをやっています。通常の文字入力の場合、WM_KEYDOWNメッセージを処理中に、続くWM_CHARメッセージをキューから取り除いて、そのままkeypressイベントを生成してしまいます。
このため、ごくごく特殊な場合にしか、WM_CHARメッセージのハンドラが動くことはないのですが、今回の件は、その特殊な場合に当てはまっていた上に、デッドキーの特殊処理に入るパターンでした。
デッドキーを2回連続で入力した場合、WM_KEYDOWN、WM_DEADCHAR、WM_KEYUP、WM_KEYDOWN、WM_CHAR、WM_CHAR、WM_KEYUPとなります。この、二つ目のWM_CHARも、2回目のWM_KEYDOWN中に処理されて、WM_CHARのハンドラが動くことはないと思っていたのですが、実際には、一つ目のWM_CHARだけが、WM_KEYDOWN中に処理され、残りのWM_CHARは、WM_CHARメッセージハンドラで処理されます。
この際に、デッドキーテーブルを参照する時に、配列の範囲外参照が発生してしまっていたので修正しています。将来的には、連続するWM_CHARをWM_KEYDOWN中に処理するようにしてしまいたいです。
Bug-org 501496の修正によるregressionで、<select>要素でドロップダウンを開いている時に、Enterキーで閉じた際、changeイベントのハンドラで、<input>にフォーカスを移動させると、その<input>要素上でkeypressイベントが発生し、これがフォームを送信してしまう、というバグです。
25以降では、Geckoでも、DOM keydownイベントで、preventDefault()を呼び出すと、keypressイベントは発生しなくなりました。このため、元のバグで、<select>要素の操作を、keypressイベントから、keydownイベントにタイミング変更を行いました。これは、keydownイベントでpreventDefault()が呼び出されても、操作ができないとセキュリティ的にも、ユーザビリティ的にも問題があるからです。
この変更によって、意図しないイベントの順序変更が発生していました。従来は、
keydown
keypress
change
だったのですが、変更後は他のWindowsのブラウザと同じく、
keydown
change
keypress
となっていました。WibKit/BlinkのMac版では、前者の順序というあたりが話がややこしいのですが。
それはさておき、<select>要素のドロップダウンをキーで閉じる、という操作を行った場合に、ユーザはそれ以上、何らかのアクションが発生するとは、考えていないはずです。ですので、ドロップダウンが閉じられた場合には、シンプルに、keydownイベントのpreventDefault()を呼び出すように変更しました。この方が、IEや、Windows版Blinkに合わせるよりも、従来のGeckoの動作に近く、ユーザの期待にも近いと考えたためです。このため、イベントの発生は以下のように変わっています。
keydown
change
つまり、フォーカス移動後の<input>要素で、keypressイベントが発生しなくなっています。
nsEventStateManagerが、グローバル変数に設定値をキャッシュしているにもかかわらず、何故か、全てのインスタンスが設定変更を監視していて、設定変更の際に、全てのインスタンスが同じ変数の値を上書きし続けるという、変なことになっていました。これにより、nsEventStateManagerのインスタンスが破棄される際に、設定変更監視を行っているオブジェクトの登録解除を行うコストがそこそこ高いらしく、タブを100から200程度ほど、一度に閉じると、相当なものになっていたようです。
今回の修正で、原則的には、Preferences::Add*VarCache()を使用するようにし、変更タイミングが必要なもののみ、staticなクラス(nsEventStateManager::Prefs)が監視するように変更しました。
この変更で、普段の利用でパフォーマンスの違いを体感できることはないと思いますが、大量に<iframe>を活用しているようなサイトだと、ms単位ではレスポンスが改善されていると思います。
GTK版Geckoでは、昔から、ネイティブウイジットで利用可能なショートカットキーをGecko上でも利用できるように、nsNativeKeyBindingsというクラスが、DOMキーイベントから、元のネイティブキーイベントを復元し、それを調べるということをやっていました。しかし、このネイティブキーイベントの復元が、DOMキーコードからの推測に基づくものだったので、そもそもDOMキーコードに変換されないキーでは動かないという問題を抱えていました(実際に通常のキーボードで発生する問題なのかは不明)。
今回の修正で、Bug-org 282097で追加されたnsKeyEvent::mNativeKeyEventに、GdkEventKeyのポインタを保存しておき、ロスレスで、ショートカットキーの調査が可能なように改善しています。
MacのJISレイアウトのフルキーボードでは、テンキーにカンマのキーがあります。このキーのハンドリングをKeyboardEvent.key以外ではやっていなかった、というバグです。
今回の修正により、このキーの、KeyboardEvent.location、KeyboardEvent.keyCode値が正しく返されるようになっています。
keydownイベントハンドラで、XMLHttpRequest.send()を同期通信として使用すると、ハングアップするというバグです。ギリギリ、Betaで重大なバグが発見され、報告されました。本当に助かります。
同期通信が行われた場合、本来なら、その通信が終わってから、keydownイベントが全ての必要な要素に配信された後に、keypressイベントが発生すべきです。しかし、Geckoの現在の設計でこれを行ってしまうと、通信中はウインドウを閉じたりすることすらできなくなってしまいます。これを解決するために、Geckoではメッセージループをネストさせて、chromeには次のWM_CHARメッセージを元にkeypressイベントを発生させ、contentには、通信終了後にキューにためておいたDOMイベントを発生させる、という実にトリッキーなことをやっています。
このため、keydownイベントの送信前に、WM_CHARメッセージの有無を確認しておき、送信後にWM_CHARメッセージをGetMessageW()で取得しにいったら、既にキューからは削除されているために、GetMessageW()から処理が返ってこない、というのが原因でした。
今回の修正では、送信前にWM_CHARメッセージの有無を確認してキャッシュするのではなく、リアルタイムで、WM_CHARメッセージの有無を確認後に、GetMessageW()を使用するように変更し、ハングアップを回避しています。
しかし、実にハッキーなことをやっているため、keydownイベントでpreventDefault()を呼んでも一切、無視されていますし、その後contentに送信されてくるイベントも正確性に欠くので、Web開発者の方は、同期通信を使わないようにした方が余計なバグを生み出さずに済むので良いでしょう(そもそもレスポンスの面から、使うことは希だと思うのですが、実情は全く知りません)。
Bug-org 907612の修正のregressionで、GTK版Geckoの、HTMLエディタ上でペーストや、カーソル移動をキーボードから行おうとすると、2回実行される、というバグです。
HTMLエディタのnsINativeKeyBindingsの呼び出し元は、FirefoxやThunderbirdで定義されている、全てのショートカットキーの実行を行った後に、nsINativeKeyBindingsにフォールバックを行います。
しかし、フォールバックを行う前に行っていた、defaultPreventedのチェックが削除されてしまったため、二重に動作するようになってしまっていました。
それにしても、ネイティブウイジットのショートカットキーの方がフォールバック先、という設計はどうなんでしょうね……
デバッグビルドでのみ、Commandキーや、Controlキーを押した際に、希にクラッシュすることがある、というバグです。
Macのモディファイアフラグには、デバイス依存フラグと、デバイス非依存フラグがあり、通常のキーイベントであれば、双方に適切なフラグが設定されています。デバイス非依存フラグを検査しないと、キーコード不明な状況で、モディファイアフラグのみが変更された場合に、生成すべきモディファイアキーのkeydownイベントと、keyupイベントの左右の違いが、デバイス非依存フラグだけでは分からないので、通常のモディファイアキーイベントが発生した場合に、左右の区別がつく、ネイティブキーコード値と、同じく、左右の区別がつくものの、ドキュメントが存在しない(OS内部使用のための)デバイス依存フラグの関連を保存しています。
このクラッシュは、既に保存していた関係と、新たに発生した通常のモディファイアキーイベントの情報とに違いが発生した場合に発生していました。
結局、相当な時間、テストしてみたものの、そのような状況は再現できず、この狂いが何故発生しているのか、その原因は分からないままです。そのため、狂いが生じた際には、デバッグビルドでもクラッシュさせず、保存してあるキーコードと、デバイス依存フラグの関係を全て破棄して、記録しなおすように修正しました。
元々、この保存情報が必要になることはほとんど無く、レアケースへの対応なので、万が一、情報が無い際に、キーコード不明なモディファイアフラグ変更が発生しても、KeyboardEvent.locationの値が狂う(右側のキーを押した場合に、DOM_KEY_LOCATION_LEFTが返される)だけなので、現実的には問題は発生しないと思います。
Bug-org 907657の修正の解説で書いた、contentで後から発生するイベントが、D3Eに対応できていない、というバグです。
遅延発生するイベントは、nsDelayedKeyEventと、nsDelayedMouseEventで、元のイベントの発生時にコピーされ、保存されるのですが、この保存するコードに、D3E用の新しいメンバのコピーを追加していなかったのがその原因です。
同様のミスを無くす為、nsKeyEvent::AssignKeyEventData()と、nsMouseEvent::AssignMouseEventData()を作成し、イベントのコピーを行う場所ではこれを利用するように修正しました。これにより、今後は同様なミスがなくなると思います。
また、他のイベントについては、Bug-org 910978で作業中です。