Fix StirDOM/MathML crash bug 309120, r+sr=dbaron

This commit is contained in:
rbs%maths.uq.edu.au 2006-01-04 07:29:09 +00:00
parent b4e783a07a
commit 782d9b827b
6 changed files with 95 additions and 81 deletions

View File

@ -695,51 +695,6 @@ nsMathMLContainerFrame::PropagateScriptStyleFor(nsIFrame* aFrame,
* =============================================================================
*/
// We use this to wrap non-MathML frames so that foreign elements (e.g.,
// html:img) can mix better with other surrounding MathML markups.
// Currently we only wrap nsInlineFrames because problems were observed only
// in the presence of such frames. By construction, a foreign frame wrapper
// has one and only one child, and the life of the wrapper is bound to the
// life of that unique child. Not all child list operations are applicable
// with a wrapper. One must either use the parent (or the unique child)
// for such operations (@see nsMathMLForeignFrameWrapper).
nsresult
nsMathMLContainerFrame::WrapForeignFrames()
{
nsIFrame* next = mFrames.FirstChild();
nsPresContext* presContext = GetPresContext();
nsFrameManager *frameManager = presContext->FrameManager();
while (next) {
nsIFrame* child = next;
next = next->GetNextSibling();
nsInlineFrame* inlineFrame;
child->QueryInterface(kInlineFrameCID, (void**)&inlineFrame);
if (inlineFrame) {
// create a new wrapper frame to wrap this child
nsIFrame* wrapper = NS_NewMathMLForeignFrameWrapper(presContext->PresShell());
if (NS_UNLIKELY(!wrapper)) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsRefPtr<nsStyleContext> newStyleContext;
newStyleContext = presContext->StyleSet()->
ResolvePseudoStyleFor(mContent,
nsCSSAnonBoxes::mozAnonymousBlock,
mStyleContext);
nsresult rv = wrapper->Init(presContext, mContent, this, newStyleContext, nsnull);
if (NS_FAILED(rv)) {
wrapper->Destroy(presContext);
return rv;
}
mFrames.ReplaceFrame(this, child, wrapper, PR_FALSE);
child->SetParent(wrapper);
child->SetNextSibling(nsnull);
frameManager->ReParentStyleContext(child, newStyleContext);
wrapper->SetInitialChildList(presContext, nsnull, child);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsMathMLContainerFrame::Paint(nsPresContext* aPresContext,
@ -814,22 +769,8 @@ nsMathMLContainerFrame::SetInitialChildList(nsPresContext* aPresContext,
nsIAtom* aListName,
nsIFrame* aChildList)
{
// First, let the base class do its job
nsresult rv = nsHTMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
// Next, since we are an inline frame, and since we are a container, we have to
// be very careful with the way we treat our children. Things look okay when
// all of our children are only MathML frames. But there are problems if one of
// our children happens to be an nsInlineFrame, e.g., from generated content such
// as :before { content: open-quote } or :after { content: close-quote }
// The code asserts during reflow (in nsLineLayout::BeginSpan)
// Also there are problems when our children are hybrid, e.g., from html markups.
// In short, the nsInlineFrame class expects a number of *invariants* that are not
// met when we mix things.
// So wrap foreign children in nsMathMLForeignFrameWrapper frames
WrapForeignFrames();
return rv;
// let the base class do its job
return nsHTMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
// ...We will build our automatic MathML data once the entire <math>...</math>
// tree is constructed.
@ -930,10 +871,7 @@ nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
nsresult
nsMathMLContainerFrame::ChildListChanged(PRInt32 aModType)
{
if (aModType != nsIDOMMutationEvent::REMOVAL) {
// wrap any new foreign child that may have crept in
WrapForeignFrames();
}
mState |= NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN;
// If this is an embellished frame we need to rebuild the
// embellished hierarchy by walking-up to the parent of the
@ -942,6 +880,7 @@ nsMathMLContainerFrame::ChildListChanged(PRInt32 aModType)
if (mEmbellishData.coreFrame) {
nsEmbellishData embellishData;
for (frame = mParent; frame; frame = frame->GetParent()) {
frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
GetEmbellishDataFrom(frame, embellishData);
if (embellishData.coreFrame != mEmbellishData.coreFrame)
break;
@ -1049,6 +988,74 @@ nsMathMLContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aCh
return NS_OK;
}
nsresult
nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame,
nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
aDesiredSize.width = aDesiredSize.height = 0;
aDesiredSize.ascent = aDesiredSize.descent = 0;
aDesiredSize.mBoundingMetrics.Clear();
aDesiredSize.mFlags |= NS_REFLOW_CALC_BOUNDING_METRICS;
// Having foreign/hybrid children, e.g., from html markups, is not defined by
// the MathML spec. But it can happen in practice, e.g., <html:img> allows us
// to do some cool demos... or we may have a child that is an nsInlineFrame
// from a generated content such as :before { content: open-quote } or
// :after { content: close-quote }. Unfortunately, the other frames out-there
// may expect their own invariants that are not met when we mix things.
// Hence we do not claim their support, but we will nevertheless attempt to keep
// them in the flow, if we can get their desired size. We observed that most
// frames may be reflowed generically, but nsInlineFrames need extra care.
nsInlineFrame* inlineFrame;
aChildFrame->QueryInterface(kInlineFrameCID, (void**)&inlineFrame);
if (!inlineFrame)
return nsHTMLContainerFrame::
ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowState,
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
// extra care for an nsInlineFrame
return ReflowForeignChild(aChildFrame, aPresContext, aDesiredSize, aReflowState, aStatus);
}
nsresult
nsMathMLContainerFrame::ReflowForeignChild(nsIFrame* aChildFrame,
nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
// don't bother trying to span words as if they were non-breaking beyond this point
if (aReflowState.mLineLayout)
aReflowState.mLineLayout->ForgetWordFrames();
// provide a local, self-contained linelayout where to reflow the nsInlineFrame
nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsLineLayout ll(aPresContext, aReflowState.mSpaceManager, aReflowState.parentReflowState,
aDesiredSize.mComputeMEW);
ll.BeginLineReflow(0, 0, availSize.width, availSize.height, PR_FALSE, PR_FALSE);
PRBool pushedFrame;
ll.ReflowFrame(aChildFrame, aStatus, &aDesiredSize, pushedFrame);
NS_ASSERTION(!pushedFrame, "unexpected");
ll.EndLineReflow();
// make up the bounding metrics from the reflow metrics.
aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.ascent;
aDesiredSize.mBoundingMetrics.descent = aDesiredSize.descent;
aDesiredSize.mBoundingMetrics.width = aDesiredSize.width;
aDesiredSize.mBoundingMetrics.rightBearing = aDesiredSize.width;
// Note: MathML's vertical & horizontal alignments happen much later in
// Place(), which is ultimately called from within FinalizeReflow().
aStatus = NS_FRAME_COMPLETE;
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return NS_OK;
}
NS_IMETHODIMP
nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -1079,8 +1086,10 @@ printf("\n");
aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS);
nsIFrame* childFrame = mFrames.FirstChild();
while (childFrame) {
nsReflowReason reason = (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
? eReflowReason_Initial : aReflowState.reason;
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
childFrame, availSize);
childFrame, availSize, reason);
rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
childReflowState, childStatus);
//NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");

View File

@ -204,11 +204,6 @@ public:
virtual nsresult
ChildListChanged(PRInt32 aModType);
// helper to wrap non-MathML frames so that foreign elements (e.g., html:img)
// can mix better with other surrounding MathML markups
virtual nsresult
WrapForeignFrames();
// helper to get the preferred size that a container frame should use to fire
// the stretch on its stretchy child frames.
virtual void
@ -235,11 +230,14 @@ public:
nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
return nsHTMLContainerFrame::ReflowChild(aKidFrame, aPresContext, aDesiredSize, aReflowState,
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
}
nsReflowStatus& aStatus);
nsresult
ReflowForeignChild(nsIFrame* aKidFrame,
nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
// helper to add the inter-spacing when <math> is the immediate parent.
// Since we don't (yet) handle the root <math> element ourselves, we need to

View File

@ -171,8 +171,10 @@ printf("\n");
PRInt32 count = 0;
nsIFrame* childFrame = GetFirstChild(nsnull);
while (childFrame) {
nsReflowReason reason = (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
? eReflowReason_Initial : aReflowState.reason;
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
childFrame, availSize);
childFrame, availSize, reason);
rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
childReflowState, aStatus);
//NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");

View File

@ -299,7 +299,9 @@ nsMathMLmactionFrame::Reflow(nsPresContext* aPresContext,
nsIFrame* childFrame = GetSelectedFrame();
if (childFrame) {
nsReflowReason reason = aReflowState.reason;
if (mWasRestyled) {
if (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
reason = eReflowReason_Initial;
else if (mWasRestyled) {
mWasRestyled = PR_FALSE;
// If we have just been restyled, make sure to reflow our
// selected child with a StyleChange reflow reason so that

View File

@ -131,7 +131,6 @@ nsMathMLmfencedFrame::RemoveFencesAndSeparators()
nsresult
nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
{
nsresult rv;
nsAutoString value;
PRBool isMutable = PR_FALSE;
@ -300,8 +299,10 @@ nsMathMLmfencedFrame::doReflow(nsPresContext* aPresContext,
fm->GetMaxDescent(aDesiredSize.descent);
}
while (childFrame) {
nsReflowReason reason = (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
? eReflowReason_Initial : aReflowState.reason;
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
childFrame, availSize);
childFrame, availSize, reason);
rv = mathMLFrame->ReflowChild(childFrame, aPresContext, childDesiredSize,
childReflowState, childStatus);
//NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");

View File

@ -197,8 +197,10 @@ nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics indexSize(nsnull);
nsIFrame* childFrame = mFrames.FirstChild();
while (childFrame) {
nsReflowReason reason = (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
? eReflowReason_Initial : aReflowState.reason;
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
childFrame, availSize);
childFrame, availSize, reason);
rv = ReflowChild(childFrame, aPresContext,
childDesiredSize, childReflowState, childStatus);
//NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");