2012年8月19日日曜日

ESウェブブラウザ通信 - テストハーネスの使い方

今回はESウェブブラウザでのCSS 2.1 Conformance Test Suiteのヘッドレステスト方法について紹介します。

CSS 2.1 Conformance Test Suiteは、CSS 2.1の実装が仕様通りになされているかどうか判断するためのテスト ページを集めたものです。テストスイートには仕様書の編集者が作成したものだけなく、Internet Explorere, Firefox, WebKitなどブラウザ ベンダーから提供したされたものも含まれています。そのテストページ数はhtml4だけでも9,365ページに及びます。

escortウェブ ブラウザでは、このテストスイートを使ってレンダリング エンジンを開発してきました。その内容については21回にわけてこのブログで報告してきました。仕様書の文面だけでは解釈が分かれそうな箇所についても、テストスイートで確認することによって解釈違いを修正できた場面なども少なくありません。以前も紹介したように、IEBlogでJason Uptonさんが、
The only way to know if a browser has correctly implemented a specification is to develop a comprehensive set of tests for the specification.
と述べられている通り、テストスイートなしに仕様書だけを見て各ベンダー間で互換性のあるウェブブラウザを実装することは現実的には不可能かもしれません。

テスト ハーネス


CSSレンダリング エンジンには高速化や新機能の実装といった形で日々修正が加えられています。そういったときに修正に何か問題があると、それまでパスしていたテストページのテストに失敗して表示が崩れたりすることがあります(リグレッションと呼ばれています)。ですので、原則としては何か修正を行ったらテストスイートのすべてのテストページを再確認しておくべき、ということになります。

一方、CSS 2.1 Conformance Test Suiteの個々のテスト ページは基本的には実際にブラウザで表示して目で見て成否を確認するように作られています。しかし何か修正を加えるたびに9,370ページものページをひとつひとつ目視で確認していたのでは実装ペースを上げることができません。そこでいちいち目視せずに自動でテストを行うためのソフトウェア、テストハーネス、を利用することが重要になってきます。

ESウェブブラウザでは、レンダーツリーのテキスト形式のダンプにpass, failといったタグをつけて記録したログファイルと、実際の実行結果を比較して判定するharnessというプログラムを用意しています。以下ではこのharnessの使ったテスト方法について説明していきます。

テスト環境の構築


1) Apache HTTPサーバーのセットアップ


CSS 2.1 Conformance Test SuiteではApache HTTPサーバー用の.htaccessファイルを利用して、特定のキャラクターエンコードでHTTPファイルを送信するといった指定がされている箇所があります。そのためテスト用のHTTPサーバーとしてはApacheを利用するのが簡単です。

harnessは、いまのところテスト用PC上でローカルに起動されているHTTPサーバーにアクセスするようになっています。Fedoraであれば、

$ sudo yum install httpd

でApacheをインストールして、/etc/httpd/conf/httpd.confを開いて、ServerNameを、

ServerName localhost:80

に、<Directory "/var/www/html">の部分のAllowOverrideを、

    AllowOverride All

と変更して、.htaccessを利用できるようにします。あとは、

# systemctl start httpd.service
# systemctl enable httpd.service

のようにすれば、Apacheをいつも起動した状態に設定できます。

2) テストスイートの展開


W3CのサイトからCSS 2.1 Conformance Test Suiteを取得してきます(現在の最新版は20110323.zipです)。これを、/var/www/html/suites/css2.1に展開します。

# cd /var/www/html/suites/css2.1
# wget http://test.csswg.org/suites/css2.1/20110323.zip
# unzip 20110323.zip

3) テスト フォントの展開


CSS 2.1 Conformance Test Suiteを利用すために必要なフォントが、やはりW3Cのサイトから提供されています。これを、/var/www/html/Style/CSS/Test/Fontsに展開します。

# cd /var/www/html/Style/CSS/Test/Fonts
# wget http://www.w3.org/Style/CSS/Test/Fonts/css-testsuite-fonts-v2.zip
# unzip css-testsuite-fonts-v2.zip

今のところ、harnessでテスト中は、ユーザースタイルシート等のサポートファイルに関しては、http経由ではなくて、上記のディレクトリに直接アクセスしています。

これでテストスイートの準備ができました。試しに、http://localhost/suites/css2.1/20110323/ にアクセスしてみてください。下のような画面が表示されれば、正しくセットアップできています。
CSS 2.1 Conformance Test Suite

テストハーネスを使ったテスト方法


テスト結果のレポート形式


