Created attachment 419132 [details]
###!!! ASSERTION: Placeholder relationship should have been torn down already; this might mean we have a stray placeholder in the tree.: '!placeholder || nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder)', file /Users/jruderman/central/layout/generic/nsFrame.cpp, line 443
This assertion was added in rev 1e37be566afa:
date: Thu Dec 24 00:21:15 2009 -0500
summary: Bug 508473 part III: Pass destruction root to frame destruction methods r=bz sr=roc
layout/base/crashtests/243519-1.html hits this assertion too.
Need this fixed so we can backport frame destruction cleanup to branch.
So the problem here is that when we have a fixed-positioned table, it's not capturing any of its abspos out-of-flows. It keeps the placeholder, but the abspos jumps out to the CanvasFrame, which is not an ancestor of the fixedpos element. Thus frame destruction gets confused.
Here's the frame tree (columns and scrollbars cut out for simplicity):
Everything *is* eventually getting destroyed correctly, because we eventually get to the placeholder for the table frame, and that gets us to the fixedpos table and the abspos frame's placeholder. We're not hitting it in the right order because the fixed list is outside the parent of the CanvasFrame, which is destroying its abspos list before its contents.
One correct fix for this bug is to make one of the table frames capture OOFs. In other words, fix bug 63895. Probably the easiest would be to have the anonymous block inside a table cell pretend it has position: relative whenever its closest element ancestor has position != static.
Another fix for this bug would be to destroy the main child lists before the abspos/fixed lists. But this is difficult to do because the child lists tend to get destroyed by a call to the superclass destructor, which eventually hits nsFrame::Destroy, which has code that must be executed last in the Destroy() order of operations. (In other words, we can't move the the regular child list destruction calls before the abspos/fixed list destruction calls because the child list destruction calls are bundled in the superclass destructor--which must be called last.) To flex the order we'd have to unbundle "destroy all your children" from "destroy yourself". (Both responsibilities are combined under the current Destroy() design.)
My patches in bug 10209 are going to fix this bug, I believe.
I pushed a crashtest for this in http://hg.mozilla.org/mozilla-central/rev/34f184d2a6f8.