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で作業中です。