ククログ

株式会社クリアコード > ククログ > 公開のOSS開発プロジェクトの業務での開発事例:Waterfoxのツリー型タブと垂直タブの統合

公開のOSS開発プロジェクトの業務での開発事例:Waterfoxのツリー型タブと垂直タブの統合

結城です。

昨年、Firefoxのフォーク版の一つとして知られるWaterfoxプロジェクト主催のAlex氏からのご依頼に基づき、Firefox用アドオン「ツリー型タブ(Tree Style Tab、以下TST)」を組み込む作業を行いました本年8月にリリースされたWaterfox 6.6.0ではその発展として、Watarfox本体の垂直タブとの統合作業を行いました。

(スクリーンショット:Waterfox 6.6.xでタブのツリー表示を有効化した様子)

本記事では、今回の契約の経緯と開発の成果の技術的側面のそれぞれをご紹介します。

初期の交渉

今回の案件は、Waterfoxの新バージョンで「タブのツリー表示」機能をより自然な形で統合したい、というご相談を頂いた所から始まりました。

前回の開発で残された課題

過去記事で詳しく述べていますが、ブラウザーのタブをツリー表示させる方法には以下の3通りがあります。

  • ブラウザー本体のタブの表示の仕方を制御して、ツリー風に表示する(以下、ネイティブ実装
  • ブラウザー本体のタブとは別に、ツリー表示形式のタブ管理UIをアドオンで提供する(以下、アドオン実装
  • ブラウザー本体のタブとは別に、ツリー表示形式のタブ管理UIをネイティブのサイドバーで提供する(以下、ネイティブサイドバー実装

前回の開発では、Firefoxの次期ESRへの追従を容易にする必要性1と開発コストの削減という2つの理由から、既存のFirefox用アドオンであるTSTを使ったアドオン実装を採用しました。 その際には、アドオン実装であるが故の様々な制約を乗り越えるためにExperiments2 APIを使用し、UIを通常とは別の専用サイドバーで表示するようにしました。

しかし、実際に機能が搭載されたバージョンのWaterfoxを使用したユーザーからは、消費メモリー量の多さの問題3の指摘が上がるなど、アドオン実装方式であるが故のデメリットが予想以上に大きかった様子が窺えました。 このことで、さらなるユーザー体験向上のためにはネイティブ実装またはネイティブサイドバー実装に切り替える必要がある、という課題が浮き彫りとなっていました。

実装方式の変更の提案

今回の開発対象となるWaterfoxはFirefox ESR140ベースです。 ブラウザー本体に含まれている垂直タブ機能を基点にすれば、現実的な工数の範囲でネイティブ実装でのツリー表示対応も実現が可能そうです。 また、前述した通りネイティブ実装化はユーザー体験の向上にも繋がります。 よって、今回はネイティブ実装への移行を含む内容で見積もりを作成し、Alex氏にご提示しました。

ですが、この見積もりは総費用が先方の予算規模を超えていたことから、残念ながら却下となりました。

このような場合には「作業項目を減らして予算規模に合わせた見積もりに修正する」のが常ですが、この時の見積もり内容では

  • Waterfox本体に本格的な変更を行うため、Waterfox本体側の開発フローに合わせた開発体制を整える必要がある。
  • タブ同士の関係をツリーとして保持するなど、ツリー管理のための処理をWaterfox本体の上に実装し直す必要がある。 (WebExtensions APIに基づくアドオンの実装をそのまま流用はできない。)

という必須の作業の部分の工数が大きかったため、細かな調整で見積額を大きく下げることは不可能でした。 そこで、方針を大きく転換し、現在のWaterfoxにおけるアドオン実装の改修で可能な範囲で改善を図る方向で、改めて認識のすり合わせを行いました。

工数削減を優先した計画への見直し

改めて整理した所、先方にとって今回解決したい課題は以下の2点だと分かりました。

  • ツリーUIを、ブラウザー本体の垂直タブと同じ位置に(垂直タブと入れ替わる形で)表示したい。
  • ツリーUIを使用しないときはアドオン部分を完全にアンロードして、CPUやメモリーの消費を抑えたい。

これらを満たすためにもWaterfox本体の改修は不可欠ですが、ネイティブ実装への切り替えに比べると、必要な改修の規模はずっと小さく済みそうでした。

前回開発時には、こちら側にWaterfox本体の開発に関わる知見が不足していたこともあり、Experiments APIを駆使して実装をすべてアドオン部分内に収めていました。 しかし、1点目を実現するためのブラウザー本体へのより積極的な介入は、Experiments APIだけで行うのは困難です4。 また、2点目を実現するためには、Experiments APIで行ってきていた制御をWatefox本体側に移さなくてはなりません5

元の見積もりのための調査6で得た知見により、Waterfox本体の開発に関われる状態になっていたことから、Experiments APIとして実装していた部分をWaterfox本体へ統合する作業については、かなり高い精度で工数を見積もることができました。 そこで、先述の課題の解決のみにフォーカスした新たな見積もりを先方に提示したところ、今度は無事に了承を頂くことができました。

実装・改修のポイント

ここからは、実際に行った作業の技術的側面についてご紹介します。

TST最新版への追従

Firefox用アドオンのTST自体は、前回のWaterfoxへの組み込み以後も開発が継続しており、この時点ですでに最新のFirefox 140開発版にも対応済みでした。 よって、まずはWaterfoxに組み込まれているTST由来の部分のコードを、最新のTSTのコードで上書きして一気に更新しました7

タブ内プレビューの廃止

先方のご要望に基づいて前回実装したタブ内へのプレビュー埋め込み機能でしたが、状況の変化により機能の必要性が薄れていました8。 そこで、先方と相談して機能の廃止を正式に決定し、実装を削除しました。

Experiments API実装の縮小とネイティブ実装への部分移行

前回の開発ではExperiments APIの機能を用いて、動的に関数を置換するなどの従来のXULアドオンと同様の手法、つまり「動的パッチ」とでも呼ぶべき手法で、Waterfox本体の動作を変更していました。 しかしこの手法は、ベースとなったFirefoxのバージョンに強く依存するのが欠点で、Firefox ESR140ベースに更新されたWaterfox開発版では動作しなくなった部分が生じていました。

今回の改修では、それらの「動的パッチ」について、適用先メソッドの変更履歴を見て、意図していた結果をFirefox ESR140ベースで実現する方法を調べ、適用先メソッドそのものを変更する(Waterfoxのコードベースに対して変更のプルリクエストを作成する)ようにしました。 詳細は後述しますが、この作業により「ツリーUIのON/OFFを切り替える処理」がアドオン部分からWaterfox本体側に移ったため、機能を使用しないときはアドオン部分を完全にアンロードできるようになりました。

なお、この作業の結果を確認するためには、Waterfox本体のビルドが必要となります。 今回はビルド手順の案内に従い、Windows 11上のWSL2のUbuntuでWindows用のバイナリをクロスビルドして、ホストのWindows 11上で動作テストを行いました。

ツリーUIとネイティブの垂直タブとの、より自然な統合

今回、外観上最も目立つ改修となったのが、ツリーUIの埋め込み位置の変更です。 どのような改修が必要だったかを説明するために、ここまでの経緯を改めてまとめます。

公開のFirefox用アドオンであるTSTは、ツリーUIを常時表示するために、WebExtensions APIのサイドバー機能を使っています。 このAPIによるサイドバーパネルは、Firefoxのメインウィンドウ内のコンテンツ領域横に置かれた「サイドバー専用のiframe」に読み込まれますが、これは「ブックマーク」「履歴」などの他のサイドバーパネルとの選択式のため、ツリーUIをそれらと同時表示・併用できないという制約があります。

(スクリーンショット:切り替え式サイドバーが排他的である様子のスクリーンショット)

前回の開発ではExperiments APIを用いて、「サイドバー専用のiframe」と「コンテンツ領域」の間に「ツリーUI専用のiframe」を埋め込み、そこにツリーUIを表示するようにしました。 また、ツリーUI表示時にはブラウザー自体のタブバーを非表示化することにより9、ツリーUIを自然にタブの代わりに使えるようにしました。

(スクリーンショット:ツリーUIとサイドバー併用時のスクリーンショット。ウィンドウ上部のタブバーも非表示となっている。)

以上がFirefox ESR128ベースのWaterfoxでのツリーUIでしたが、Firefox ESR140ベースとなったWaterfoxでは、ここにブラウザー自体の「新型サイドバー」と「垂直タブバー」という2つの要素が加わった結果、状況が複雑化しました。

これまでにあった「ツリーUIのON/OFF」「ブラウザー本体のタブバーの表示/非表示」に、新たに「新型サイドバーのON/OFF」「垂直タブバーのON/OFF」という設定が加わったことで、それぞれの状態の組み合わせは12通り10が存在することになります。 このすべてのパターンで適切に動作するよう調整するのはあまりにコストが大きすぎるので、組み合わせを整理して、今回の改修では以下の4パターンのみを許容する11ようにしました。

  • 水平タブバー使用時A(新型サイドバーOFF、垂直タブバーOFF、タブバー表示、ツリーUI OFF)
  • 水平タブバー使用時B(新型サイドバーON、垂直タブバーOFF、タブバー表示、ツリーUI OFF)
  • 垂直タブバー使用時(新型サイドバーON、垂直タブバーON、タブバー表示、ツリーUI OFF)
  • ツリーUI使用時(新型サイドバーON、垂直タブバーON、タブバー非表示、ツリーUI ON)

その上で、各場面で以下のように動作するよう改修を行いました。

  • ツリーUIのON/OFFと同期してアドオン部分の有効・無効を切り替えるようにしました。
    • アドオン部分を完全にアンロードすることで、ツリーUIを使っていないときのCPU使用率やメモリーの消費量を大幅に低減できました。
    • TSTはタブ同士の親子関係をWebExtensions APIのtabs.Tab.openerTabIdによる参照関係で保持する設計のため、アドオン部分を再度有効化した後も、タブのツリー構造は維持され続ける結果となります。
  • ツリーUI専用のiframeを、新型サイドバー内の垂直タブバーと同じ位置に置くようにして、このiframeと垂直タブバーの表示状態をそれぞれ排他的に制御するようにしました。 (スクリーンショット:新しいiframeの挿入位置を示した図)
    • ツリーUI有効時でも、垂直タブバーが見えなくなっているだけで、ブラウザー自身は垂直タブバーモードで動作しているため、垂直タブ時の「カーソルを合わせた時にサイドバーを展開する」「タブとサイドバーを隠す」などの動作はそのまま反映されます。

まとめ

以上、業務として行ったWaterfoxのツリーUIの改修の概要をご紹介しました。

株式会社クリアコードは、公開のオープンソース開発プロジェクトに対する機能追加や改修なども、業務として承っています。 人的リソースの集中投入が必要になる機能追加や大規模改修などで開発リソースの不足にお悩みのプロジェクトオーナーさまや、事業で必要なオープンソース開発プロジェクトとの関わり方でお悩みの企業の開発担当者さまは、是非ともお問い合わせフォームよりお問い合わせ下さい。

  1. この時の開発対象のWaterfoxがFirefox ESR128をベースとしており、そこでネイティブ実装を作り込むと、将来的にFirefox側で既に実装が始まっていた本体内蔵の垂直タブ機能と競合する恐れがありました。

  2. 仕様検討段階の新しいWebExtensions APIを検証するなどの目的で、独自のWebExtensions APIを実装する技術。Firefox 57以前のXULアドオンと同等の高い自由度を得られる代償として、動作対象とするFirefoxのバージョンへの依存度が高くなるという欠点があります。

  3. 具体的には、タブ内へのプレビュー画像の埋め込みに起因して消費メモリー量が増大していました。Firefoxはタブのプレビュー画像をプロファイル内に保存していますが、アドオンからはそれらの画像を参照できないため、Base64エンコードした文字列として画像データを保持する必要があります。そのためタブの数が多いと、多数の巨大な文字列がメモリーを圧迫することになります。

  4. ブラウザー本体の動作の各所により細かく介入する必要があり、Experiments APIの範囲内だけで実現すると、コードが複雑化しすぎる懸念がありました。

  5. この時点では「ツリーUIに切り替えるボタン」もExperiments APIで提供していたため、アドオン部分を完全にアンロードすると、そもそもツリーUIへの切り替えができなくなってしまう状況でした。

  6. この調査は契約締結前に行っていますが、開発に必要な工数ということで、先方の了解を頂いて最終的な見積もりに計上しており、タダ働きにはならないようにしています。

  7. 前回の開発作業において「公開のアドオンとして開発する部分」と「Waterfox固有の部分として追加する部分」とを分けて実装しており、前者の更新は単純なファイルの上書きで済ませられるようになっています。

  8. 今回の開発対象のWaterfoxはFiefox ESR140を元にしたバージョンで、タブ上でのプレビュー表示機能は初期状態で有効化されていました。タブの数が非常に多いときの消費メモリー量の増大というデメリットを鑑みると、独自にプレビューをタブ内に埋め込む利点は小さくなっていました。

  9. 設定で表示/非表示を切り替え可能。

  10. 真偽型の設定4つの組み合わせは最大で2の4乗の16通りがありますが、「垂直タブバーON」時には必ず「新型サイドバーON」となる(「垂直タブバーON」且つ「新型サイドバーOFF」の状態はあり得ない)ため、4通りを引いて12通りとなっています。

  11. これ以外のパターンに設定しようとした場合は、4パターンのいずれかに自動調整するようにしています。例えば、ツリーUI使用時に新型サイドバーをOFFにした場合は、自動的にツリーUIがOFFになり水平タブに切り替わる、といった要領です。