ペルソナの技術詳解

ペルソナを使用している方は結構いるかと思います。
今日はそのペルソナの技術的な話をしたいと思います。

ペルソナ設定データ

ペルソナの設定データはabout:configなどから見られる、lightweightThemes.usedThemesが主な設定データとなっています。これは以下のようなプロパティを持つJSON形式の配列となっています。

[
  {
    id: "ペルソナのID番号(必須)",
    name: "テーマの名前(必須)",
    author: "作者の名前",
    accentcolor: "背景色",
    textcolor: "テキスト色",
    headerURL: "ツールバーの背景画像URL(必須)",
    footerURL: "ステータスバーの背景画像URL",
    previewURL: "アドオンの管理画面から見られるテーマの画像URL",
    iconURL: "アドンの管理画面から見られるテーマのアイコン画像URL",
    updateURL: "JSON形式でアップデート情報を出力するURL"
  },
  {
    //...
  }
]

強調部分のプロパティは必須です。また、~URLhttpから始まる文字列である必要があります(そうでないと通常の方法では反映されない)。

ペルソナの有効化

ペルソナを有効にすると以下のようなことが起こります。

  • window要素の lwtheme 属性が true になります
  • window要素の lwthemetextcolor 属性が bright または dark になります
    • textcolor が影響しており、このRGB値から輝度を計算し、明るいなら bright、暗いなら darkとなります
    • また、bright なら :root:-moz-lwtheme-brighttext というCSSセレクタが有効になり、ツールバーなどのラベルに黒のシャドウが付きます。dark なら :root:-moz-lwtheme-darktext セレクタが有効になり、白のシャドウが付きます
  • window要素の style 属性が設定されます
    • colorプロパティにtextcolor(値がない場合は”black”)
    • background-colorプロパティにaccentcolor(値がない場合は”white”)
    • background-imageプロパティにheaderURL
  • window要素の drawintitlebar 属性に true が設定される(MacOS Xのみ)
  • statusbar要素の style 属性が設定されます
    • colorプロパティにtextcolor(値がない場合は”black”)
    • background-colorプロパティにaccentcolor(値がない場合は”white”)
    • background-imageプロパティにfooterURL
  • 各要素のCSSの以下の擬似要素が有効になる
    • :-moz-lwtheme
    • :-moz-lwtheme-brighttextまたは:-moz-lwtheme-darktext
      (window要素の lwthemetextcolor 属性値に左右される)

また、同時にheaderURLとfooterURLの画像がプロファイルディレクトリ下の lightweighttheme-headerlightweightthtme-footer にダウンロードされます。これは、ペルソナが有効な状態でFirefoxを再起動したときに使われる画像となります。

JavaScriptモジュール

ペルソナで使用するJavaScriptモジュールには以下の2つがあります。

  1. LightweightThemeConsumer.jsm
  2. LightweightThemeManager.jsm

これらは Firefoxインストールディレクトリ/modules/ ディレクトリ内にありますので、ソースを読みたい方はどうぞ。

LightweightThemeManager.jsm

“Manager”と付いている通り管理を担当するモジュールです。

  • ペルソナデータの取得
  • ペルソナデータの削除
  • ペルソナデータの追加と変更通知
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");

などとインポートして使用します。

データ取得

var themes = LightweightThemeManager.usedThemes

usedThemes プロパティはペルソナ設定データで挙げた lightweightThemes.usedThemes を取得して JSON.parse した値を返すゲッタとして定義されています。返ってくる値はオブジェクトの配列です。

データのIDがわかっている場合は

var theme = LightweightThemeManager.getUsedTheme(aId);

からも取得可能です。

現在使われているデータは

var currentTheme = LightweightThemeManager.currentTheme

var currentTheme = LightweightThemeManager.currentThemeForDisplay

から取得可能です。
currentThemeForDisplay の方は、headerURL,footerURL に限り、ローカルファイルへのパスに変換されたデータとなります。

データ削除

LightweightThemeManager.forgetUsedTheme(aId);

データ追加と変更通知

LightweightThemeManager.currentTheme = aThemeData;

