- From: Boris Zbarsky <bzbarsky@MIT.EDU>
- Date: Sat, 30 May 2009 02:59:48 -0400
- To: www-style list <www-style@w3.org>
I've recently been working on Gecko's support for section 17.2.1 of CSS2.1 (table anonymous objects), and I've run into a number of cases where behavior is underdefined, or not defined the way browsers actually implement it. I've posted about some of these issues in the past. I've decided to write up a proposal based on what I've ended up implementing in Gecko. The technical issues I'm trying to address are the following: 1) Various underdefined behavior wrt whitespace handing, definitions of adjacent, and so forth. 2) The following testcase is interoperably rendered by IE8, Gecko, Webkit, and Presto in a way that does not match the current spec: <!DOCTYPE html> <body> <div style="display: table"> <div style="display: table-cell">1</div> <div>2</div> <div style="display: table-cell">3</div> </div> </body> (per spec there should be three rows in that table, while implementations only have one). My proposal aligns with implementations here. 3) Handling of out-of-flow children (whatever that means) of table-related boxes is not well defined. Some experimentation shows that this testcase: <!DOCTYPE html> <body> <table> <tr> <td>One</td><td>Two</td><td>Three</td><td>Four</td> </tr> <tr> <td>1</td> <td style="position:absolute; top: 200px">2</td> <td style="position:absolute; top: 200px">3</td> <td>4</td> </tr> </table> </body> is rendered interoperably by IE8, Gecko, Presto, and Webkit in the following manner: the boxes containing "2" and "3" are positioned on top of each other 200px below the table, and the cell containing "4" is placed in the third column. The behavior does not change if <span>s with CSS table display types are used in the testcase, and the above markup is more readable, so I used it for the example. In IE7, the cell containing "4" is placed in the second column, not the third one. If, in the same testcase, I replace "position: absolute" with "float: left", then rendering is again interoperable in Webkit, Gecko, Presto, and IE8. The "2" and "3" are both placed into the second column; the "4" is placed into the third column. Again, changing to using <span>s with appropriate display values does not affect the behavior in terms of which things end up in which columns. Again, my proposal aligns with implementations on this issue. With all that in mind, here is the proposal: =================================================================== Definitions: 1) A non-replaced box is called "table-related-inside" if its value of the "display" property is one of 'table', 'inline-table', 'table-row-group', 'table-header-group', 'table-footer-group', or 'table-row'. 2) A box is called "table-related-outside" if its value of the "display" property is one of 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-column-group', 'table-column, 'table-cell', or 'table-caption'. 3) Two boxes which have the same parent box and are both in-flow are "adjacent" if there are no boxes between them in the parent's in-flow list. This is a little fuzzy, but the entire box tree definition is pretty fuzzy. I can pin this down more in terms of Gecko's implementation, but that seems ... imperfect. I welcome ideas on how to make this concept (which I think there's general agreement on amongst implementors) clearer. 4) A nonempty set of in-flow boxes is called "consecutive" if all elements of the set have the same parent, and if no box not in the set is adjacent to two different boxes in the set. The parent of a consecutive set of boxes is well-defined: it is the parent of any box in the set. 5) For a consecutive set of boxes S, we say "wrap set S in box B" to mean that box B is placed in the in-flow child list of the parent of S immediately before the first box belonging to S and then all boxes in S are removed from their parent's in-flow child list and inserted into B's in-flow child list. This operation preserves the order of the boxes in S. 6) A box is a "valid table child" if it is a 'table-row-group', 'table-header-group', 'table-footer-group', 'table-caption', 'table-column-group', 'table-column', or 'table-row' box. 7) A box is "discardable" if it is generated by a Text node that contains only whitespace. The value of the 'white-space' property does not affect whether a box is discardable. 8) To "discard" a box means to remove it from the box tree. It, and any child boxes it might have, are not rendered. Anonymous table objects are generated according to the following rules: 1) For every out-of-flow box T which would be a child of a table-related-inside box P if T were in-flow, insert an inline box with width and height 0 in the child list of P at the position where T would appear if it were in-flow. If this inline box is ever discarded, also discard the out-of-flow box T. The inline box is called the "placeholder" of T. 2) Discard all child boxes of 'table-column' boxes. 3) If a box T is not a 'table-column' box and has a parent P which is a 'table-column-group' box, discard T. 4) If a box P that is not table-related-inside has an in-flow child box T that is table-related-outside, generate a box P'. P' must be an 'inline-table' box if P is 'inline' and a 'table' box otherwise. Take the maximal consecutive set of boxes which contains T and consists only of boxes that are table-related-outside and wrap this set in P'. 5) If a box P is a 'table' or 'inline-table' box and has a child T which is not a valid table child, generate a 'table-row' box P'. Take the maximal consecutive set of boxes which contains T and consists only of boxes that are not valid table child boxes, and wrap this set in P'. If P' now has only one child and this child is discardable, discard P'. 6) If a box P is a 'table-row-group', 'table-header-group', or 'table-footer-group' box and contains a child T which is not a 'table-row' box, generate a 'table-row' box P'. Take the maximal consecutive set of boxes which contains T and consists only of boxes that are not 'table-row' boxes, and wrap this set in P'. If P' now has only one child and this child is discardable, discard P'. 7) If a box P is a 'table-row' box and contains a child T which is not a 'table-cell' box, generate a 'table-cell' box P'. Take the maximal consecutive set of boxes which contains T and consists only of boxes that are not 'table-cell' boxes, and wrap this set in P'. If P' now has only one child and this child is discardable, discard P'. Otherwise, if P' now has an in-flow child box which is the placeholder for a box S and S has a computed value of 'float' other than 'none', then P' becomes the containing block os S. 8) Continue applying rules 4-7 until a pass through all four rules yields no changes to the box tree. =================================================================== Note that rules 4-7 can actually be applied in any order desired, or even concurrently, since each rule can only affect the child lists of a certain set of boxes and the four sets are disjoint. An alternate stopping condition for rule 8 is to keep applying rules 4-7 until there are no "impedance mismatches" or whatever you want to call situations with missing boxes; one would then need to define that term. I think the stopping condition used in the proposal above is simpler to state and sufficiently well-defined; in practice it's pretty clear when one is done with this algorithm. I have posted some tests for the above algorithm at <http://test.csswg.org/svn/submitted/css2.1/tables/>. The tests do pass in current Gecko development builds; all other browsers I have tried (including Gecko before I started working on this, of course) fail at least some of these, especially the ones that test dynamic changes or whitespace handling. The same tests are available as HTML files one can just load at <http://web.mit.edu/bzbarsky/www/testcases/table-anonymous-objects/>. Sadly, that TLD is on IE8's "pretend to be IE7" list, so those wishing to try the tests in IE8 will have to copy them elsewhere. I welcome any feedback on either the above proposal or the tests; I make no guarantees about either of them being bug-free, or about the tests correctly testing the rules above, though I did try to make sure of all of that. I'm fairly certain the tests don't test the rules exhaustively, of course. -Boris
Received on Saturday, 30 May 2009 07:00:29 UTC