Found while fixing #342 (#481), which leaves these unchanged.
TagBalancingHtmlStreamEventReceiver.prepareForContent opens implied elements from the current top of the stack before it checks what the top can contain, so a table part arriving in a container that is not a table gets a new table implied there, even when a browser would return to a table already open or ignore the part.
- A row arriving inside a cell's
div starts a new table inside the div; a browser closes the cell and adds the row to the open table:
<table><tr><td><div>x<tr><td>y</td></tr></table>
now: <table><tbody><tr><td><div>x<table><tbody><tr><td>y</td></tr></tbody></table></div></td></tr></tbody></table>
browser: <table><tbody><tr><td><div>x</div></td></tr><tr><td>y</td></tr></tbody></table>
- A row arriving inside a
p with no table open gets a table implied inside the p, and a browser does not keep a table inside a p, so the output re-parses differently and is not idempotent:
<div><p>x<tr><td>y</td></tr>
now: <div><p>x<table><tbody><tr><td>y</td></tr></tbody></table></p></div>
browser reads the output as: <div><p>x</p><table>...</table><p></p></div>
- A row arriving after a bare
col gets a table implied inside the colgroup, again not idempotent:
<table><col><tr><td>y</td></tr></table>
now: <table><colgroup><col /><table><tbody><tr><td>y</td></tr></tbody></table></colgroup></table>
browser: <table><colgroup><col></colgroup><tbody><tr><td>y</td></tr></tbody></table>
The common cause is that the implied-elements step does not ask whether the element it implies can go inside the current top, and does not look for an open table to return to; a browser's "clear the stack back to a table context" does both. #481 added that return for tables it pushed out of the way, and the same walk, guarded by the table-scope boundaries (template, and foreign content once #461 lands), could serve here. Cases 2 and 3 are stability bugs, since the output is read back as a different tree; they are layout rather than safety, since nothing changes parsing context. Reproduced on main at fad01c1.
Found while fixing #342 (#481), which leaves these unchanged.
TagBalancingHtmlStreamEventReceiver.prepareForContentopens implied elements from the current top of the stack before it checks what the top can contain, so a table part arriving in a container that is not a table gets a new table implied there, even when a browser would return to a table already open or ignore the part.divstarts a new table inside thediv; a browser closes the cell and adds the row to the open table:pwith no table open gets a table implied inside thep, and a browser does not keep a table inside ap, so the output re-parses differently and is not idempotent:colgets a table implied inside thecolgroup, again not idempotent:The common cause is that the implied-elements step does not ask whether the element it implies can go inside the current top, and does not look for an open table to return to; a browser's "clear the stack back to a table context" does both. #481 added that return for tables it pushed out of the way, and the same walk, guarded by the table-scope boundaries (
template, and foreign content once #461 lands), could serve here. Cases 2 and 3 are stability bugs, since the output is read back as a different tree; they are layout rather than safety, since nothing changes parsing context. Reproduced onmainat fad01c1.