| <!DOCTYPE html> |
| <ruby> |
| <div></div> |
| <span id="firstInline"></span> |
| <rt id="rubyText" style="display:none;"></rt> |
| <span id="secondInline"></span> |
| <div id="removeMe"></div> |
| <div id="absPos" style="position:absolute;"></div> |
| <span id="addMe" style="display:none;"></span> |
| </ruby> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script> |
| // The comments describe what happens with crbug.com/852640 present. |
| test(() => { |
| // Perform 4 style changes. Relayout before and between each |
| // change. |
| document.body.offsetTop; |
| // Remove a regular block. Its previous and next siblings are an inline |
| // and an absolutely positioned object, respectively. They should be |
| // placed together, i.e. the absolutely positioned object should be put |
| // under the anonymous block around the inline. That's what would have |
| // happened if the style were like this during initial layout. Getting |
| // to the same style situation via DOM changes should result in the |
| // exact same tree. With the bug present, we just leave the absolutely |
| // positioned box alone, and keep it as a *sibling* (instead of making |
| // it a child, which would have been the correct thing) of the |
| // anonoymous wrapper around #firstInline and #secondInline. |
| document.getElementById("removeMe").style.display = "none"; |
| document.body.offsetTop; |
| // Add an inline after the absolutely positioned box. It finds no |
| // adjacent anonymous wrapper block (there's just #absPos, and it's not |
| // inside a wrapper), so it creates one, and puts itself and #absPos |
| // inside it. Now we have two sibling anonymous wrapper blocks (one with |
| // #firstInline and #secondInline, and one with #absPos and #addMe), |
| // which is weird. |
| document.getElementById("addMe").style.display = "inline"; |
| document.body.offsetTop; |
| // Insert an RT object between #firstInline and #secondInline. This will |
| // split the ruby run and the ruby base in two; one run and base that |
| // ends with #firstChild, and one run and base that starts with |
| // #secondChild. We now have a first ruby base that ends with an |
| // anonymous block (to contain #firstInline), and a second ruby base |
| // that starts with an anonymous block (to contain #secondInline). This |
| // is fine. |
| document.getElementById("rubyText").style.display = "block"; |
| document.body.offsetTop; |
| // Remove the RT object again. This will cause the two ruby runs and |
| // bases to be merged back into one. There is code that carefully makes |
| // sure that the anonymous block at the end of the first base is merged |
| // with the anonymous block at the start of the next base. This is the |
| // right thing to do, since we want the two inlines back on one and the |
| // same line. However, this will cause the first anonymous block in the |
| // second base to be destroyed (because its contents, |
| // i.e. #secondInline, is moved over to the anonymous block around |
| // #firstInline). This in turn will leave the second base with one |
| // anonymous block (around #absPos and #addMe). Our tree modification |
| // machinery will detect this and unwrap #absPos and #addMe from their |
| // anonymous block and destroy it. The second base will now be marked as |
| // "children inline", while the first base is still marked as having |
| // block children. This could be fine, but if we now just move the |
| // children of the second base directly into the first base, we're going |
| // to end up with a mix of block and inline children within the same |
| // block, and that's not allowed. |
| document.getElementById("rubyText").style.display = "none"; |
| }, "No crash or CHECK/DCHECK failure."); |
| </script> |