Firefox 4 の HTML5 パーサ – インライン SVG、スピード、などなど

この記事は Firefox の新しい HTML5 パーサを開発している Henri Sivonen によるゲスト記事です。HTML パーサはブラウザの中でもとくに複雑で繊細な部品のひとつです。HTML パーサは HTML ソースを Web ページに変換する部分を制御しますが、その部分を変更するのは稀ですから、充分なテストが必要になります。Gecko の開発が始まったのは 1990 年代終わりですが、大部分は再構築されています。しかし、HTML パーサは「オリジナル」なものとして残り続けている部分のひとつです。新しい HTML5 パーサは従来のパーサを置き換え、HTML5 への準拠はもちろん、スピードやその他の新しい機能をもたらします。

Gecko の HTML パーサを置き換えるプロジェクトが始まったのは1998年で、これまでかなり長くの期間行われています。そしてついに先日、新しいパーサが trunk ビルドにおいてデフォルトで有効になりました。つまり、ナイトリービルド をダウンロードするだけで、なにも設定を変更する必要なく新しいパーサを試せるのです。

訳注: Firefox 3.6 にも、バージョンは古いですが HTML5 パーサが搭載されています。設定を変更することでテストが可能です。

新しい HTML5 パーサには、主に4つの改良点があります。

  • SVG と MathML をインラインで HTML5 ページに埋め込めます。XML 名前空間は必要ありません。
  • パース処理は Firefox のメイン UI スレッドの外で行われます。これにより、全体的にブラウザのレスポンスが向上します。
  • 新しいパーサは innerHTML の呼び出しを 20% ほど高速化します。
  • 新しいパーサによって、古いパーサに関係する数多くのバグ が一掃されました。

Firefox Nightly もしくは他の HTML5 対応ブラウザで次の HTML5 デモ をご覧ください。次のように見えるはずです。

図: HTML5 対応ブラウザでは HTML 文書中にインラインで SVG, MathML を記述できる

HTML5 パーサとは

Gecko の HTML5 パーサは、HTML5 の構文解析アルゴリズム に基づき、バイトストリームを DOM ツリーに変換するものです。

HTML5 は HTML の実装者に対し、構文解析処理をを定義する初めての仕様になります。HTML5 より前の HTML 仕様では、バイトストリームを DOM ツリーに変換する処理について触れることはありませんでした。また、HTML5 より前の HTML は理論上、SGML の上に定義されるものでした。ですから、valid な HTML 文書のソースと DOM の関係は暗黙的ですが存在していました。しかし、invalid な文書の構文解析についてはうまく定義されていませんでした (Web 上のコンテンツの多くが、valid な HTML4 ではありません)。また、理論的には SGML の構文も HTML で使えるはずですが、実際に利用できるものはそのうちの一部でした。有名なブラウザーが、すべての SGML 構文を実装しなかったのです。

適切な仕様が存在していなかったことにより、ブラウザ開発者はその隙間を自分たちで埋めることになりました。挙動の互換性を保つため、大きなマーケットシェアを持つブラウザ (Mosaic, Netscape, IE など) をリバースエンジニアリングすることもありました。結果、ドキュメント化されていない共通ルールと、挙動の違いが生まれてしまいました。

HTML5 の構文解析アルゴリズムは、HTML を利用するブラウザやその他のアプリケーションについて、詳細な挙動を標準化するものです。設計上、HTML5 の構文解析アルゴリズムは現在の HTML コンテンツを処理することも可能ですから、アプリケーションは古いコンテンツのために古いパーサをメンテナンスし続ける必要はありません。Gecko の trunk ナイトリービルドにおいて、HTML5 パーサは text/html で送出されたすべてのコンテンツに利用されます。

何が今までと違うのか

HTML5 の構文解析アルゴリズムは字句化 (tokenization) とツリー構築 (tree building) というふたつのパートから構成されます。字句化はソースストリームをタグやテキスト、コメント、要素中の属性などに分割つする処理です。ツリー構築はそれらの情報を受け取り DOM ツリーを構築する処理になります。HTML5 構文解析アルゴリズムの字句化パートは、これまでの Gecko の挙動よりも Internet Explorer に近いものとなっています。Internet Explorer は大きなマーケットェアを持っているので、Web サイトの多くが IE のトークナイザで壊れないようにテストされていたと言えるのです。一方、ツリー構築の部分は WebKit の挙動に近いものとなっています。ですから、HTML5 以前は WebKit が最も妥当なツリー構築手法を提供していたのです。

さらに、HTML5 パーサはネットワークストリームの構文解析をメインスレッド外で行います。これまで、ブラウザはほとんどのタスクをメインスレッドで行ってきました。このメインスレッド外での構文解析という大きな変更は、古い Gecko の HTML パーサよりもメンテナンス性の高い HTML5 パーサのコードベースによって実現できました。

Web 開発者に関係する新機能

これまで話したことは、主にブラウザ開発者の興味をひくものだったでしょう。HTML5 パーサで注目すべき点は、パーサが変更されたことに気づかないところです。

しかし、Web 開発者にとって大きな機能がひとつあります。インライン MathML とインライン SVG です。HTML5 の構文解析によって、MathML と SVG は XML を必要とせず、Web のメインファイルフォーマットである HTML で利用可能になったのです。

