Shiki’s Weblog

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

2011/10/18 #ESウェブブラウザ通信

CSS 2.1 Test Suite #2から続けてきたW3C CSS 2.1テストスイートの9章も今回でひとまず最後です。以下、相対配置、絶対配置、そしてフロートの順に失敗していたテストの内容とその修正についてまとめていきます。・position-relative-035 このテストはサイズ16pxのフォントには1px以上のラインギャップがある、ということでないと成功しません。

r2027r2027

r2027では、Ahemフォントに対応した描画をするようにした際にラインギャップの処理を入れていなかったので真っ黒になってしまっています(Ahemフォントはラインギャップの値が0なのでした)。

r2028r2028

r2028で、ラインギャップも考慮してline-heightを決定するように修正しています。TrueTypeフォントのラインギャップをどう計算するか、というのには思ったよりも紆余虚曲折があったみたいなのですが、ここではOS/2テーブルから'usWinAscent + usWinDescent - unitsPerEm'で計算しています。・abspos-007 このテストでは、インライン コンテキストの中にブロックレベルのボックスが絶対配置されたときのスタティック ポジションが次の行の先頭になっているかどうかチェックしています。

r2028r2028

r2028まではスタティック ポジションは常にインライン レベルで計算してしまっていたのでした。r2029で修正しています。

r2029r2029

abspos-inline-002

このテストでは、相対配置されているインライン要素の中にインライン要素が絶対配置されている場合のレイアウトをチェックしています。

r2030r2030

"PASS"と表示されているので良さそうに見えますが、その直前の"The test has "というテキストが表示されていません。

r2031r2031

"This test..."ではじまる相対配置されたインライン要素からは、2つのインライン ボックス("This test has "と".")が生成されるのですが、スタッキング コンテキストの中には最後のボックスしか記録していなかったために、"This test has "の部分が描画されていませんでした。r2031で修正しています。・abspos-inline-003

r2031では、このテストでassertに引っかかっていました。ソース中、 <span class="test"><span class="absolute">PASSED</span><span class="fail">FAILED</span></span> となっている部分で、外側の'span class="test"'に直接対応するインラインレベル ボックスがないので、"PASSED"のインライン要素の絶対位置を決めるために参照するボックス自体がない、という状態になっていたのでした。

r2032r2032

r2032では、インライン要素内のインライン ボックスについては各要素からその子孫の要素によって生成されたインラインボックスも参照できるように修正しています。

この辺りで9.6, 9.7, 9.8, 9.9 と実装済みの部分に付いては割りと落ち着いてきたので、また9.4に戻ります。・ empty-inline-001 このテストは空のインラインのテストで、ラインボックスの高さが0になることをテストしています。

r2033r2033

前回inlines-020で空のインライン要素にも高さがある、ということをテストしたばかりですが、9.4.2には、

