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

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

もずはっく日記(2021年9月)

2021年9月23日

最後発でbeforeinputイベントを実装しているはずなのに……
初回投稿日時: 2021年09月23日08時48分53秒
カテゴリ: Editor Events Firefox Google Chrome Safari
SNS: (list)

Geckoのエディタのリファクタリングからの続きです。

beforeinputイベントは各ユーザの操作に応じて、DOMツリーの変更前に一度だけ発火するというイベントです。例えば、テキストをキーボードから入力するとinputTypeinsertTextbeforeinputイベントが発火され、これをpreventDefault()するとブラウザのエディタが何も変更しなくなるので、例えば入力文字の限定等に使えます。Geckoのエディタのpublicなメソッドを整理する必要があったのは、この「一度だけ」発火する、という点にありました。私の当初の目論見では、この巨大な変更さえ行えばなんとか形にはなるんじゃないかと思っていました。ところが、現実は、Geckoは唯一beforeinputイベントを実装できていないブラウザエンジンで、つまり、最後に実装するブラウザエンジンであるにも関わらず、仕様がかつ、ブラウザ間の互換性維持のためのWPTに自動テストがほぼゼロという信じられない状況でした。

Document.execCommandでは発火するべきではないイベントで、なおかつユーザ入力をWPT上でエミュレートするTestDriverがようやく使えるようになってきている時期だったので、まあ、後者が無いのはまだ分かりますが、とにかく前者がひどい。Googleの開発者もAppleの開発者も全然ブラウザ間の互換性に興味がなく、かつ、丁寧な実装をするつもりが無かったことが明白です。

Google Chrome/Chromiumのバグで例を挙げると、特定の入力パスではbeforeinputイベントが発火されなかったり(これは私のpublicメソッドの整理等を行わず、発火用のコードを差し込んでいった実装であることが推測されます)、InputEvent.dataが適切にセットされていなかったり(これは、WPTだけではなく、Chromiumのツリーにも自動テストが無いことを示唆します)。さらには、beforeinputイベントが存在するのかどうなのかを判定するために必要なGlobalEventHandler.onbeforeinputが実装されていないためにGeckoが安全にbeforeinputイベントをshipしにくいことが当時からMozilla内での懸念事項となったり、またはshipしてもUA名で判定されているWebアプリではいつまでもGeckoだけ(下手すればバグ持ちだったり、機能制限があったりする)専用のパスで処理されてしまうというひどい状況を生んでくれていました。

また、beforeinputイベントのgetTargetRanges()の戻り値にも苦しめられます。仕様書の定義では、

InputEvent.getTargetRanges(): returns an arrays of StaticRanges which will be affected by the change to the DOM if it is not canceled.

とあり、驚くことにこれが全文です。実装者から見ればこれは何も定義されていないのと同義です。でも何故かBlinkやWebKitの開発者の人達はこれだけで実装してしまったのです。

そこで先行するBlinkとWebKitの動作を確認してみると、やはり互換性が無かったり、実際に変更がある範囲とは異なる場合がかなり多く見受けられました。とりあえず色々と割りきって、これは削除する時の範囲がSelectionと異なる場合にだけ有用だろうという判断で、そこだけを中心にテストを書いてみました(これだけでも結構な日数がかかりました)。そのテスト結果は現在でも芳しくありません(期待される結果を概ねBlinkの動作としており、また、あるべきDOMツリーの形もBlinkの動作にあわせているものが多く、Geckoのスコアはまだ低いままです。順次このスコアを上げていくことでBlinkとの互換性が改善していくという準備のためにあえこうしています)。

これらの問題をある程度のところまで解決していくのにとにかく時間がかかるので、またしてもbeforeinputイベントの実装完了が遠のいたのです(いったい、一部のWeb開発者の方の早くGeckoでもbeforeinputを実装してくれという要望の、そのゴール、つまりどんな実装を要求しているのか疑問だらけになってきました)。

ちなみに、Input Eventsの仕様はLevel 1Level 2に別れており、Web開発者が欲しい機能はおそらくLevel 2(Level 1ではIMEからの入力は一切preventDefault()でキャンセルできない)であるにもかかわらず、Level 2のinputイベントの発火タイミングは後方互換性がなく、とても受け入れられるものではありません。この問題は残念ながら現在でも解決していません。

続く……

関連するかもしれないエントリ

関連するかもしれないエントリを発見できませんでしたが、無いとは限りません。