CSS 2.1 Conformance Test Suiteのテスト結果のレポート形式については、W3CのCSSWG(CSS ワーキンググループ)で決められていて、下記のサイトにまとめられています:

http://wiki.csswg.org/test/implementation-report

escortウェブ ブラウザでは、今のところhtml4のテストのみ行なっています。そのテスト結果は以下のページから確認することができます:

http://code.google.com/p/es-operating-system/source/browse/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data

r2923の段階ではFedora 17上でescortは約90.8%のテストにパスしていることがわかります。

自動テスト用のログファイルの準備


自動テストを行うためには、まず各テストのタグ付きのログファイルを用意します。はじめてテストするときは目視でひとつひとつテストをチェックしていかないといけません。一方、テスト済みのテストに関しては、implement-report-Escort-Fedora.dataの結果を元にログファイルを自動で生成する機能がharnessにあります。

ログを生成するには、implement-report-Escort-Fedora.dataに対応するリビジョンのビルド ディレクトリで以下のようにコマンドを実行します:

$ mkdir html4
$ ./harness -j16 -g ~/es/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

-g オプションがログファイルの生成を指示しています。-j16 はテストを16プロセスで並行して実行するように指示しています(プロセス数はお使いのCPUに合わせて調整してください)。

./Script.test以降が各テストプロセスで実行するコマンドになります。--vはログレベルの指定です(harnessでは2を指定します)。-geometry以降はglutInitが処理する引数になります。

2012/8/24 補足: r2948以降、ログレベル1だとharnessに対応しなくなっています。2を指定してくださいい。

harnessの実行が終わると(Core i7 3770のPCでは5分前後かかります)、ログファイルがディレクトリhtml4の下に生成されています。

$ ls html4
absolute-non-replaced-height-001.log
absolute-non-replaced-height-002.log
absolute-non-replaced-height-003.log
・・・snip・・・

ちなみにログファイルの中身はこのような感じになっています:

$ cat html4/absolute-non-replaced-height-001.log
# html4/absolute-non-replaced-height-001.htm    pass
## render tree
* block-level box [html] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
  * block-level box [body] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
    * block-level box [p] (0, 0) w:816 h:17.6783 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
      * line box (0, 0) w:581.614 h:17.6783 (0, 0) m:0:0:0:0
        * inline-level box (0, 0) w:581.614 h:17.6783 m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 "Test passes the a filled blue square touches the upper-left corner of the black box." #000000
    * block-level box [anonymous] (0, 17.6783) w:816 h:0 (0, 0) t:0 m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 transparent
      * line box (0, 17.6783) w:0 h:0 (0, 0) m:0:0:0:0
        * block-level box [div] (0, 96) w:288 h:192 (0, 0) m:0:0:0:0 p:0:0:0:0 b:3:3:3:3 transparent
          * line box (3, 99) w:0 h:0 (0, 0) m:0:0:0:0
            * block-level box [div] (3, 99) w:96 h:96 (0, 0) m:0:0:0:0 p:0:0:0:0 b:0:0:0:0 #0000ff

1 行目に実装レポートの形式で結果が記述されていて、2行目以降にScript.testから出力されたレンダー ツリーのダンプが書き込まれています。

なおharnessが保存したり比較したりするレンダー ツリーはloadイベントを処理した直後のツリーになっています。ですので、ページのロードが完了した後でさらにマウスで何か操作したりしないといけないようなテストについてはharnessで完全にテストできているわけではない、という点は注意が必要です。

自動テストの実行と確認


ログファイルの準備ができたので、実際にテストしてみます:

$ ./harness -j16 ~/es/trunk/escort/testlog/css2.1/20110323/implement-report-Escort-Fedora.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

harnessをテスト プロセス数を指定する-j16以外のオプションなしで実行すると、比較テストを行います。harnessの戻り値は、何も変化がなければ0に、変化があれば1になります。

$ echo $?
0

またテスト結果は、report.dataというファイルに記録されています。何か変化があったテストでは結果が"uncertain"に、実行中にクラッシュしたりタイムアウトしたりしたテストでは結果が"fatal"と記されています。

"uncertain"となったテストを確認したい場合は、まず

$ grep '#\|uncertain' report.data > uncertain.data

のようにして、 表示に変化のあったテストだけを抜き出します。

補足: grepで#も含めているのは、harnessは#からはじまる行をディレクテブ(命令)として処理していて、指定されたユーザースタイル シートを読み込んだり、テスト用のフォントの有効・無効を切り替えたりしているためです。

続いて以下のように、

