If we dump "ColumnSet" log via `MOZ_LOG=ColumnSet:5 ./mach run`, the assertion happens in the fourth grid container in the second iteration of column balancing. ``` GridContainer(summary):frag3 content:frag1 Block OverflowList< video > OverflowContainerList > content:frag2 <empty> > GridContainer(summary):frag4 <-- Assertion happens in SanityCheckChildListsBeforeReflow at the beginning of reflow. <empty> ``` The Content doesn't fit since it has overflow list. However the Content has a next-in-flow in grid frag3's OC list (created in the first iteration of column balancing). This looks wrong. If it is incomplete, it's next-in-flow should be in OverflowList; if it is overflow-incomplete, its next-in-flow should be in ExcessOverflowContainerList. In both cases, it's next-in-flow is expected to be drained by frag4. So let's rewind back to take a look at the frame tree at the beginning of the second column balancing iteration. =========================================== Frame tree before we call NormalizeChildLists() on frag1. This is the result at the end of the first iteration of the column balancing. ``` GridContainer(summary):frag1 <-- At here, before calling NormalizeChildLists() Block GridContainer(summary):frag2 Link GridContainer(summary):frag3 OverflowContainerList< Content:frag1 Block > GridContainer(summary):frag4 OverflowContainerList< Content:frag2 Video > ``` =========================================== After we call NormalizeChildLists() on grid's frag 1, all the children's first-in-flows are pulled up to frag1's principal child list, and the Content's frag2 is put in grid frag2's ExcessOverflowContainerList because it is a overflow container. ``` GridContainer(summary):frag1 <-- At here, after calling NormalizeChildLists() Block Link Content:frag1 Block GridContainer(summary):frag2 ExcessOverflowContainerList< Content:frag2 Video > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ``` =========================================== After reflowing frag1, Link and Content cannot fit, and is on frag1's overflow list. So, after calling NormalizeChildLists() for frag2, they're pulled from frag1. ``` GridContainer(summary):frag1 Block GridContainer(summary):frag2 <-- At here, after calling NormalizeChildLists() Link Content:frag1 Block ExcessOverflowContainerList< Content:frag2 Video > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ``` Note: Content:frag2 is still in ExcessOverflowContainerList after DrainExcessOverflowContainersList() because we don't drain the child in self excess overflow containers list if it's prev-in-flow has the same parent. (In this case both Content:frag1 and Content:frag2 has the same parent.) So Content:frag2 won't reflow until frag3 pulls it, which is pretty bad ... =========================================== After my proposed fix, the frame tree after we call NormalizeChildLists() on grid's frag 1 should look like this. That is, we remove the NS_FRAME_IS_OVERFLOW_CONTAINER bit for Content:frag2, and put it in grid frag2's OverflowList. The rationale is that Content:frag2 should start from scratch and it doesn't necessary a overflow container. If it needs to be a overflow container after reflow, PushIncompleteChildren() will add the bit, and move it to a proper child list. ``` GridContainer(summary):frag1 <-- At here, after calling NormalizeChildLists() Block Link Content:frag1 GridContainer(summary):frag2 OverflowList< <-- After the fix. Content:frag2 > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ```
Bug 1405813 Comment 3 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
If we dump "ColumnSet" log via `MOZ_LOG=ColumnSet:5 ./mach run`, the assertion happens in the fourth grid container in the second iteration of column balancing. ``` GridContainer(summary):frag3 content:frag1 Block OverflowList< video > OverflowContainerList > content:frag2 <empty> > GridContainer(summary):frag4 <-- Assertion happens in SanityCheckChildListsBeforeReflow at the beginning of reflow. <empty> ``` The Content doesn't fit since it has overflow list. However the Content has a next-in-flow in grid frag3's OC list (created in the first iteration of column balancing). This looks wrong. If it is incomplete, it's next-in-flow should be in OverflowList; if it is overflow-incomplete, its next-in-flow should be in ExcessOverflowContainerList. In both cases, it's next-in-flow is expected to be drained by frag4. So let's rewind back to take a look at the frame tree at the beginning of the second column balancing iteration. =========================================== Frame tree before we call NormalizeChildLists() on frag1. This is the result at the end of the first iteration of the column balancing. ``` GridContainer(summary):frag1 <-- At here, before calling NormalizeChildLists() Block GridContainer(summary):frag2 Link GridContainer(summary):frag3 OverflowContainerList< Content:frag1 Block > GridContainer(summary):frag4 OverflowContainerList< Content:frag2 Video > ``` =========================================== After we call NormalizeChildLists() on grid's frag 1, all the children's first-in-flows are pulled up to frag1's principal child list, and the Content's frag2 is put in grid frag2's ExcessOverflowContainerList because it is a overflow container. ``` GridContainer(summary):frag1 <-- At here, after calling NormalizeChildLists() Block Link Content:frag1 Block GridContainer(summary):frag2 ExcessOverflowContainerList< Content:frag2 Video > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ``` =========================================== After reflowing frag1, Link and Content cannot fit, and is on frag1's overflow list. So, after calling NormalizeChildLists() for frag2, they're pulled from frag1. ``` GridContainer(summary):frag1 Block GridContainer(summary):frag2 <-- At here, after calling NormalizeChildLists() Link Content:frag1 Block ExcessOverflowContainerList< Content:frag2 Video > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ``` ~~Note: Content:frag2 is still in ExcessOverflowContainerList after~~ ~~DrainExcessOverflowContainersList() because we don't drain the child in self~~ ~~excess overflow containers list if it's prev-in-flow has the same parent. (In~~ ~~this case both Content:frag1 and Content:frag2 has the same parent.) So~~ ~~Content:frag2 won't reflow until frag3 pulls it, which is pretty bad ...~~ (Edit: See mat's response in comment 5, which makes more sense) =========================================== ~~After my proposed fix, the frame tree after we call NormalizeChildLists() on~~ ~~grid's frag 1 should look like this. That is, we remove the~~ ~~NS_FRAME_IS_OVERFLOW_CONTAINER bit for Content:frag2, and put it in grid frag2's~~ ~~OverflowList. The rationale is that Content:frag2 should start from scratch and~~ ~~it doesn't necessary a overflow container. If it needs to be a overflow~~ ~~container after reflow, PushIncompleteChildren() will add the bit, and move it~~ ~~to a proper child list.~~ ``` GridContainer(summary):frag1 <-- At here, after calling NormalizeChildLists() Block Link Content:frag1 GridContainer(summary):frag2 OverflowList< <-- After the fix. Content:frag2 > GridContainer(summary):frag3 <empty> GridContainer(summary):frag4 <empty> ```