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 ...

===========================================

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>
```
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>
```

Back to Bug 1405813 Comment 3