$ ./harness -i uncertain.data ./Script.test ~/es/trunk/escort/testdata/default.css --v=2 -geometry +0+0

harnessを -i オプションをつけて実行すると、テストがひとつひとつ表示されて、コマンド プロンプトから結果を再度入力していくことができます。

[html4/absolute-non-replaced-height-001.htm] pass?

このとき単に[Enter]を押せば、ログファイル中に記録されてい判定(この例ではpass)のままログのレンダーツリーだけが更新されます。それ以外の判定を入力する場合は、判定内容を直接タイプするか、以下のような短縮形が使えます:

p   pass    成功
f   fail    失敗
i   invalid テスト自体が無効
n   na      テストしている機能が未実装
q   quit    harnessを終了
z   undo    ひとつ前のテストに戻ってテストをやり直す

また未実装の機能を利用しているためにテストが失敗しているのであれば、短縮形ではなく、

[html4/replaced-intrinsic-001.htm] ? na (svg)

といった具合に入力しておくとあとで調査しやすくなります。

ブラウザの修正中は、このようにいくつかのテストをピックアップして、それらを集中的にテストして進めていくことが多いのですが、それによって思わぬ他のテストが崩れていたりする場合もあるので要注意です。もっと大規模なプロジェクトの場合は、テスト結果が(悪い方向に) 変わるようなパッチをコミットできないようにしたりすることもあると思いますが、ESプロジェクトではいまのところそこまで厳格なことはしていなくて、リグレッションはリグレッションで別パッチで後でまとめて修正したりしているのはこれまで報告してきた通りです。

付録: harnessのコマンドライン オプション


harnessコマンドには、-g, -i オプションといったオプション以外にも、次のようなオプションがあります。

-g   レポートファイルの判定を元にログファイルを生成します。
-i   テストをひとつひとつ実行して、結果を入力していきます。
-r   ログファイルからreport.dataを再生成します。
-u   ログファイル中のレンダーツリーのダンプを指定したScript.testからの出力に置換します。

-u は、レンダーツリーのダンプ内容自体を変更したりした場合に利用します。

まとめ


今回はescortウェブ ブラウザのテストを自動化するテスト ハーネスについて紹介しました。harnessプログラム自体もプロジェクトの進展とともに進化している部分もあるので、また何か新しいことがあればこのブログからもお知らせしていきます(データセンターがあればテストに16プロセスなんてケチなことは言わずに、1,024プロセスでテスト時間5秒みたいな感じになりますよね)。

それから一般的にはいわゆる標準規格のテスト スイートは、時間と労力をかけて独自に開発したり、あるいはお金を払ってテスト スイートごと購入したりしなければならないことが少なくありません(数百万円〜/年、数千万円〜/年のようなイメージです)。CSS 2.1 Conformance Test Suiteのような規模なものが無償で手に入るというのは実はすごいことです。もし仮に一律1ページ5,000円だったとしたら、・・・やめときませう f^_^;;

次回は計画中のCSSレンダリング エンジンの改良などについて報告していく予定です。

2012年8月18日土曜日

ESウェブブラウザ通信 - Ubuntu版のリリースに向けて

これまでescortウェブ ブラウザのバイナリ パッケージはFedora版のみ公開してきました。次のバージョン0.2.3からはUbuntu用のdebパッケージも公開する予定です。今回は、今後の参考のためにdebパッケージを自分で作成して公開する際の手順をまとめておきます。

FedoraとUbuntuの違いは、いろいろあると思いますが、まず利用しているパッケージの形式がFedoraはrpm、Ubuntuはdebになります。それからファイルシステムの構成方法は、どちらもFilesystem Hierarchy Standard (FHS)に基づいているのですが、Ubuntuが標準のまま利用しようとしている感じなのに対して、Fedoraは、
The FHS document is the authoritative reference to any FHS-compliant file system, but the standard leaves many areas undefined or extensible.
としていて多少違いがあります。escortブラウザではr2930から、Fedoraだと/usr/libexecディレクトリを利用している部分は、Ubuntuでは/usr/libを利用するように修正しています。

注意: これまでにUbuntu上でescortをソースからビルド、インストールされていて、もし/usr/libexecの中にesrilleというディレクトリだけがある場合は、/usr/libexecごと削除してr2930以降にアップデートしてください。

この記事では、これ以降はご自分でdebパッケージを作成する必要がなければ、特にescortについての新しい情報は含まれていません。

escortのdebパッケージの作成手順


ツールのインストール


