Geckoのエディタのリファクタリング
初回投稿日時: 2021年09月09日21時46分39秒
最終更新日時: 2021年09月23日08時50分13秒
カテゴリ: Editor Firefox
固定リンク: id=2021090900
SNS:
Tweet (list)
なんとなく気まぐれで久しぶりに書いてみようかなと。
今はGeckoのeditor moduleのオーナーとしてゴリゴリとやっていますが、振り返るとエディタをどうこうしないと、みたいな感じでオーナーになったわけではなく、当時のマネージャに「IME周りのハンドリングをもっと向上するには最終的なアウトプットであるエディタの理解も必要」とか、「エディタはこの10年ぐらい(当時)、誰も積極的にメンテナンスしてないので他の場所のバグに重点を置くけど面倒見る人が必要」みたいにだまして説得して就任した記憶があります。
最初に着手したのはたぶん、主要クラスのリネーム。それまでのグローバルなnamespaceにns
というprefixでクラスを置いておくのが、当時、既に他のコンポーネント(例えばDOM)が既にmozilla::dom
というnamespaceに移行していたりで、放置しておくとヘッダファイルの記述が面倒だな、という後ろ向きなモチベーションから入っていった気がします。まあ、実際に修正してスッキリはしたんですが。
次に取り組んだのは脱XPCOM。Geckoのエディタは当時、mozilla::EditorBase
(旧名:nsEditor
)、mozilla::TextEditor
(旧名:nsTextEditor
、<input>
、<textarea>
用のエディタ)、mozilla::HTMLEditor
(旧名:nsHTMLEditor
、designMode
やcontenteditable
用のエディタ)を、最初にnsIEditor
インターフェースを実装するエディタとしてEditorBase
を得、その上でさらに目的に合致するものとしてnsIPlaintextEditor
かnsIHTMLEditor
のインターフェースを持つ、TextEditor
やHTMLEditor
を得てメソッドを呼び出したりしていました。COM周りをやったことある人なら分かると思いますが、デザイン的には綺麗なものの、とにかくQIと、その仮想クラスで定義されているvirtual
メソッドの呼び出しが遅いというのがMozilla内でも当時問題になっていました。前者は64bitを超える容量の比較が連続するので当然ですし、後者はもうhot pathでは無視できないコストだというのがC++を書かれている方にはうなずいて頂けるかと。なのでこれらを解消するために各エディタユーザにはconcreate classに直接アクセスするようにしたり、各エディタが複数のルールで動作できるように作られていたediting rulesという概念を削除して、とにかく基本的に安全かつシンプルな構成にしていきました。
そんな感じでリファクタリングを楽しんでいる時に舞い込んできたのがbeforeinput
イベントの案件でした。それ以前から懸案としては上がっていたのですが、どうにかしないといけない、ということで実装を始めると予想通りその道のりは長く、想像以上のものになりました(少なくとも最初に問いかけられてから実際にshipするまで5年弱かかっています)。
まずbeforeinput
イベントの実装にあたって問題だったのは、エディタの各クラスが内部からpublic
なメソッドを呼び出しているため、一回のユーザのオペレーションや、JSからのAPIの呼び出しがエディタモジュール内ではハッキリしないということでした。そこで、public
なメソッドを制限しこれらをAction
と(勝手に)命名し、そこから呼び出されていたpublic
メソッドで行われていたことをSubAction
と(やはり勝手に)命名し、どこから始まって、どこで終わるのかを明確にする作業を複数のbugで行い、さらに、各public
メソッドでスタック上に一時情報を保存するようにし、管理の簡略化や省メモリ化を実現しました。
これらにより、beforeinput
イベントの実装への下準備が全て整うと思っていました。でも、そうではなかったのが現実の厳しさでした。