aThemeDataペルソナ設定データのプロパティを持つ必要があります。
データの取得にも出てきた currentTheme を使用します。
これはセッタとして定義されていて、データの追加や順番の入れ替えてPrefernecesへの反映は行いますが、実際の画像などの反映は行わずに通知を行います(理由は後述)。

LightweightThemeConsumer.jsm

実は LightweightThemeManager.jsm 側では実際のデータから画像やテキスト色の変更は行っておらず、こちらのモジュールが受け持っています。

何故なら、”Manager”側でそれをやろうとすると、Firefoxのウィンドウが複数あった場合にそれぞれに変更をかけるのは面倒だからです。
“Consumer”モジュールは意識せずとも内部で自動的にインポートされており、各ウィンドウで動作するようになってして、変更通知と共にデータを受け取って実質的な変更を行う仕組みとなってします。

LightweightThemeManager.jsmはドキュメントルートにXBLでバインドされるmozilla-central mozilla/toolkit/content/widgets/general.xmlで使用されています。よってこのモジュールは新たにインポートする必要はありません。

そして、lightweight-theme-changedというTopic名の通知を監視して、この通知と共にDataにくる値を画像やテキスト色などペルソナの有効化で書いた内容の変更がなされます。

Webサイトからの配布の仕組み

http://www.getpersonas.com/から実際にプレビューやインストールできますが、その仕組を解説しましょう。

ペルソナは DOM Event を発行することでプレビューやインストールがされます。
DOM Eventには以下の3つのイベントがあります。

  • InstallBrowserTheme
  • PreviewBrowserTheme
  • ResetBrowserThemePreview

これらのイベントを特定の属性を持った要素から dispatchEvent してあげます。

特定の属性とは、data-browsertheme という属性名で、属性値にはペルソナ設定データのJSONコードが入っている属性です。以下のような感じです。

<img src="preview.png"
     data-browsertheme='{"id":"1000","name":"sample","headerURL":"http://example.com/header.png"}' />

実際にはHTMLに直接埋め込むことはせず、JavaScriptで属性を付加することになるでしょう。

var theme = {
  id: "1000",
  name: "sample",
  headerURL: "http://example.com/header.png"
};
var themeElem;
function init(){
  themeElem = document.getElementById("theme");
  themeElem.setAttribute("data-browsertheme", JSON.stringify(theme));
}
window.addEventListener("load", init, false);

コード全容は、Lightweight themes – MDCにコードのサンプルがありますので、ご参考に。
私自身もhttp://www.paw.hi-ho.ne.jp/makochi/personas/に実験的に作ってみたサンプルがあります(これはzenper :: Add-ons for Firefoxなどのアドオンを入れている場合用です)。

また、Firefox側でのイベントリスナのコードはmozilla-central identifier search “LightWeightThemeWebInstaller”を見ると良いでしょう。

3 件のコメント

  1. mooz :

    大変参考になる記事を書いていただき, ありがとうございます.
    一つ, 以前から気になっていたことがあったのでご質問させていただきます.

    ギャラリーの Persona には, テキストにシャドウを設定するものと, 無いものがあるように見受けられます.

    テキストのシャドウを設定する項目があるのかと window.LightWeightThemeWebInstaller._manager.currentTheme 辺りを覗いてみたのですが, そういったものを見つけることは出来ませんでした.

    この辺りの設定がどのようにして行われているのか, もしご存知でしたら教えていただければと思います.

  2. hatena.ne.jp/teramako/ :

    >>moozさん
    Firefoxルートwindowに適応されるCSSセレクタに
    :root:-moz-lwtheme-brighttext または :root:-moz-lwtheme-darktext があります(lwthemetextcolor 属性の値によって変化)
    このセレクタが text-shadow プロパティを設定しています。
    メニューなどのラベルにシャドウが出るのはこのプロパティがカスケードして適応されているからです。逆に出ないものは text-shadow: none などで打ち消しているからでしょう。

  3. mooz :

    ご説明ありがとうございます. 謎が解けました.

    「影が付いていないものがある」と先ほど書きましたが, これは自分の勘違いだったようで, 背景色と影の色が同じために, あたかも影が付いていないように見えていただけのようです. お騒がせしました.

    text-shadow が少々大げさ過ぎかなとも思うので, これらを無効にする手段が (userChrome.css や Stylish 抜きで) 出てくると良いなと思っています.