Fedoraではrpmbuildやmockというツールを使ってパッケージを作成しましたが、Ubuntuではdebhelperpbuilderといったツールを使いますので、予めインストールしておきます:

$ sudo apt-get install ubuntu-dev-tools  # pbuilder
$ sudo apt-get install debhelper         # dh

debianディレクトリの準備(dh_make コマンド)


rpmを構築するためにはSPECファイルを作成しましたが、debの構築ではdebianというディレクトリの下にいくつかの設定ファイルが必要になります。r2932以降で必要なファイルがソースツリーに予めコミットしてあります。

はじめてdebianディレクトリを準備する場合は、make distで作成したtarballを使って、そのひな形をdh_makeコマンドで用意することができます:

$ sudo apt-get install dh-make
$ tar zxvf esidl-0.2.0.tar.gz
$ cd esidl-0.2.0
$ dh_make -e info@esrille.org --copyright apache \
-f ../esidl-0.2.0.tar.gz --native

上記のdh_makeコマンドの引数の内容は以下のとおりです:

-e info@esrille.org # パッケージをesrille.orgが提供していることを示します
--copyright apache  # apacheライセンスのオープンソースプログラムであることを示します
--native            # esidl-0.2.0.tar.gzがはじめからdebianに対応したtarballであることを示します

debianディレクトリ内のファイルはrpmのSPECファイルで記述したのと同様の内容をいくつかのファイルに分けて記述したような感じになっています。詳細は、『Debian 新メンテナーガイド』などを参考にしてください。SPECファイルもそうでしたが、esidlやescortのようにautotoolsを使っているプロジェクトであれば、特に複雑な設定は必要なさそうです。

パッケージに署名するための鍵の準備


注意: 自分でパッケージに署名する必要がなければ、キーリストへの鍵の登録だけを行います。

pbuilderを利用するときにはパッケージに署名をしておかないとその他の設定がいろいろと面倒になるところがあるので、GnuPGを使って鍵を生成しておきます。

$ gpg --gen-key

GnuPGの詳しい使い方は『GnuPGの使い方』などを参考にしてください。esrille.orgから配布するパッケージにはバージョン0.2.3からは、
Esrille Inc. (0.2) <info@esrille.org>
の鍵で署名していく予定です。ニックネームは今のところ(メージャー バージョン.マイナー バージョン)表記としています。

なお、1箇所注意しておいたほうがよいのは、 署名に使うためにgpgで作成した鍵とdebian/changelogファイル中の、
Firstname Lastname (nickname) <user@domain.tld>
の部分はまったく同じでないといけない、という点です(参考: debsign: clearsing failed: secret key not available)。

鍵を作り終わったら、作成した鍵を使って署名したパッケージをaptコマンドで認証できるように、 公開鍵をaptのキーリストに登録しておきます。公開鍵を、

$ gpg -a --export userid

で表示して、それを、

$ apt-key add -
...公開鍵のテキストを貼り付ける...
^D  # EOFを入力

のようにすれば、キーリストに鍵を登録できます。登録されている鍵は、

$ apt-key list

で確認できます。

補足: ソースパッケージの認証は~/.gnupg/trustedkeys.gpgを参照するようで、

$ gpg --no-default-keyring --keyring trustedkeys.gpg \
--import

で登録できます。

ローカルのdebレポジトリの準備


escortのパッケージのビルドで少し面倒な所は、escortの前にesidl Web IDLコンパイラのパッケージをビルドして、さらにそれを利用してescortのパッケージをビルドしないといけない点です。

こういった場合、pbuilderでは、ローカルにdebパッケージのレポジトリを用意しておいて、そこにesidlのパッケージを登録しておき、escortをビルドするときにはローカルのレポジトリからesidlを取得してくる、という方法がPbuilderTricksに紹介されています。

そこで、pbuilderのセットアップを行う前にロカールのdebレポジトリを準備しておきます。
HowToSetupADebianRepositoryではいろいろなdebレポジトリの構築方法が説明されていて迷ってしまうのですが、ここではapt-ftparchiveを使った方法をまとめておきます。

まずはこちらなども参考にレポジトリのルート ディレクトリを決めます。 ここでは、
~/ftparchive
を使うことにしておきます。そうしたら、その下にさらに以下のようなディレクトリ構造を作ります:

~/ftparchive
  + conf
  + db
  + dists
  + hook  # このディレクトリはpbuilderが参照します
  + pool
      + precise   # 12.04 LTS (Precise Pangolin)用のプール

