2012年1月7日土曜日

ESウェブブラウザ通信 - CSS 2.1 Test Suite #11

あけましておめでとうございます。新年もESウェブブラウザの開発を進めています。このブログも合わせて引き続きよろしくお願いいたします。

昨年の最後のブログでは、より複雑なフローティングボックスのレイアウトについて対応を進めていきました。今回は、CSS 2.1の仕様書から12.5 Listsの実装をある程度進めて、そのあとで4章の最初から4.3.4まで主にCSSの字句解析・構文解析時のエラーからの復帰処理についてCSS 2.1テストスイートを使って実装とテストを進めていきます。

リスト

CSS 2.1ではリストの詳細については一部、
CSS 2.1 does not define how the list numbering is reset and incremented. This is expected to be defined in the CSS List Module [CSS3LIST].  
といった具合に、細かい規程をCSS 3に先送りしている箇所があります。その背景については、現在のCSS 3 Listsのエディタ、Tab Atkins Jr.さんのブログでまとめられているのが参考になります。

ESウェブブラウザでは、CSS 3 Listsの規程を一部先取りしながら、まずはCSS 2.1として期待通りに動くような実装を目指していきます。進め方はいつも通り、まず下記の修正でクリティカルパスを実装して、詳細はCSSのテストスイートを動かしながら直していきます。

r2218, r2219: ::marker擬似エレメントを導入。
r2220: 'list-style-position'プロパティに対応。
r2221: ''list-style'ショートハンドに対応。
r2222: カウンタの詳細実装を追加。

CSS 3 Listsでおもしろいのは::marker擬似エレメントの導入です。::beforeとほとんど同様の実装で、リストのマーカーに特化した処理を記述できるようになっています。CSS 2.1の仕様をまとめていく過程で::beforeに機能を詰め込みすぎて収拾がつかなくなって、CSS 2.1では詳細の規程をCSS 3に先送りした、といった経緯があったりするみたいですね。

・ c561-list-displ-000

ふつうに<ol>, <li>を使った場合には、r2222でリストの表示ができるようになっているのですが、このテストでは、div要素のdisplayに'list-item'を指定することでリストを表示させようとしているので未対応になっていました。

r2223
CSS 3 Listsでは、 displayに'list-item'を指定されていた場合には、::marker擬似要素を生成して、自動的にカウンタ'list-item'を増加させるように規程されています。

r2224
r2224でその処理を実装しています。

・ c563-list-type-001

decimal以外のリストのタイプもテストしています。

r2224
r2225で対応しました。CSS 3 Listsでは、'@counter-style'ルールを使ってかなり自由にカウンタのスタイルを設定することができるのですが、ESウェブブラウザではいまのところCSS 2.1で必要なスタイルをハードコーディングしています。

r2225
・ c564-list-img-000

'list-style-image'のテストです。

r2225
r2226でひとまず'list-style-image'に対応するようにしました。イメージが無効な場合は'list-style-type'を使わないといけないのですが、その辺は今後実装していきます。

r2226

CSS 2.1では、
CSS 2.1 does not specify the precise location of the marker box - 12.5.1
となっていて、マーカーの位置は具体的には指定されていないのですが、このテストでは、CSS 3 Listsで規定されている、
the horizontal static position of the marker is such that the marker's "end" edge is placed against the "start" edge of the list item's parent. - 4. Marker Position
という規則に則っているようです。

r2226
"end" edgeなどもCSS 2.1にはない概念だったりしますが、r2227でひとまず対応しています。メジャーなブラウザでは、さらにマーカーの直後にスペースが入るようなのですが、その辺は最新の仕様の状況など見ながら対応していければと思います。

r2227
・ counter-reset-increment-002

カウンタのインクリメントのテストです。

r2227

ひとまずr2228で細かなカウンタまわりのバグをまとめて修正しています。

r2228
これでWebKit系のブラウザと同じ崩れ方になりました。というのも、CSS 3 Listsの仕様を導入していると、 list-itemという名前のデフォルトのカウンタがあらかじめ予約されているのですが、このテストでもlist-itemという名前のカウンタを使っているので、CSS 3 Listsの規程の動作とテストのCSSの設定が両方とも動作してカウンタが想定以上に増加していってしまうのです。
r2228 (カウンタの名前をlist-item以外に変更)
HTMLファイルを修正して、カウンタ名を'list-item'以外に変更すると上図のように想定通りの動作になります。CSS 3リストで予約するカウンタ名が本当にlist-itemで大丈夫なのかという疑問はちょっと残りますね。

