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

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

もずはっく日記(2018年12月)

2018年12月7日

Bug-org 1465702 EditorBase, TextEditor and HTMLEditor should use a stack class to store all information which are necessary to handle each EditAction like TextEditRules and HTMLEditRules
初回投稿日時: 2018年12月07日00時12分26秒
最終更新日時: 2018年12月12日00時03分17秒
カテゴリ: Editor Events Mozilla Core Mozilla65 バグ修正
SNS: (list)

InputEvent.inputTypebeforeinputイベントの実装時に非常に重要なので、これ(とbeforeinput)を実装するための準備として、Geckoのエディタを大きく書き換えていました。これをブロックしているバグを見ると、なんと5月ぐらいに取りかかってるようなので、実に半年間もやっていたわけです。

Geckoのエディタのコンクリートクラスは、TextEditorHTMLEditorという名前通りのふたつのクラスがあります。前者は当然、<input>要素や、<textarea>要素、後者は、document.designModecontenteditable属性の指定された要素があるドキュメントでそれぞれインスタンス化されています。これらのエディタは、確実にinputイベントを何らかの編集後に発火させるために編集が見込まれるメソッドの各所にスタック上にインスタンス化されるクラスを設置し、それの最後のインスタンスが破棄される際にinputイベントが発火されるようにしています。この設計は普段のメンテナンス性を高める点では優秀ですが、InputEvent.inputTypeの実装を行う今回のように、編集内容をイベント発火時に知ることが困難です(複数の編集がネストすることがあり、それぞれに対して別のinputイベントを発火する必要があるため、なおさらです)。

そこで私が考えたアプローチは、これらの基底クラスも含め、ユーザの入力で編集が始まったとき、もしくは、Webアプリがエディタを通して何らかの編集を開始した時に、スタックに新しいクラスをインスタンス化し、その中にユーザ、もしくはWebアプリが行おうとした編集内容を記録しておき、inputイベントの発火時にはその情報を参照しようというものです。そうすれば、どんなに複雑な編集が行われたとしても、編集内容を示すInputEvent.inputTypeは確実に、なおかつ、的確に設定できることが保証されます。しかし、これを行うには、エディタ外部からの呼び出し時にのみそのインスタンスを生成するという必要があります。

ここでまず問題になったのが、外部から呼び出されるメソッドがそのままpublicメソッドでは無いという点です。なぜなら、publicメソッドはクラス内部からも呼び出されるためです。もし、Webアプリによって、ユーザの編集中に他の編集がネストできないならこれは問題になりません。しかし、Web標準仕様はそれを許しています。つまり、純粋に外部から呼び出される場合にのみpublicメソッドを使用し、エディタ内部で編集中にはprotected以下のスコープのメソッドを呼び出すようにエディタ全体を書き変えるしかありません。

ところがここで問題になったのはこれら全てのクラスのpublicメソッドの多さです。具体的には、これらのクラスはnsIEditornsIPlaintextEditornsIHTMLEditornsIEditorMailSupportnsIEditorStyleSheetsnsIHTMLAbsPosEditornsIHTMLInlineTableEditornsIHTMLObjectResizernsITableEditorといった多くのインターフェースを実装し、さらにQuantum Flowプロジェクトで高速化のために削除した、もしくは複製されたpublicメソッドを多々もつクラスです。

この絶望的な物量を前にしても、内部からも呼び出されるpublicメソッドはprotectedメソッドとして実装し、publicメソッドは外部からの呼び出し時にも用い、対応するprotectedメソッドを呼ぶだけにしていくしかありませんでした。より、C++として安全な実装(ビルド時に内部からpublicメソッドが呼ばれないようにする)があるかもしれませんが、ひとまず、こういった形で半年かけて大きく書き換えたのがこのバグ修正となっています。

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

bug-org 1465702を含むエントリ