ここでは、Ubuntu 12.04(Precise Pangolin)用のパッケージだけを準備しています。confの中には以下の2つの設定ファイルを用意しておきます。

$ cat ~/ftparchive/conf/apt-ftparchive.conf
Dir {
    ArchiveDir       ".";
    CacheDir         "db";
}

Tree "dists/precise" {
    Sections         "main";
    Architectures    "i386 amd64 source";
    Directory        "pool/precise";
    SrcDirectory     "pool/precise";
}

Default {
    Packages {
        Extensions   ".deb";
    };
};

$ cat ~/ftparchive/conf/precise-release.conf
APT::FTPArchive::Release::Origin "Esrille Inc.";
APT::FTPArchive::Release::Label "ES operating system";
APT::FTPArchive::Release::Suite "unstable";
APT::FTPArchive::Release::Codename "precise";
APT::FTPArchive::Release::Architectures "i386 amd64 source";
APT::FTPArchive::Release::Components "main";
APT::FTPArchive::Release::Description "Packages for Ubuntu 12.04 from Esrille";

ここまで準備ができたら、あとはpbuilderが生成したファイルをpool/preciseの中にコピーして、以下のようなスクリプトを実行すると、~/ftparchive/distsの中にレポジトリに必要なファイルが生成されます:

$ cat  ~/ftparchive/update-archive.sh
#!/bin/sh
rm -rf db
mkdir -p db
rm -rf dists
mkdir -p dists/precise/main/binary-amd64
mkdir -p dists/precise/main/binary-i386
mkdir -p dists/precise/main/source
apt-ftparchive generate conf/apt-ftparchive.conf
apt-ftparchive -c conf/precise-release.conf release dists/precise > dists/precise/Release
gpg -abs -o dists/precise/Release.gpg dists/precise/Release

このupdate-archive.shスクリプトはあとで利用するのでここで作成しておきます。

pbuilderのセットアップ


pbuilderはFedoraのmockのUbuntu版のような感じで、やはりchroot環境でビルドすることでパッケージの依存関係の誤りなどを発見しやすくしてくれるものです。まずは、chroot環境を構築します。

$ pbuilder-dist precise create

'precise'はUbuntu 12.04 (Precise Pangolin) 用のパッケージをビルドすることを指定しています。ホストのOSが64ビット版(amd64)であれば、以下のような具合に32ビット(i386)のchroot環境も操作できます。

$ pbuilder-dist precise i386 create

続いて先ほど作成したロカールのdebレポジトリにpbuilderがアクセスできるように設定していきます。まず、以下のような~/.pbuilderrcファイルを作成します(userとなっている箇所は適当に置き換えてください)。

$ cat ~/.pbuilderrc
OTHERMIRROR="deb file:///home/user/ftparchive precise main"
BINDMOUNTS="/home/user/ftparchive"
HOOKDIR="/home/user/ftparchive/hook"
EXTRAPACKAGES="apt-utils"

また$HOOKDIRに以下のようなファイルD05deps作成します(変わったファイル名ですが名前の付け方に規則があるので変更しないように):

$ cat  ~/ftparchive/hook/D05deps
#!/bin/sh
apt-get update

以上の設定をpbuilderに反映させます:

$ pbuilder-dist precise update --override-config \
--configfile ~/.pbuilderrc

更にesidlパッケージの署名をpbuilder内でも認証できるようにしておかないといけないので、署名に使う鍵の公開鍵をpbuilderの環境にも保存しておきます(参考):

$ pbuilder-dist precise login --save-after-login
# apt-key add -
...公開鍵のテキストを貼り付ける...
^D  # EOFを入力
# もう一度^Dを押してログアウト

先ほどホスト側で行ったのと同じ処理をchroot環境内でも予め実行しておくわけです。

これでpbuilderのセットアップは完了です。

ソースパッケージの作成 (esidl)


次に、esidlのtarballを展開して、ソースパッケージだけを作成します。

$ cd esidl-0.2.3
$ dpkg-buildpackage -S
$ cd ..
$ ls -F
esidl-0.2.3/
esidl_0.2.3.dsc
esidl_0.2.3_source.changes
esidl_0.2.3.tar.gz
esidl-0.2.3.tar.gz

esidl_0.2.3(途中はアンダースコア)ではじまるファイルがdpkg-buildpackageコマンドの作成したファイルで、pbuilderが参照するファイルになります。(mockでもrpmbuildでソースパッケージだけ先に作ったのと似ています。)

なお、ソースツリーでdebianディレクトリ内のファイルを変更したときは、この手順から実行し直す必要があります。