リストの処理自体はまだ作り込んでいかないといけない部分が残っているのですが、基本的な処理は入ったので、今はここでいったん終わりにして、CSS 2.1の仕様書の4 Syntax and basic data typesのテストに進んでいきます。

CSSの構文とデータ型のテスト

これまで他の章のテストを進めて来れたことからもわかるように、エラーもなく丁寧に記述されているCSSスタイルシートのパース処理については、ここまでの段階でも大きな問題はありません。今回テストを進めていくのは文法エラーからの復帰処理など、一部誤りがあるようなスタイルシートの処理などが中心になります。

ESウェブブラウザでは字句解析にRE2C、構文解析にbisonを使用しています。修正箇所もこれらのツールのソースコードの修正がかなりあるので、そういった部分の詳細に興味のあるひとはいわゆるドラゴンブックが定番の教科書だと思うので参考にしてみてください。

補足: 字句解析はlex(flex)の方が定番だったと思うのですが、ESウェブブラウザの内部処理コード(char16_t)との親和性などでより扱いやすいRE2Cを使っています。

・ core-syntax-009

@importルールの基本的なテストを行っています。

r2231
r2232で@mediaルールにも対応しました。

r2232
・ list-style-020

最後のblue circleの行のlist-styleの設定(.seven)はすべて無効なのでデフォルトのcircleが表示されるはず、というテストです。

r2235

r2236で無効なプロパティの設定を無視する枠組みを実装して、無効なlist-styleを除外できるようにしました。

r2236
・ case-sensitive-003

:first-child擬似クラスセレクタと:lang擬似クラスセレクタに未対応でしたので、赤い行が残っています。
r2236

r2237で:first-child擬似クラスセレクタに、r2238で:lang擬似クラスセレクタにそれぞれ対応しました。

r2238
・ case-sensitive-004

langセレクタの比較で大文字・小文字を区別し処理してしまっていないかテストしています。
r2238
r2239でlangセレクタの比較では大文字・小文字を区別しなように修正しました。

r2239
・ case-sensitive-005

カウンタの名前の大文字、小文字を区別しているかどうかテストしています。

r2239
r2240でカウンタ名の大文字と小文字を区別するように修正しました。

r2240
・ escapes-005

\00006Cのようなユニコードのエスケープ表記のテストです。

r2240
r2240では、"back\000047round"を"backGround"までは変換できていたのですが、さらにプロパティ名は大文字・小文字を区別しないので内部的にはさらに"background"のようにすべて小文字に変換しておく必要がありました。

r2241
r2241で修正しています。

・ ident-003

CSS 2.1の仕様書に載せられているyacc/lexの文法では、#ではじまるRGBカラーと、#ではじまるIDセレクタなどを区別していないのですが、それをそのまま利用していたので'#-1ident'という文字列が有効なIDセレクタとして処理されたりしてしまっていました。

r2241
ランタイムでチェックしてもよいのですが、r2242では字句解析のレベルでRGBカラーとIDセレクタを区別するように修正しています。

r2242
・ at-import-010

@importルールは、@charsetを除いて、ほかのどのルールよりも先に来ていないといけないのですが、無効なルールセットに関してはその限りではない、という点をテストしています。スタイルシート中最初の2行は無効なので、3行目の@importルールが有効になるというテストになっています。

r2043
r2044で不正な擬似セレクタを無視できるように修正しました。

r2044
・ ident-020

スタイルシートの中に.および#と識別子の間に'-'が1文字入っている無効なセレクタが含まれているのですが、それによってパーサーが混乱しないで続く有効なセレクタを処理できているかどうかテストしています。

r2245
r2246でエラー処理を追加しています。

r2246
・ at-rules-004

このテストのスタイルシートの
p { color: green; }
@foo {};
p { color: red; }
という部分を見ていると、一瞬3行目のpルールは有効なような気がしてしまいますが、実際には@fooは}で終わっていて、";"だけの文は許されておらず、"; p"というセレクタもないので、最初のpルールだけが生き残る、という具合になっています。

r2246
r2247では、ひとまずbisonのstatement_listのルールに以下の3種類のエラー対策のルールを追加しています。
  | statement_list '@' error '{' error '}' optional_sgml
  | statement_list '@' error ';' optional_sgml
  | statement_list error '{' error '}' optional_sgml
