mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 18:08:58 +00:00
Fix StirDOM/MathML crash bug 309120, r+sr=dbaron
This commit is contained in:
parent
b4e783a07a
commit
782d9b827b
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user