debパッケージの作成 (esidl)


続けて、pbuilderを使ってesidlのdebパッケージを構築します。

$ pbuilder-dist precise build esidl_0.2.3.dsc

実行が完了すると、~/pbuilder/precise_result の中にdebパッケージが作成されています:

$ cd ~/pbuilder/precise_result
$ ls
esidl_0.2.3.dsc
esidl_0.2.3_amd64.changes
esidl_0.2.3_amd64.deb
esidl_0.2.3.tar.gz

この状態ではまだパッケージに署名がされていないので、署名しておきます。

$ debsign esidl_0.2.3_i386.changes

ローカルdebレポジトリの更新


次に生成されたesidlのdebパッケージをローカルレポジトリに登録します:

$ cd ~/ftparchive
$ cp ~/pbuilder/precise_result/esidl_0.2.3* pool/precise
$./update-archive.sh
 pool/precise: New 1,347 B 1 files 202 kB 0s
 pool/precise: New 20 B 0 files 0 B 0s
 pool/precise:  esidl has no source override entry
  esidl has no binary override entry either
 New 1,324 B 1 pkgs in 0s
Packages done, Starting contents.
 dists/precise/Contents-amd64: New 220 B 1 files 202 kB 0s
 dists/precise/Contents-i386: New 20 B 0 files 0 B 0s
Done. 202 kB in 1 archives. Took 0s

update-archive.shの最後のステップでReleaseに署名しておくのがポイントです(参考: SecureApt - All about secure apt)。こうしておくと、あとでescortのdebパッケージをビルドする際に、pbuilderがesidlのパッケージを無事にインストールできます。ちなみに署名がないと、

Untrusted packages could compromise your system's security.
You should only proceed with the installation if you are certain that
this is what you want to do.

  esidl

Do you want to ignore this warning and proceed anyway?
To continue, enter "Yes"; to abort, enter "No": Abort.
E: pbuilder-satisfydepends failed.

となって、pbulderが強制終了されてしまいます(これはこれで直す方法があるようですが、署名してしまっておいた方が簡単な気がします)。

これでようやくescortのdebパッケージをビルドする準備ができました。今後、esidlには変更がなくて、escortだけパッケージを構築し直したい場合には次のステップから始めれば大丈夫です。

debパッケージの作成 (escort)


いよいよescortのdebパッケージをビルドしていきます。手順はesidlの場合と同じです。

$ tar zxvf escort-0.2.3.tar.gz
$ cd escort-0.2.3
$ dpkg-buildpackage -S
$ cd ..
$ ls -F
escort-0.2.3/
escort_0.2.3.dsc
escort_0.2.3_source.changes
escort_0.2.3.tar.gz
escort-0.2.3.tar.gz
$ pbuilder-dist precise build escort_0.2.3.dsc
$ cd ~/pbuilder/precise_result
$ ls
escort_0.2.3.dsc
escort_0.2.3_amd64.changes
escort_0.2.3_amd64.deb
escort_0.2.3.tar.gz
esidl_0.2.3.dsc
esidl_0.2.3_amd64.changes
esidl_0.2.3_amd64.deb
esidl_0.2.3.tar.gz
$ debsign escort_0.2.3_amd64.changes

これでパッケージがすべて準備できました。

実際にHTTPサーバーから公開する場合には、escortのファイルもpoolに入れて、~/ftparchiveから~/ftparchive/distsと~/ftparchive/poolの部分を公開することになります。

まとめ


今回はUbuntu用のdebパッケージの作成方法をまとめておきました。それから前回、次回紹介しますと書いてしまったテスト ハーネスの使い方についてはまた次回に、ということで、今回はここまでです。

2012年8月11日土曜日

ESウェブブラウザ通信 - テーブルの自動レイアウトの改善等

今回は、今日リリースしたescort 0.2.2で新たに実装した機能について紹介します。escort 0.2.2では、CSS 2.1の実装の改善を主な目的として開発を進めきました。CSS2.1 Conformance Test Suiteの達成率は90.8%とescortではこれまででベストの結果となっています。

link要素のmedia属性


r2870では、link要素のmedia属性が未サポートだったので、
&lt;link href="/includes/deed3-print.css" media="print" rel="stylesheet" type="text/css">
といった印刷メディア用のスタイルシートも一緒にスクリーン上で処理してしまっていました。 下図は r2870でCreative Commons のライセンスの要約のページを表示した際のスクリーンショットです。
r2870 (link要素のmedia属性未対応)
r2871, r2872でlink要素のmedia属性に対応しています。
r2871 (対応済み)
なお、今回の実装は CSS 2.1 のメディア リストの仕様に基づいています。メディア リストは CSS 3では、メディア クエリーとなって強化されている部分ですが、escortではいまのところ未対応です。