CSSの文は@ルール文か、ルールセット文のどちらかですが、最初の2つは無効な@ルール文、最後の1つが無効なルールセットに対応します。(なお、修正自体はまだ不十分であとのat-rule-001のテストなどでさらに修正していきます。)

r2247
・ at-rule-003

CSSでは、{}, [], ()といったペアはまとめてエラー処理するよう指定されています(4.2)。

r2247
r2248r2249でひとまず{}のマッチング処理を追加しています。

r2248
・ at-rule-001

このテストのスタイルシートの、
@ import "support/at-rule-red.css";
div
{
    color: red;
}
という部分では、@とimportの間に空白が1文字入ってしまっています。一見、これも@ルールで行末の;(セミコロン)でルールが終わって次のdivルールが有効になるように思えます。しかし実は@ルールとして処理して構わないのは@の直後に空白を含まず識別子が来た場合だけなので、上のルールは'@ import "support/at-rule-red.css"; div'という長いセレクタ相当の部分がある不正な1つのルールセットということになります。

r2249
先ほどのr2247では、@ではじまる文を@ルール文として処理するように修正しましたが、それではダメで、r2250では、@記号の直後に空白などをはさまずに識別子がある場合のみ@ルール文として処理するように修正しています:
 | statement_list '@' IDENT error invalid_block optional_sgml
 | statement_list '@' IDENT error ';' optional_sgml
 | statement_list error invalid_block optional_sgml
r2250
なお、このテストに関しては詳しい解説がマイクロソフト社のArron Eicholzさんからメーリングリストに流れていたのが参考になりました。

・ core-syntax-004

CSSでは、スタイルシートの終わりまできて、開いたままの{ではじまるブロックがあれば、強制的に閉じるように規程していますが、そのテストになっています。

r2251
r2252でこの仕様に対応しています。

r2252

これは正しい宣言と;(セミコロン)の間に不正な文字列が入っている場合のテストです。このような場合、パーサーは不正な部分を飛ばして処理を続けていくこともできるのですが、CSSの場合には正しかった宣言も無効なものとして扱うように規程しています。

r2252
r2254で宣言のあとの;(セミコロン)あるいは}の前に不正な文字があった場合にはその宣言を取り消すように修正しています。

r2254

CSSでは、文字列が対応する"(ダブルクォート)もしくは'(シングルクォート)で閉じられずに行末まで来てしまった場合は、その文字列を強制的に閉じて、かつその文字列を使用しているルールを無効することになっていますが、そのテストになっています。

r2254
r2255で対応しています。

r2255
・ blocks-001

{}、[]、()のペアはまとめてエラー処理する必要があるのですが、そのテストになっています。
r2255
r2248での{}に続いて、r2256で[]と()にも対応しました。

r2256
・ eof-002

