← 他の記事もよんでみる
Available languages:
日本語English

BCCC #3 -- Animation.overallProgressをFirefoxに実装したヨ

目次

"BCCC"は"Browser Contribution/Crash Club"の略です👶

さいきんFirefox 142にAnimation.overallProgressをshipしました!(intent to ship: https://groups.google.com/a/mozilla.org/g/dev-platform/c/_vMp7q8N0HE)

完全に新規のAPIを実装したのは初めてだったので嬉しいです。ということで、色々わかったことを軽くメモしておいてみます。

(いちおう)Web Animationsの説明

Animationっていうインターフェースがあるの?」という人のためにAnimationについて少しだけ紹介すると、まずW3Cが作っているWeb Animationsという仕様があります。
この仕様はCSSやSVGといったアニメーション機構を統一的に扱える抽象的なモデルを作ろうというモチベーションから始まったものです。

CSS Transitions [CSS-TRANSITIONS-1], CSS Animations [CSS-ANIMATIONS-1], and SVG [SVG11] all provide mechanisms that generate animated content on a Web page. Although the three specifications provide many similar features, they are described in different terms. This specification proposes an abstract animation model that encompasses the common features of all three specifications. This Web Animations model is backwards-compatible with the current behavior of these specifications such that they can be defined in terms of this model without any observable change.
https://drafts.csswg.org/web-animations-1/#relationship-to-other-specifications

Web AnimationsにおいてアニメーションはTiming ModelとAnimation Modelから成ります。簡単に言うならTiming Modelの要点は時刻をアニメーションの進行度合いに変換することであり、Animation Modelの要点は進行度合いを受け取って具体的なeffect value(CSSプロパティの値など)を吐き出すことです。

At the core of the Web Animations timing model is the process that takes a local time value and converts it to an iteration progress.
https://drafts.csswg.org/web-animations-1/#animation-effect-calculations-overview

For some kinds of animation effects, the Web Animations animation model takes the iteration progress and iteration index values produced by the timing model and uses them to calculate a corresponding output.
https://drafts.csswg.org/web-animations-1/#animation-model

アニメーションを抽象的なモデルに落とし込むだけでなく、JSでアニメーションを操作するAPIも提供してくれています。ちなみに最初の計画ではAPIまで作るつもりがなかったという話を聞いたことがありますが、本当かはよく知りません。

仕様がリリースされたのは2013年で、いろいろな記事も書かれています。ここではひとまずspec editorであるBrianさんの記事を掲載しておきます。アニメーションでできることとその実装の大変さに関するプレゼンテーションも面白いので、興味がある方は見てみてください!

https://birtles.blog/2013/06/26/introducing-web-animations/

https://www.youtube.com/watch?v=QybMNLFoK5s

Web AnimationsのAPIはElement.animateAnimation.commitStylesなどいくつかありますが、コードを書くなら例えばこんな感じになります👶コンソールで実行してみるとページ末尾に黒い四角形が現れて回ります。JSだけでアニメーションが完結するのはすごく面白くて、場合によっては非常に便利です :)

const div = document.createElement("div");
div.style = `
  height: 100px;
  width:100px;
  background-color:black;
  color:white;
`;
document.body.appendChild(div);
const anim = div.animate(
  [{ transform: "rotate(0)" }, { transform: "rotate(360deg)" }],
  {
    duration: 10000,
    iterations: 1,
  },
);
if ("overallProgress" in Animation.prototype) {
  setInterval(() => {
    div.innerText = `${Math.round(anim.overallProgress * 1000) / 10}%`;
  }, 100);
}

白い字で30.6%と書かれた黒い四角が傾いて表示されている
黒い四角がゆっくりまわります。overallProgressが動く環境なら度合いが表示されます

上のコードには、今回実装したoverallProgressもさりげなく入れてみました。overallProgressはBlinkかGecko(preview)なら動きますが、それ以外だとおそらく動かない方のパスを通るはずです。ただしWebKitのpreviewなら動くかもしれません。
overallProgressはその名の通り、アニメーションの進行度を返してくれます。ちなみに実はもともとprogressという名前でしたが、他とちょっと名前が被っていたこともあり変わりました。興味がある人は下記のコメントからの議論を見てみてください👀

https://github.com/w3c/csswg-drafts/issues/8799#issuecomment-2444800871

実装してみてどうだったか?

WebIDLが便利

overallProgressを実装するにあたり、とりあえずアニメーション系のAPIが集まっている場所(dom/animation/Animation.cpp)インターフェースを書くかぁと思いました。

ただ、ここでちょっと冷静になります。JSエンジンにも手を入れないといけないのか?とか。そこでWebIDLの存在を思い出します。Firefoxのドキュメントを見てみましょう。