テーブルの自動レイアウト


テーブルの自動レイアウト アルゴリズムは、CSS 2.1の仕様書17.5.2.2では、
UAs are not required to implement this algorithm to determine the table layout in the case that 'table-layout' is 'auto'; they can use any other algorithm even if it results in different behavior.
となっています(≒未定義)。現状ではCSS標準のレイアウト アルゴリズムがないので、何か特定の動作に期待して'table-layout'プロパティが'auto'に設定されている表をレイアウトに使わないこと、というのがよく言われているお約束の趣旨かな、と思います。

そのためこれまでのescortのテーブルの自動レイアウト アルゴリズムはかなり手を抜いたものになっていて、Google CodeのES operating systemのページはr2872では以下のような描画になってしまっていました。
r2872
Google Codeのこのページでは、左側のリンクばかりのカラムの幅はautoに、右側のカラムの幅は100%(表全体の幅に対して100%という意味)に設定されています。ですのでnon-normative(参考)としてCSS 2.1の仕様書に載っているアルゴリズムに倣うと、左側のカラムは最小限必要な幅だけを取って、残りを右側のカラムが(幅がなるべく100%に近づくように)全部専有する感じになります。

このとき『最小限必要な幅』というのはとりあえずレイアウトしてみないことにはわからないので、参考アルゴリズムではレイアウト処理が1パスでは終わらなくて、仕様書にも"This algorithm may be inefficient"と記載されています。

escort 0.2.2では、CSS 2.1の参考アルゴリズムを参考に、Google Codeのページくらいはそれなりにレイアウトできるように実装を改良することにしました。
r2873
r2873では、自動レイアウトのテーブルに2パスのレイアウト処理を取り入れました。

1パス目では従来と同じように、テーブルを包含ブロックとして各セルをレイアウトしつつ(このとき算出されたセルの幅を"maximum" cell widthとしています)、参考アルゴリズムに記述されている各セルのminimum content width (MCW)を合わせて計算しています。MCWは行の途中で折り返すことのできない単語の最大幅などから計算できます。

2パス目では、まずMCWをもとにMIN(最低限必要なテーブル全体の幅)を計算します。テーブル自体に指定された幅(W)がautoの場合は、簡略レイアウトで求めた幅から計算される値から参考アルゴリズムのMAXを計算しています(r2875)。

またMIN &lt; Wの場合などには余った幅を参考アイルごリズムでは、
If the used width is greater than MIN, the extra width should be distributed over the columns.
と、各カラムに分配するように記述されています。ところがこの1文の解釈が実は結構大変なところでした。r2873では、ひとまず幅が明示的に固定値で指定されているカラムには分配しないようにしてありました。

このようにして各カラムの幅がきまったら、各セルをカラムの幅に合わせて再度レイアウトしていきます。

すこしリビジョンが進んで、r2888ではinput要素のsize属性に対応しています(右上の方にあるテクストボックスの幅が広がっています)。
r2888
r2888では、テキストボックスの幅が広がった分、es-operating-systemというテキストを含んでいるセルの幅が不足してテキストが途中で折り返されるようになってしまいました。
r2889
r2889では、自動テーブルレイアウトのアルゴリズムを改良して、余った幅は、まだmaximum column widthに達していないカラムに優先して分配して、それでも余っていたら各カラムに均等に分配、という2段階で分配するようにしました。これで"es-operating-system"の部分も無駄に改行されずに済むようになりました。

ただr2889では『各カラムに均等に分配』という処理のために、Summary Peopleというリンクがあるセルの右隣にあるMCWが0のセルの幅も増やしてしまっていました。この点については、幅0のセルは0のままにしておく、というのが各メジャー ブラウザでの暗黙のルールの様子です。
r2890
r2890では、幅0のセルは0のままにしておくように修正しました。Summary Peopleというリンクがあるセルの下線がウィンドウ幅いっぱいに広がっているのに気づくでしょうか?

CSS 3では、 標準のテーブル自動レイアウト アルゴリズムの策定が期待されるところですが(*)、escortブラウザでは、当面は更に凝ったテーブルの自動レイアウト処理が必要かどうか他のサイトなども見ながら確認していきたいと思います(David Baronさんも詳細を検討されている途中のようです)。