スタイルシートの最後でまだ閉じられていない(と[についても仕様通りに強制的に閉じているかどうかテストしています。

r2256
r2257で対応しています。

r2257
・ eof-003

CSSでは、文字列が閉じられないままスタイルシートの終わりに来たときは、行末の場合とは違って、文字列を閉じてかつそれを有効な文字列として処理を継続するように規程されています。そのような場合のテストになっています。

r2257
r2258で対応しています。

r2258
補足: re2cは、
re2c:yyfill:enable = 0;
のようにyyfillを無効にしている場合には、終端のチェックがかからないので、自前でチェックするようにr2258で合わせて修正しています:
Set this to zero to suppress generation of YYFILL(n). When using this be sure to verify that the generated scanner does not read behind input. Allowing this behavior might introduce sever security issues to you programs. - Manpage of RE2C
eof-005

;(セミコロン)で閉じる@ルールも、スタイルシートの最後まで閉じられなかった場合は強制的に閉じて、有効なルールとして処理する必要があります。そのテストになっています。

r2258
r2259で対応しています。

r2259

・ font-family-invalid-characters-002

ファンクション中の式にエラーがある場合、()は対応づけてエラー処理をしないといけません。そのテストになっています。

r2259
r2260でひとまず対応しています。

r2260
・ comments-003

/*ではじまるCSSのコメントも、スタイルシートの最後まで閉じられなかった場合は強制的に閉じる必要があります。

r2260
r2261で対応しています。

r2261
 ・ matching-brackets-001

@ルールの処理ではブロックなのか、ブロックを含まない;(セミコロン)で終端されるルールなのか明確に区別しておく必要があります。

r2261
r2262で、{}を含んだerror_blockと{}を含まないerror_non_blockにエラー箇所を分けるようにしました。

r2262
・ uri-005

このテストではCSSの実装の問題はなくて、URIのパーセント エンコードのバグと、RFC 3986のHTML5による拡張が未実装のために正常に動作していませんでした。

r2262
r2263, r2264でそれぞれ修正しています。

r2264
・ uri-012

このテストの解釈はすこし難しいのですが、4.1.1のコアシンタックスまで戻って見ると、()内にはブロックは現れない、と考えられるので、url( { test )の{は行末の}とマッチングされることはなく、直後の;(セミコロン)でこの不正な関数は打ち止められる、という理解になるのだと思います。
r2264
r2265で対応しています。

r2265
・ uri-017

url(ではじまるURIも、スタイルシートの最後まで閉じられなかった場合は強制的に閉じる必要があります。
r2266
r2267およびr2276で修正しています。

r2267
・ at-import-009

先ほどのat-import-010で修正したのと似たパターンで、@importルールの前にある他の@ルールが無効なので、@importルールが有効になる、というテストです。

r2267
r2268で対応しています。

r2268
・ import-001

このテストは一瞬@importルールの位置のテストのように見えますが、単純に@mediaルール内の構文エラーに対処しているかどうかのチェックです。

r2268
r2269で対応しています。

r2269
・ at-rule-013

このテストもimport-001に続いて@mediaルール内の構文エラーに対処しているかどうかのチェックです。

r2269
r2270で対応しています。

r2270
・ counters-010

これは字句・構文解析まわりでなくてカウンターの処理のバグでした。

r2272
r2273r2280でひとまず修正しました。カウンタまわりは次回以降、さらに修正していきます。

r2273
・ z-index-016

このテストは以前も取り上げたことがありますが、整数しか受け付けないCSSプロパティに2.0のような表記の浮動小数点で値を指定した場合にエラーにできない、という問題が残っていました。

r2273
r2274, r2275でそのような場合もエラーにできるように改善しました。

r2275
・ border-width-009

マイナスのボーダー幅をパース時にエラーとして無視しているかどうかのテストです。

r2276
こちらも以前に一度触れたことがありますが、これまではマイナスの値を受け付けないプロパティについてもパースには成功して計算値として既定値を返すような実装になっていました。r2277で、マイナスのボーダー幅をパース時にエラーとして無視できるようにしました。

r2277
ほかのプロパティについても同様の修正をr2278, r2279で行っています。

なお宣言の式の部分については、何かのツール用のコードのように見えるかもしれませんが、bisonで生成したパーサーが生成した木構造をC++のプログラムで解析するようになっています。

・ background-position-001

このテストでは、body要素の背景画像を使って描かれているライム色の線が200pxの位置にくればOKです。
r2281
body要素のbackgroundの設定はhtml要素の方に移るわけですが、r2281ではbackground-positionの計算値を計算していなかったために、body要素のfont-sizeではなくて、html要素のfont-sizeから解決値として位置を決定するようになってしまっていました。
r2282
r2282, r2284で修正しています。

以上で4章の4.3.4までの構文処理のテストについてはuri-013の#twelve、およびuri-015を除いて成功するようになりました。(未対応のプロパティのためにFAILしているテストは一部残っています。)

ちなみに4章のここで取り上げたテストに関して、執筆時点でのメジャーなブラウザのPASS率を見てみると、

Firefox 9 100%
Internet Explorer 9 100%
Internet Explorer 8 87.5% (このページを見る限りIE9もほぼ同様のようです)
Opera 11 75%
Chrome 16 62.5%

2010/1/13 追記: IE9では100%PASSするようです。Test Suite Failuresの個別のページに"IE9 Mode"という記載がなければFAILするのはIE 8でだけということのようです。(参考)

といった具合になっています。エラーからの回復処理などは、まだ足並みが揃っていない様子です。CSSに関してはまだきちんと文法はチェックして書いておいた方が無難かもしれないですね。

まとめ

今回はここまでです。ESウェブブラウザのCSS 2.1テストスイート全体のPASS率は約64%になりました。次回は4.3.5 Countersの部分からテストと開発を続けていく予定です。


0 件のコメント:

コメントを投稿