つまり、洗練されたタイポグラフィで数式を HTML 文書で表示させたいとき、文書を XHTML に作り直すことや、整形式の XHTML を出力するよう Web サイトを管理するソフトウェアを修正する必要もありません。たとえば、次の二次方程式をそのまま HTML に埋め込むことができます。

x=b±b24⁢a⁢c2⁢a

同様に、XHTML に作り直すことなく、スケーラブルな画像を SVG からインラインで HTML に埋め込むことができます。最近は画面の大きさや解像度が多様になっていますから、画像を様々なズームレベルで鮮明に表示させることが重要になっています。SVG 画像はこれまでも object などから参照させることで HTML 文書中に表示できましたが、SVG をインラインで直接埋め込むことが便利な場合もあるでしょう。たとえば、注意を促すアイコンを外部ファイルから参照するのではなく、インラインで埋め込んでみましょう。

<svg height="86" width="90" viewBox="5 9 90 86" style="float: right;">
  <path stroke="#F53F0C" stroke-width="10" fill="#F5C60C" stroke-linejoin="round" d="M 10,90 L 90,90 L 50,14 Z"/>
  <line stroke="black" stroke-width="10" stroke-linecap=round x1="50" x2="50" y1="45" y2="75" />
</svg>

文書の先頭に <!DOCTYPE html> と記述し、上記のコードを埋め込んでください。新しいナイトリービルドで数式と警告マークが現れるはずです。

基本的に、MathML や SVG の XML ファイルがある場合、それをそのまま HTML ソースに貼りつけるだけで構いません (ただし、XML 宣言や DOCTYPE は取り除いてください)。ただし、注意点が2つあります。ひとつは、コードに名前空間接頭辞をつけることはできません。svg:svgmath:math と書くことはできません。もうひとつは、XLink を利用する場合、その名前空間接頭辞は xlink でなければいけません。

上記の MathML と SVG の例で見られるように、インライン MathML やインライン SVG はより HTML ライクで、XML 中に書いたものよりも煩雑ではありません。名前空間の宣言や属性周りの不必要な引用符が省略されています。しかし、引用符を省略してもタグは XML トークナイザではなく HTML5 トークナイザによって処理されるので、これでも動作するのです。名前空間宣言がなくても問題ありません。HTML5 のツリービルダは MathML や SVG らしい要素について、名前空間宣言を利用しないからです。代わりに、<svg> が現れるとその要素には DOM 上で SVG 名前空間が割り当てられ、同様に <math> にはMathML の名前空間が割り当てられます。また、MathML の例でお分かりかもしれませんが、これまで HTML でサポートされていない名前文字参照が利用されていますね。

Web 制作者むけに、インライン MathML とインライン SVG の構文解析についてまとめてみました。

  • <svg></svg> には DOM 上で SVG の名前空間が割り当てられます。
  • <math></math> には DOM 上で MathML の名前空間が割り当てられます。
  • foreignObjectannotation-xml (あまり重要ではありませんが) はネストした HTML スコープを開始します。ですから、SVG や MathML, HTML をその要素内で利用することが可能です。
  • パーサは大文字と小文字を修正します。ですから <SVG VIEWBOX=’0 0 10 10′> といったソースも HTML 中では動作します。
  • DOM メソッドと CSS セレクタは大文字と小文字を区別します。ですから DOM の呼び出しや CSS セレクタを利用する際は自分で正規化した表記を利用する事になります。SVG ではいくつかの構文が camelCase で定義されているので、たとえば viewBox と書く必要があります。
  • MathML や SVG 要素内で <foo/> という構文が現れた場合、その foo 要素はすぐに閉じられます。これは HTML 要素内の処理とは異なっています。
  • 属性は HTML 要素内と同じように字句化されます。ですから、HTML 要素内と同じ条件で引用符の省略などが行えます (引用符の省略は、値が空ではなく、また空白文字や ", , `, <, =, > を含まないときに可能です)。
  • 注意: 上記の2項目は、古い HTML の字句化と互換性を持たせる点でうまく組み合わせられない場合があります。たとえば、最後に書いた属性の引用符を省略したい場合、タグを閉じるスラッシュの前にはスペースが必要です。つまり、<circle fill=green /> は OK ですが <circle fill=red/> は NG です。
  • xmlns から始まる属性は名前空間の指定に何ら意味を持ちません。ですから、xmlns を利用する必要はありません。
  • XLink 名前空間に属する属性には xlink という接頭辞を利用しなければいけません (例: xlink:href)。
  • 要素名に接頭辞やコロンを含めることはできません。
  • SVG の script 要素の内容は XML で字句化されたように処理されます。HTML の script 要素と同じように処理されるわけではありません。
  • SVG や MathML の要素に開いた <![CDATA[]]> セクションがある場合、その中身は XML と同じように処理されます。これを利用し、text/html 中の SVG や MathML をサポートしない古いブラウザで、テキストが現れないようにすることができます。
  • MathML の名前文字参照は文書中すべてで利用できます (HTML コンテンツ内でももちろん使えます)。
  • (理由は分かりませんが)、SVG の断片を HTML に記述したり、MathML 意外の目的で <math> タグを記述した古いコンテンツに対応するため、HTML 要素を SVG 要素の子要素として (foreignObject なしで) 記述すると、その場で SVG/MathML コンテクストから抜け出してしまいます。これにより、typo によって驚くような挙動に出くわすことがあります。