Fix crash bug 322348 by making ReParentStyleContext more sane. r+sr=dbaron

This commit is contained in:
bzbarsky%mit.edu 2006-03-16 01:30:38 +00:00
parent 403cbe4cd1
commit 4b74ae14f8
6 changed files with 109 additions and 92 deletions

View File

@ -11887,14 +11887,12 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
// Support for :first-line style
static void
ReparentFrame(nsPresContext* aPresContext,
ReparentFrame(nsFrameManager* aFrameManager,
nsIFrame* aNewParentFrame,
nsStyleContext* aParentStyleContext,
nsIFrame* aFrame)
{
aFrame->SetParent(aNewParentFrame);
aPresContext->FrameManager()->ReParentStyleContext(aFrame,
aParentStyleContext);
aFrameManager->ReParentStyleContext(aFrame);
}
// Special routine to handle placing a list of frames into a block
@ -11959,8 +11957,10 @@ nsCSSFrameConstructor::WrapFramesInFirstLineFrame(
// Give the inline frames to the lineFrame <b>after</b> reparenting them
kid = firstInlineFrame;
NS_ASSERTION(lineFrame->GetStyleContext() == firstLineStyle,
"Bogus style context on line frame");
while (kid) {
ReparentFrame(aState.mPresContext, lineFrame, firstLineStyle, kid);
ReparentFrame(aState.mFrameManager, lineFrame, kid);
kid = kid->GetNextSibling();
}
lineFrame->SetInitialChildList(aState.mPresContext, nsnull,
@ -12004,7 +12004,6 @@ nsCSSFrameConstructor::AppendFirstLineFrames(
return rv;
}
nsIFrame* lineFrame = lastBlockKid;
nsStyleContext* firstLineStyle = lineFrame->GetStyleContext();
// Find the first and last inline frame in aFrameItems
nsIFrame* kid = aFrameItems.childList;
@ -12032,7 +12031,7 @@ nsCSSFrameConstructor::AppendFirstLineFrames(
lastInlineFrame->SetNextSibling(nsnull);
kid = firstInlineFrame;
while (kid) {
ReparentFrame(aState.mPresContext, lineFrame, firstLineStyle, kid);
ReparentFrame(aState.mFrameManager, lineFrame, kid);
kid = kid->GetNextSibling();
}
aState.mFrameManager->AppendFrames(lineFrame, nsnull, firstInlineFrame);
@ -12074,12 +12073,10 @@ nsCSSFrameConstructor::InsertFirstLineFrames(
if (firstBlockKid->GetType() == nsLayoutAtoms::lineFrame) {
// We already have a first-line frame
nsIFrame* lineFrame = firstBlockKid;
nsStyleContext* firstLineStyle = lineFrame->GetStyleContext();
if (isInline) {
// Easy case: the new inline frame will go into the lineFrame.
ReparentFrame(aState.mPresContext, lineFrame, firstLineStyle,
newFrame);
ReparentFrame(aState.mFrameManager, lineFrame, newFrame);
aState.mFrameManager->InsertFrames(lineFrame, nsnull, nsnull,
newFrame);
@ -12120,7 +12117,9 @@ nsCSSFrameConstructor::InsertFirstLineFrames(
// Give the inline frames to the lineFrame <b>after</b>
// reparenting them
ReparentFrame(aPresContext, lineFrame, firstLineStyle, newFrame);
NS_ASSERTION(lineFrame->GetStyleContext() == firstLineStyle,
"Bogus style context on line frame");
ReparentFrame(aPresContext, lineFrame, newFrame);
lineFrame->SetInitialChildList(aState.mPresContext, nsnull,
newFrame);
}
@ -12179,8 +12178,7 @@ nsCSSFrameConstructor::InsertFirstLineFrames(
else {
// We got lucky: aPrevSibling was the last inline frame in
// the line-frame.
ReparentFrame(aState.mPresContext, aBlockFrame, firstLineStyle,
newFrame);
ReparentFrame(aState.mFrameManager, aBlockFrame, newFrame);
aState.mFrameManager->InsertFrames(aBlockFrame, nsnull,
prevSiblingParent, newFrame);
aFrameItems.childList = nsnull;

View File

@ -891,82 +891,98 @@ nsFrameManager::DebugVerifyStyleTree(nsIFrame* aFrame)
#endif // DEBUG
nsresult
nsFrameManager::ReParentStyleContext(nsIFrame* aFrame,
nsStyleContext* aNewParentContext)
nsFrameManager::ReParentStyleContext(nsIFrame* aFrame)
{
nsresult result = NS_ERROR_NULL_POINTER;
if (aFrame) {
// DO NOT verify the style tree before reparenting. The frame
// tree has already been changed, so this check would just fail.
nsStyleContext* oldContext = aFrame->GetStyleContext();
if (oldContext) {
nsPresContext *presContext = GetPresContext();
nsRefPtr<nsStyleContext> newContext;
result = NS_OK;
newContext = mStyleSet->ReParentStyleContext(presContext, oldContext,
aNewParentContext);
if (newContext) {
if (newContext != oldContext) {
PRInt32 listIndex = 0;
nsIAtom* childList = nsnull;
nsIFrame* child;
// DO NOT verify the style tree before reparenting. The frame
// tree has already been changed, so this check would just fail.
nsStyleContext* oldContext = aFrame->GetStyleContext();
// XXXbz can oldContext really ever be null?
if (oldContext) {
nsPresContext *presContext = GetPresContext();
nsRefPtr<nsStyleContext> newContext;
nsIFrame* providerFrame = nsnull;
PRBool providerIsChild = PR_FALSE;
nsIFrame* providerChild = nsnull;
aFrame->GetParentStyleContextFrame(presContext, &providerFrame,
&providerIsChild);
nsStyleContext* newParentContext = nsnull;
if (providerIsChild) {
ReParentStyleContext(providerFrame);
newParentContext = providerFrame->GetStyleContext();
providerChild = providerFrame;
} else if (providerFrame) {
newParentContext = providerFrame->GetStyleContext();
} else {
NS_NOTREACHED("Reparenting something that has no usable parent? "
"Shouldn't happen!");
}
newContext = mStyleSet->ReParentStyleContext(presContext, oldContext,
newParentContext);
if (newContext) {
if (newContext != oldContext) {
PRInt32 listIndex = 0;
nsIAtom* childList = nsnull;
nsIFrame* child;
aFrame->SetStyleContext(newContext);
aFrame->SetStyleContext(newContext);
do {
child = aFrame->GetFirstChild(childList);
while (child) {
if (NS_FRAME_OUT_OF_FLOW != (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
// only do frames that are in flow
if (nsLayoutAtoms::placeholderFrame == child->GetType()) {
// get out of flow frame and recurse there
nsIFrame* outOfFlowFrame =
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
do {
child = aFrame->GetFirstChild(childList);
while (child) {
// only do frames that are in flow
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
if (nsLayoutAtoms::placeholderFrame == child->GetType()) {
// get out of flow frame and recurse there
nsIFrame* outOfFlowFrame =
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
result = ReParentStyleContext(outOfFlowFrame, newContext);
NS_ASSERTION(outOfFlowFrame != providerChild,
"Out of flow provider?");
// reparent placeholder's context under out of flow frame
nsStyleContext* outOfFlowContext = outOfFlowFrame->GetStyleContext();
ReParentStyleContext(child, outOfFlowContext);
}
else { // regular frame
result = ReParentStyleContext(child, newContext);
}
ReParentStyleContext(outOfFlowFrame);
// reparent placeholder too
ReParentStyleContext(child);
}
child = child->GetNextSibling();
}
childList = aFrame->GetAdditionalChildListName(listIndex++);
} while (childList);
// do additional contexts
PRInt32 contextIndex = -1;
while (1) {
nsStyleContext* oldExtraContext = aFrame->GetAdditionalStyleContext(++contextIndex);
if (oldExtraContext) {
nsRefPtr<nsStyleContext> newExtraContext;
newExtraContext = mStyleSet->ReParentStyleContext(presContext,
oldExtraContext,
newContext);
if (newExtraContext) {
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
else if (child != providerChild) {
// regular frame, not reparented yet
ReParentStyleContext(child);
}
}
else {
result = NS_OK; // ok not to have extras (or run out)
break;
child = child->GetNextSibling();
}
childList = aFrame->GetAdditionalChildListName(listIndex++);
} while (childList);
// do additional contexts
PRInt32 contextIndex = -1;
while (1) {
nsStyleContext* oldExtraContext =
aFrame->GetAdditionalStyleContext(++contextIndex);
if (oldExtraContext) {
nsRefPtr<nsStyleContext> newExtraContext;
newExtraContext = mStyleSet->ReParentStyleContext(presContext,
oldExtraContext,
newContext);
if (newExtraContext) {
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
}
}
#ifdef DEBUG
VerifyStyleTree(GetPresContext(), aFrame, aNewParentContext);
#endif
else {
break;
}
}
#ifdef DEBUG
VerifyStyleTree(GetPresContext(), aFrame, newParentContext);
#endif
}
}
}
return result;
return NS_OK;
}
static nsChangeHint

View File

@ -158,13 +158,14 @@ public:
NS_HIDDEN_(void) NotifyDestroyingFrame(nsIFrame* aFrame);
/*
* Reparent the style contexts of this frame subtree to live under the new
* given parent style context. The StyleContextParent of aFrame should be
* changed _before_ this method is called, so that style tree verification
* can take place correctly.
* Reparent the style contexts of this frame subtree. The parent frame of
* aFrame must be changed to the new parent before this function is called;
* the new parent style context will be automatically computed based on the
* new position in the frame tree.
*
* @param aFrame the root of the subtree to reparent. Must not be null.
*/
NS_HIDDEN_(nsresult) ReParentStyleContext(nsIFrame* aFrame,
nsStyleContext* aNewParentContext);
NS_HIDDEN_(nsresult) ReParentStyleContext(nsIFrame* aFrame);
/*
* Re-resolve the style contexts for a frame tree. Returns the top-level

View File

@ -690,11 +690,10 @@ nsFieldSetFrame::MaybeSetLegend(nsIFrame* aFrameList, nsIAtom* aListName)
void
nsFieldSetFrame::ReParentFrameList(nsIFrame* aFrameList)
{
nsFrameManager* frameManager = mContentFrame->GetPresContext()->FrameManager();
nsStyleContext* newParentContext = mContentFrame->GetStyleContext();
nsFrameManager* frameManager = GetPresContext()->FrameManager();
for (nsIFrame* frame = aFrameList; frame; frame = frame->GetNextSibling()) {
frame->SetParent(mContentFrame);
frameManager->ReParentStyleContext(frame, newParentContext);
frameManager->ReParentStyleContext(frame);
}
mContentFrame->AddStateBits(GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
}

View File

@ -146,7 +146,8 @@ nsFirstLetterFrame::SetInitialChildList(nsPresContext* aPresContext,
nsFrameManager *frameManager = aPresContext->FrameManager();
for (nsIFrame* frame = aChildList; frame; frame = frame->GetNextSibling()) {
frameManager->ReParentStyleContext(frame, mStyleContext);
NS_ASSERTION(frame->GetParent() == this, "Unexpected parent");
frameManager->ReParentStyleContext(frame);
}
return NS_OK;
}

View File

@ -844,14 +844,15 @@ NS_IMETHODIMP nsInlineFrame::GetAccessible(nsIAccessible** aAccessible)
static void
ReParentChildListStyle(nsPresContext* aPresContext,
nsStyleContext* aParentStyleContext,
nsFrameList& aFrameList)
nsFrameList& aFrameList,
nsIFrame* aParentFrame)
{
nsFrameManager *frameManager = aPresContext->FrameManager();
for (nsIFrame* kid = aFrameList.FirstChild(); kid;
kid = kid->GetNextSibling()) {
frameManager->ReParentStyleContext(kid, aParentStyleContext);
NS_ASSERTION(kid->GetParent() == aParentFrame, "Bogus parentage");
frameManager->ReParentStyleContext(kid);
}
}
@ -898,7 +899,8 @@ nsFirstLineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowState& i
if (frame && !GetPrevInFlow()) {
// We are a first-line frame. Fixup the child frames
// style-context that we just pulled.
aPresContext->FrameManager()->ReParentStyleContext(frame, mStyleContext);
NS_ASSERTION(frame->GetParent() == this, "Incorrect parent?");
aPresContext->FrameManager()->ReParentStyleContext(frame);
}
return frame;
}
@ -921,7 +923,7 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
nsFrameList frames(prevOverflowFrames);
mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
ReParentChildListStyle(aPresContext, mStyleContext, frames);
ReParentChildListStyle(aPresContext, frames, this);
}
}
@ -932,7 +934,7 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
nsFrameList frames(overflowFrames);
mFrames.AppendFrames(nsnull, overflowFrames);
ReParentChildListStyle(aPresContext, mStyleContext, frames);
ReParentChildListStyle(aPresContext, frames, this);
}
// Set our own reflow state (additional state above and beyond
@ -993,7 +995,7 @@ nsFirstLineFrame::Reflow(nsPresContext* aPresContext,
SetStyleContext(newSC);
// Re-resolve all children
ReParentChildListStyle(aPresContext, mStyleContext, mFrames);
ReParentChildListStyle(aPresContext, mFrames, this);
}
}
}