Line boxes that contain no text, nopreserved white space,no inline elements with non-zero margins, padding, or borders, and no otherin-flowcontent (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes...

と書かれているので、このテストは正しいわけです。ただ、10.8には、

Empty inline elements generate empty inline boxes, but these boxes still have margins, padding, borders and a line height, and thus influence these calculations just like elements with content.

とも書かれているので、ややこしい感じになってます。

r2034r2034

r2034では、マージン、ボーダー、パディングがすべて0(左右の設定も含む)の空のインライン要素が生成するインラインレベルボックスの高さは0にするように修正しました。・inline-formatting-context-002

r2034r2034

このテストではバグが2つ露見していて、ひとつはインラインボックスの余白が効いていないというバグ。もうひとつは、入れ子のインライン要素のスタイルの重ね合わせに対応していないというバグです。

r2035r2035

r2035では、ひとまずインライン要素の余白を適用するように修正しています。入れ子のインライン要素のスタイルの重ね合わせについては、大きめの修正になる可能性もあるので、9章のテストではひとまず保留にしておきます。・inline-formatting-context-015 このテストでは、前回スタッキング コンテキストの実装を改善したときにサボっていた箇所を見つけられてしまいました。

r2035r2035

本来表示するはずのフロートの青い枠の後に、背景がオレンジ色のブロックボックスを描画しているので青い枠が見えなくなってしまっています。

r2036r2036

r2036で位置指定されていないフロートについては、子孫のボックスを描画したあとに描画するように修正しています。本当はさらにその後で子孫のインラインボックスを描画しないといけないのですが、その修正は9章のテストでは保留しておきます。・float-002 単純なテストなのですが、よく見ると青いボックスがオレンジの枠に接していません。

r2036r2036

#1r1984で行末の空白を削除するようにした際に、インラインボックスの幅だけ調整していて、合わせてラインボックスの幅を調整するのを忘れていたのでした。

r2037r2037

r2037で修正しています。・floats-placement-vertical-003 このテストはモジラから提供されたテストのようですが、良くできているテストでした。

r2037r2037

青いフローティングボックスは1行目には収まらないのですが、その判定がきちんとできているかどうか、さらに、青いボックスが収まらなかったときに続く黄色いフローティングボックスを先に収めてしまわないかどうかをチェックしています。ひとまず1行に収まりきらなかったフロートをきちんと包含ボックス内で処理していなかったバグを修正した段階では下図のようになりました。黄色いフローティングボックスは幅だけ考えれば2つとも1行目に収まってしまうのですが、このように順番を入れ替えたレイアウトはNGというわけです。

r2037 修正中r2037 修正中

r2038でこれらの問題を修正しています。

r2038r2038

モジラのテストは画面中にテストの評価方法を記載しないようで意図を解釈するのにHTMLのソースファイルを見ないといけないのが少し難点ですが、コメントの中には、 Check that we don't allow floats to reorder とあって、あぁ、なるほど、という感じです。・clear-002 フローティング要素にclearプロパティが一緒に設定されている、というパターンのテストです。

r2038r2038

r2038までは、まったく考慮していなかったのでした。r2039で修正しています。

r2039r2039

floats-014 正常なら黒い枠の中にブルーのフローティングボックスが4つとも収まります。

r2040r2040

これはr2038で一部修正ミスがあったのでr2041で修正しています。

r2041r2041

floats-015 このテストも、正常なら黒い枠の中にブルーのフローティングボックスが4つとも収まります。

r2041r2041

フロートの高さを消費していく分の計算にバグがあったのをr2042で修正しました。

r2042r2042

float-006 このテストは9.5の、

Note: this means that floats with zero outer height or negative outer height do not shorten line boxes.

という部分のテストです。配置を計算するときに高さ0のフロートの幅は0として扱うというわけです。

r2039r2039

r2040r2043で、高さ0のフロートを考慮するコードの追加と、幅0フロートをラインボックスに入れることができなかった、というバグを修正しています。

r2043r2043

floats-005 このテストは正常なら縦長のグリーンの長方形がひとつ表示されます。

r2043r2043

まずidセレクタの大文字・小文字の区別の処理が壊れていたのをr2044で修正しました。

r2044r2044

r2044までは、最後までラインボックスに収まりきらなかったフロートは強制的にclearしながら順にレイアウトしていっていたのですが、それだとクリアしなくても収まった筈のフロートの前でも強制的に改行してしまう場面が上図のように出てきてしまいます。この場合だと、最初の赤い部分に最下行の左側の緑の部分が収まる筈だったのです。

r2045,r2046で最後まで残ったフロートも通常通りにレイアウトしていくように修正しました。

r2045r2045

floats-006 画面の説明だけ読むとパスしているように見えてしまうのが難点なのですが、このテストはWebKit系のブラウザも下のr2046と同じように崩れています。

r2046r2046

正しくはFirefoxなどのように3つのボックスが横1列に並びます(オレンジが一番右側)。

r2047r2047

このテストでは、ふつうにレイアウト処理を進めていくと、改行処理を行う直前に行末に空白が1文字残っているのですが、その空白は改行処理で'white-space'の設定に従って取り除かれます。したがって、その分だけラインボックスにスペースが増えるのですが、その増えたスペースをちゃんと利用しないとr2046のように青いボックスがひとつ次の行に回ってしまうのです。r2047でこの問題を修正しています(微妙にずれているように見えるのは既知のAhemフォントのレンダリング側の問題です)。

clear-float-002 このテスト自体はごく単純に'clear: right;'を使っているテストです。

r2047r2047

float-006では、外側の高さが0のフロートは幅も0として扱うという、という修正をしました。そのとき単純にマージンを足し込んで高さを計算していたので、このテストでは高さが -96 (margin-top)+ 96 (height)= 0 となってしまって、幅を0として扱ってしまっていたのでした。 ~~r2048でこの問題を修正しています。~~ 2012/2/17追記 : r2048の修正は誤りで、stack-floats-001など他のテストにPASSできなくなってしまいます。フローティング ボックスの外側の高さは9.5に" floats with zero outer height or negative outer height "という記述がある通り、0未満となっても構いません。そうではなくて、フローティング ボックスの有効な幅を計算する場合は、クリアランスも込みで高さ計算する、という具合に解釈すれば、ほかのフローティング ボックスのテストを崩さずにこのテストも成功するようになるようです。r2419で修正しています。

r2048r2048

floats-101

このテストは、フローティング ボックスを子孫に含んだボックスのshrink-to-fitのテストになっています。

r2048r2048

本来は左側のボックスの中に右側にあるボックスが入っていないといけません。shrink-to-fitをoffにしてみると以下のように描画されて、shrink-to-fitの実装が子孫のフロートを考慮できていないことがわかります。

r2048 (shirik-to-fitをオフ)r2048 (shirik-to-fitをオフ)

r2049でこの問題を修正しました。r2048までは、右のフローティングボックスと右端のインライン要素との間にあるギャップをフローティングボックスの左マージンに足し込んでいたのですが、それだと処理がやっかいになってしまうので、LineBoxクラスにgapというメンバー変数を追加しています。

r2049r2049

floats-122 このテストでは、包含ボックスに2文字分の幅があって、最初に1文字分の幅のフロート(白いボックス)、続いて"X "という2文字からなる緑色のテキストがくるのですが、行末の空白が削除されて、最終的には1行の中にフロートと"X"というテキストが収まり、緑色の正方形だけが見える、というテストです。floats-006では最後にフロートを挿入できたのに対して、このテストではフロートは最初に入れられている点が少し違います。

r2049r2049

r2049では、ふたつバグがあって、ひとつはテキストが1行に収まらないときに1フロート分垂直方向の位置をシフトダウンするときにラインボックスに未挿入のフロートを消失してしまう、というバグ(それで白いボックスが見えていません)。もうひとつは、シフトダウン前に行末の空白が削除できないかどうかチェックしていないというバグです。r2050で前者をまず修正しました。

r2050r2050

ひとまずフロートを消失してしまう問題は解決して、左上に白いフローティングボックスが表示されるようになりました。そして、"X "の2文字分のために改行したけれども、行末の空白が削除されて結局は1行に収まる筈だった、というのが見てわかります。

r2051r2051

r2051でシフトダウン前の行末の処理を修正しました(薄く赤い線が残っているのは例のAhemフォントの描画側の問題です)。

floats-138 このテストでは、正常ならLine 1とLine 2は別の行に表示されます。

r2051r2051

これはまだ修正を進めていないマージンのつぶし処理関連のバグで、すべての場合には対応できていないのですが、r2052でひとまず修正をいれてあります。

r2052r2052

floats-108 このテストはどちらかというと10.3.5のテストかと思います。正常であれば、青いボックスはすべて同じ大きさで描画されなければなりません。

r2052r2052

フロートを配置するときに計算する利用可能な幅( available width )は、単純に包含ブロックの幅から余白等の幅を引いて計算すればよかったのですが、r2052ではわざわざラインボックスに残っている幅を使おうとして崩れていました。CSSのフローティング ボックスは隙間があればなんでもかんでも詰め込む、というわけではなくて、フロートの望ましい幅( preferred width )が収まるだけの幅が包含ブロックにあれば無理はしないで改行しながら詰め込んでいくわけですね。

r2053r2053

r2053でこの問題を修正しています。実際、変に窮屈にボックスを詰め込むよりも、r2053のように表示できた方が読みやすいですね。というわけで、実装済みの機能の範囲では9章のテストについてはだいたいパスするようになりました。そこで9章はひとまず完了にして、次回からは10章のテストスイートに進んでいきます。実際には特定のテストに合わせて加えた修正によって、今までパスしていたテストが失敗するようになってしまったりすることもあります。今の段階では一通りテストスイートをみていって、改めて最初からテストをやり直してみるときに9章の残りのテストも詳しく見ていくことにします。