https://firefox-source-docs.mozilla.org/dom/webIdlBindings/index.html

https://firefox-source-docs.mozilla.org/dom/bindings/webidl/index.html

1つめのページの方が具体的な手順が載っていそうに思えますね。今回はAnimationインターフェースへの追加なのでdom/webidl/Animation.webidlというファイルにどうにかしてインターフェースを定義して、Firefoxを普通にビルドすればglueコードが自動生成されるようです!便利。

問題はどうインターフェースを定義するかです。なんだかいろいろ書いてあって難しいですね。ただ、今回は要するにspecのIDLすなわちreadonly attribute double? overallProgress;をコピペすれば終わりです。これはなかなかすごいです。spec段階から練り上げられていることのありがたさが詰まっています。

ちなみにIDLの詳しい説明がなんとMDNにも載っておりメンテされています。今回はあまり読みませんでしたが、やはりMDNはすごいですね。

https://developer.mozilla.org/en-US/docs/MDN/Writing_guidelines/Howto/Write_an_api_reference/Information_contained_in_a_WebIDL_file

実装もspecのおかげでスムーズだった

このAPIの実装の負荷は高くなかったです。
1年前にspecは完成しており、Blinkでは実装済みだったのでWPTケースもすでにありました。specの内容もかなりシンプルな方で、Geckoにすでに実装されている部品を組み合わせるだけで済むタイプの処理でした。

自動更新されるBCDがすごい

新しいAPIを作成したとなると、Browser Compat Dataに更新を入れる必要があります。BCDというのは各ブラウザの機能対応データをまとめている場所で、例えばMDNの下の方にあるブラウザ別対応表の元データになっています。

BCDのデータはきれいに構造化されています。説明はこのあたりにあります。api.mdがAPI対応のデータについての説明ですが、すっきりしているのでこれを読まなくてもデータを見たらなんとなくわかると思います👶比較的短いCSSImageValueのJSONを載せておきます。

{
  "api": {
    "CSSImageValue": {
      "__compat": {
        "mdn_url": "https://developer.mozilla.org/docs/Web/API/CSSImageValue",
        "spec_url": "https://drafts.css-houdini.org/css-typed-om/#imagevalue-objects",
        "tags": [
          "web-features:css-typed-om"
        ],
        "support": {
          "chrome": {
            "version_added": "66"
          },
          "chrome_android": "mirror",
          "edge": "mirror",
          "firefox": {
            "version_added": false,
            "impl_url": "https://bugzil.la/1278697"
          },
          "firefox_android": "mirror",
          "oculus": "mirror",
          "opera": "mirror",
          "opera_android": "mirror",
          "safari": {
            "version_added": "16.4"
          },
          "safari_ios": "mirror",
          "samsunginternet_android": "mirror",
          "webview_android": "mirror",
          "webview_ios": "mirror"
        },
        "status": {
          "experimental": false,
          "standard_track": true,
          "deprecated": false
        }
      }
    }
  }
}

今回BCDを更新したタイミングではoverallProgressがまだNightlyに留まっていたので、version_addedの値はpreviewにします。これによってMDNではNightlyと表示されるわけです。

面白いのはこれが自動更新されるということです。BCDにあるAPIは(すべてではないですが)mdn-bcd-collectorというツールによって自動テストされており、その結果は自動で反映されるのです。最高ですね。

mdn-bcd-collectorについては、公式の概要ページが非常によくまとまっています。

https://mdn-bcd-collector.gooborg.com/docs/about.md

せっかくなのでテストページだけ見てみると、下記がoverallProgressのものです。スマホでもパソコンでも好きなブラウザでアクセスして、ワンプッシュでテストできます。ぜひRun Testsを押してやってみてください👶

https://mdn-bcd-collector.gooborg.com/tests/api/Animation/overallProgress

いつリリースされる?

実装したのでワクワクでリリースを待ちます。Firefoxはリリーストレインを導入しており、スケジュールは誰でもここで見れます。ドメイン名が素直だなといつも思っています。

https://whattrainisitnow.com

自分がoverallProgressをマージしたのは6/24でした。上のページを見るとわかりますが、これはちょうど142のNightly startsとSoft code freezeの間にあたります。ということでバージョン142でのリリースとなります。ちなみにNightlyにはほぼ即日で反映されます!

まとめ

というわけでoveallProgressは明日ベータがリリースされる142からFirefoxでavailableになります👶

実は今回の実装においては、Firefox固有のフィンガープリンティング防止機構(RFP, resistFingerPrinting)に起因するテストバグが一番厄介でした。これについてはひと段落したらまた書きます :)

← 他の記事もよんでみる