(*) CSS3 BOXに、
[CSS3TBL]
Bert Bos; David Hyatt. CSS3 Tables Module. (forthcoming). W3C Working Draft. (Work in progress.)
という記載が見られます。

ドキュメント タイトルの空白のつぶし


r2873のウィンドウのタイトルバーを見てみると、"es-operating-system -     ES operating system..." のように余分な空白が見えます。
r2873
HTMLファイル中ではこの部分は改行コードなどが入っていたりするのですが、それがそのまま表示されてしまっていました。

HTML Living Standardの3.1.4では、documentからtitleを取得するときは、
Replace any sequence of one or more consecutive space characters in value with a single U+0020 SPACE character.
と規定されているので、r2874で対応しています。
r2874
ちなみに、HTMLTitleElement要素のtext属性を取得する場合は、文字列の前後以外の空白のつぶしは行わないのが仕様のようです。

テーブルの絶対配置


escort 0.2.1以前はテーブルの絶対配置に未対応だったのですが、r2879からr2884にかけてCSS2.1 Conformance Test Suiteを使ってテストしつつ対応しました。
table-percent-width-001 (r2879)
r2879ではテーブルの高さの処理に問題があって、テストスイートのabspos-006などで問題がありました。 PASS という文字はページの右下に表示されないといけないのですが、テーブルの高さがビューポートの高さに設定されてしまっていました。
abspos-006 (r2879)
 r2880で問題点を修正しています。
abspos-006 (r2880)
r2881では、仕様書14.2のキャンバス全体をルート要素の背景色で塗りつぶすという処理にバグがありました。
abspos-containing-block-initial-004c (r2881)
r2882で修正しています。
abspos-containing-block-initial-004c (r2882)
abspos-containing-block-initial-004eは、ルート要素のスタイルに"display:table"が設定されているという嫌な感じのテストです。
abspos-containing-block-initial-004e (r2882)
r2882の段階では、匿名のセルに誤ってスタイルを設定してしまっていたので、セルが絶対配置されているようなおかしな状態になってしまっていました。
r2883
r2883でその点を修正していますが、背景色が黄色になっていません。キャンバスの色はbody要素から来ているので、rootで再計算した値をそのまま使ってしまうとデフォルトの色になってしまっていたのでした。
r2884
r2884でひとまず修正しましたが、この処理は想像よりも面倒でr2912でようやく実装が落ちつきました。

リグレッションの修正


テーブルの自動レイアウトでは各セルについて2パスでリフローを実行したり、といったこともあってリグレッションがいろいろと発生して、一時的にCSS 2.1 Conformance Test Suiteの達成率も3月末の90.1%から84%くらいまで落ちてしまっていました。r2890以降r2919までリグレッションの修正を続けて達成率を90.8%まで復旧させました。修正内容については、escort 0.2.2のTODOリストChangeLogを参考にしてください。

まとめ


今回は、escort 0.2.2で新規に実装した下記の機能について紹介しました。
  • link要素のmedia属性の処理
  • 自動テーブルレイアウトアルゴリズムの実装
  • 絶対配置されたテーブルのレイアウト機能の実装
  • Document要素のtitle属性取得時の空白のつぶしの実装
特に自動テーブルレイアウトアルゴリズムの実装では、まだ標準仕様がないために実装にあたっては他のブラウザのレイアウトと見比べながら改良していくということで結構手間取りました。

自動テーブルレイアウトはもうあまりにも多く(レイアウト目的に)使われすぎてしまっていて、今後は標準仕様を詰めていくしかないのだろうと思います。けれどもロンドン オリンピックの開会式にも登場されていたTim Berners-Leeさんの"Principles of Design"でも引用されているKISSの原則
"Keep it simple, stupid!"
には自動テーブルレイアウトは合ってない感じがします。特定のブラウザだけに非常に複雑な機能を実装してみて、他のベンダーも合わせて、と言うのではなくて、ものすごい単純だけどこれ便利だね、ということで他のベンダーもすぐにコピーしていくような発展の仕方の方がウェブらしいかな、と。

次回のESウェブブラウザ通信では、harnessコマンドを使ったescortブラウザのテスト方法について紹介したいと思います。またescortの方は、今後レンダーツリーの部分リフロー処理の実装をはじめて行く予定です(今回も実はテーブルの各セルについては部分リフローとほぼ同じ処理を行なっているわけですけれども)。部分リフローまでできるようになれば、escortのCSSレイアウトエンジンの骨格部分は固まってくる感じになると思います。

というわけで、今回はここまでです。