michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsMathMLContainerFrame.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsIDOMMutationEvent.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsIReflowCallback.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "nsIScriptError.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsMathMLElement.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // michael@0: // nsMathMLContainerFrame implementation michael@0: // michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame) michael@0: michael@0: NS_QUERYFRAME_HEAD(nsMathMLContainerFrame) michael@0: NS_QUERYFRAME_ENTRY(nsIMathMLFrame) michael@0: NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) michael@0: michael@0: // ============================================================================= michael@0: michael@0: // error handlers michael@0: // provide a feedback to the user when a frame with bad markup can not be rendered michael@0: nsresult michael@0: nsMathMLContainerFrame::ReflowError(nsRenderingContext& aRenderingContext, michael@0: nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: // clear all other flags and record that there is an error with this frame michael@0: mEmbellishData.flags = 0; michael@0: mPresentationData.flags = NS_MATHML_ERROR; michael@0: michael@0: /////////////// michael@0: // Set font michael@0: nsRefPtr fm; michael@0: nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); michael@0: aRenderingContext.SetFont(fm); michael@0: michael@0: // bounding metrics michael@0: nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup"); michael@0: mBoundingMetrics = michael@0: aRenderingContext.GetBoundingMetrics(errorMsg.get(), errorMsg.Length()); michael@0: michael@0: // reflow metrics michael@0: aDesiredSize.SetTopAscent(fm->MaxAscent()); michael@0: nscoord descent = fm->MaxDescent(); michael@0: aDesiredSize.Height() = aDesiredSize.TopAscent() + descent; michael@0: aDesiredSize.Width() = mBoundingMetrics.width; michael@0: michael@0: // Also return our bounding metrics michael@0: aDesiredSize.mBoundingMetrics = mBoundingMetrics; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: class nsDisplayMathMLError : public nsDisplayItem { michael@0: public: michael@0: nsDisplayMathMLError(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayMathMLError); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayMathMLError() { michael@0: MOZ_COUNT_DTOR(nsDisplayMathMLError); michael@0: } michael@0: #endif michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("MathMLError", TYPE_MATHML_ERROR) michael@0: }; michael@0: michael@0: void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx) michael@0: { michael@0: // Set color and font ... michael@0: nsRefPtr fm; michael@0: nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm)); michael@0: aCtx->SetFont(fm); michael@0: michael@0: nsPoint pt = ToReferenceFrame(); michael@0: aCtx->SetColor(NS_RGB(255,0,0)); michael@0: aCtx->FillRect(nsRect(pt, mFrame->GetSize())); michael@0: aCtx->SetColor(NS_RGB(255,255,255)); michael@0: michael@0: nscoord ascent = aCtx->FontMetrics()->MaxAscent(); michael@0: michael@0: NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup"); michael@0: aCtx->DrawString(errorMsg.get(), uint32_t(errorMsg.Length()), michael@0: pt.x, pt.y+ascent); michael@0: } michael@0: michael@0: /* ///////////// michael@0: * nsIMathMLFrame - support methods for stretchy elements michael@0: * ============================================================================= michael@0: */ michael@0: michael@0: static bool michael@0: IsForeignChild(const nsIFrame* aFrame) michael@0: { michael@0: // This counts nsMathMLmathBlockFrame as a foreign child, because it michael@0: // uses block reflow michael@0: return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) || michael@0: aFrame->GetType() == nsGkAtoms::blockFrame; michael@0: } michael@0: michael@0: static void michael@0: DestroyHTMLReflowMetrics(void *aPropertyValue) michael@0: { michael@0: delete static_cast(aPropertyValue); michael@0: } michael@0: michael@0: NS_DECLARE_FRAME_PROPERTY(HTMLReflowMetricsProperty, DestroyHTMLReflowMetrics) michael@0: michael@0: /* static */ void michael@0: nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame* aFrame, michael@0: const nsHTMLReflowMetrics& aReflowMetrics, michael@0: const nsBoundingMetrics& aBoundingMetrics) michael@0: { michael@0: nsHTMLReflowMetrics *metrics = new nsHTMLReflowMetrics(aReflowMetrics); michael@0: metrics->mBoundingMetrics = aBoundingMetrics; michael@0: aFrame->Properties().Set(HTMLReflowMetricsProperty(), metrics); michael@0: } michael@0: michael@0: // helper method to facilitate getting the reflow and bounding metrics michael@0: /* static */ void michael@0: nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFrame, michael@0: nsHTMLReflowMetrics& aReflowMetrics, michael@0: nsBoundingMetrics& aBoundingMetrics, michael@0: eMathMLFrameType* aMathMLFrameType) michael@0: { michael@0: NS_PRECONDITION(aFrame, "null arg"); michael@0: michael@0: nsHTMLReflowMetrics *metrics = static_cast michael@0: (aFrame->Properties().Get(HTMLReflowMetricsProperty())); michael@0: michael@0: // IMPORTANT: This function is only meant to be called in Place() methods michael@0: // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the michael@0: // information. michael@0: NS_ASSERTION(metrics, "Didn't SaveReflowAndBoundingMetricsFor frame!"); michael@0: if (metrics) { michael@0: aReflowMetrics = *metrics; michael@0: aBoundingMetrics = metrics->mBoundingMetrics; michael@0: } michael@0: michael@0: if (aMathMLFrameType) { michael@0: if (!IsForeignChild(aFrame)) { michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame); michael@0: if (mathMLFrame) { michael@0: *aMathMLFrameType = mathMLFrame->GetMathMLFrameType(); michael@0: return; michael@0: } michael@0: } michael@0: *aMathMLFrameType = eMathMLFrameType_UNKNOWN; michael@0: } michael@0: michael@0: } michael@0: michael@0: void michael@0: nsMathMLContainerFrame::ClearSavedChildMetrics() michael@0: { michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: FramePropertyTable* props = PresContext()->PropertyTable(); michael@0: while (childFrame) { michael@0: props->Delete(childFrame, HTMLReflowMetricsProperty()); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: // helper to get the preferred size that a container frame should use to fire michael@0: // the stretch on its stretchy child frames. michael@0: void michael@0: nsMathMLContainerFrame::GetPreferredStretchSize(nsRenderingContext& aRenderingContext, michael@0: uint32_t aOptions, michael@0: nsStretchDirection aStretchDirection, michael@0: nsBoundingMetrics& aPreferredStretchSize) michael@0: { michael@0: if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) { michael@0: // when our actual size is ok, just use it michael@0: aPreferredStretchSize = mBoundingMetrics; michael@0: } michael@0: else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) { michael@0: // compute our up-to-date size using Place() michael@0: nsHTMLReflowMetrics metrics(GetWritingMode()); // ??? michael@0: Place(aRenderingContext, false, metrics); michael@0: aPreferredStretchSize = metrics.mBoundingMetrics; michael@0: } michael@0: else { michael@0: // compute a size that doesn't include embellishements michael@0: bool stretchAll = michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); michael@0: NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) || michael@0: stretchAll, michael@0: "invalid call to GetPreferredStretchSize"); michael@0: bool firstTime = true; michael@0: nsBoundingMetrics bm, bmChild; michael@0: nsIFrame* childFrame = michael@0: stretchAll ? GetFirstPrincipalChild() : mPresentationData.baseFrame; michael@0: while (childFrame) { michael@0: // initializations in case this child happens not to be a MathML frame michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); michael@0: if (mathMLFrame) { michael@0: nsEmbellishData embellishData; michael@0: nsPresentationData presentationData; michael@0: mathMLFrame->GetEmbellishData(embellishData); michael@0: mathMLFrame->GetPresentationData(presentationData); michael@0: if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) && michael@0: embellishData.direction == aStretchDirection && michael@0: presentationData.baseFrame) { michael@0: // embellishements are not included, only consider the inner first child itself michael@0: // XXXkt Does that mean the core descendent frame should be used michael@0: // instead of the base child? michael@0: nsIMathMLFrame* mathMLchildFrame = do_QueryFrame(presentationData.baseFrame); michael@0: if (mathMLchildFrame) { michael@0: mathMLFrame = mathMLchildFrame; michael@0: } michael@0: } michael@0: mathMLFrame->GetBoundingMetrics(bmChild); michael@0: } michael@0: else { michael@0: nsHTMLReflowMetrics unused(GetWritingMode()); michael@0: GetReflowAndBoundingMetricsFor(childFrame, unused, bmChild); michael@0: } michael@0: michael@0: if (firstTime) { michael@0: firstTime = false; michael@0: bm = bmChild; michael@0: if (!stretchAll) { michael@0: // we may get here for cases such as ... ... , michael@0: // or ....... michael@0: break; michael@0: } michael@0: } michael@0: else { michael@0: if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) { michael@0: // if we get here, it means this is container that will stack its children michael@0: // vertically and fire an horizontal stretch on each them. This is the case michael@0: // for \munder, \mover, \munderover. We just sum-up the size vertically. michael@0: bm.descent += bmChild.ascent + bmChild.descent; michael@0: // Sometimes non-spacing marks (when width is zero) are positioned michael@0: // to the left of the origin, but it is the distance between left michael@0: // and right bearing that is important rather than the offsets from michael@0: // the origin. michael@0: if (bmChild.width == 0) { michael@0: bmChild.rightBearing -= bmChild.leftBearing; michael@0: bmChild.leftBearing = 0; michael@0: } michael@0: if (bm.leftBearing > bmChild.leftBearing) michael@0: bm.leftBearing = bmChild.leftBearing; michael@0: if (bm.rightBearing < bmChild.rightBearing) michael@0: bm.rightBearing = bmChild.rightBearing; michael@0: } michael@0: else if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)) { michael@0: // just sum-up the sizes horizontally. michael@0: bm += bmChild; michael@0: } michael@0: else { michael@0: NS_ERROR("unexpected case in GetPreferredStretchSize"); michael@0: break; michael@0: } michael@0: } michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: aPreferredStretchSize = bm; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMathMLContainerFrame::Stretch(nsRenderingContext& aRenderingContext, michael@0: nsStretchDirection aStretchDirection, michael@0: nsBoundingMetrics& aContainerSize, michael@0: nsHTMLReflowMetrics& aDesiredStretchSize) michael@0: { michael@0: if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) { michael@0: michael@0: if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) { michael@0: NS_WARNING("it is wrong to fire stretch more than once on a frame"); michael@0: return NS_OK; michael@0: } michael@0: mPresentationData.flags |= NS_MATHML_STRETCH_DONE; michael@0: michael@0: if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { michael@0: NS_WARNING("it is wrong to fire stretch on a erroneous frame"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Pass the stretch to the base child ... michael@0: michael@0: nsIFrame* baseFrame = mPresentationData.baseFrame; michael@0: if (baseFrame) { michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(baseFrame); michael@0: NS_ASSERTION(mathMLFrame, "Something is wrong somewhere"); michael@0: if (mathMLFrame) { michael@0: bool stretchAll = michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); michael@0: michael@0: // And the trick is that the child's rect.x is still holding the descent, michael@0: // and rect.y is still holding the ascent ... michael@0: nsHTMLReflowMetrics childSize(aDesiredStretchSize); michael@0: GetReflowAndBoundingMetricsFor(baseFrame, childSize, childSize.mBoundingMetrics); michael@0: michael@0: // See if we should downsize and confine the stretch to us... michael@0: // XXX there may be other cases where we can downsize the stretch, michael@0: // e.g., the first ∑ might appear big in the following situation michael@0: // michael@0: // michael@0: // michael@0: // ab michael@0: // ab michael@0: // michael@0: // michael@0: // michael@0: nsBoundingMetrics containerSize = aContainerSize; michael@0: if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && michael@0: aStretchDirection != mEmbellishData.direction) { michael@0: if (mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) { michael@0: containerSize = childSize.mBoundingMetrics; michael@0: } michael@0: else { michael@0: GetPreferredStretchSize(aRenderingContext, michael@0: stretchAll ? STRETCH_CONSIDER_EMBELLISHMENTS : 0, michael@0: mEmbellishData.direction, containerSize); michael@0: } michael@0: } michael@0: michael@0: // do the stretching... michael@0: mathMLFrame->Stretch(aRenderingContext, michael@0: mEmbellishData.direction, containerSize, childSize); michael@0: // store the updated metrics michael@0: SaveReflowAndBoundingMetricsFor(baseFrame, childSize, michael@0: childSize.mBoundingMetrics); michael@0: michael@0: // Remember the siblings which were _deferred_. michael@0: // Now that this embellished child may have changed, we need to michael@0: // fire the stretch on its siblings using our updated size michael@0: michael@0: if (stretchAll) { michael@0: michael@0: nsStretchDirection stretchDir = michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ? michael@0: NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL; michael@0: michael@0: GetPreferredStretchSize(aRenderingContext, STRETCH_CONSIDER_EMBELLISHMENTS, michael@0: stretchDir, containerSize); michael@0: michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: if (childFrame != mPresentationData.baseFrame) { michael@0: mathMLFrame = do_QueryFrame(childFrame); michael@0: if (mathMLFrame) { michael@0: // retrieve the metrics that was stored at the previous pass michael@0: GetReflowAndBoundingMetricsFor(childFrame, michael@0: childSize, childSize.mBoundingMetrics); michael@0: // do the stretching... michael@0: mathMLFrame->Stretch(aRenderingContext, stretchDir, michael@0: containerSize, childSize); michael@0: // store the updated metrics michael@0: SaveReflowAndBoundingMetricsFor(childFrame, childSize, michael@0: childSize.mBoundingMetrics); michael@0: } michael@0: } michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: // re-position all our children michael@0: nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize); michael@0: if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { michael@0: // Make sure the child frames get their DidReflow() calls. michael@0: DidReflowChildren(mFrames.FirstChild()); michael@0: } michael@0: michael@0: // If our parent is not embellished, it means we are the outermost embellished michael@0: // container and so we put the spacing, otherwise we don't include the spacing, michael@0: // the outermost embellished container will take care of it. michael@0: michael@0: nsEmbellishData parentData; michael@0: GetEmbellishDataFrom(mParent, parentData); michael@0: // ensure that we are the embellished child, not just a sibling michael@0: // (need to test coreFrame since resets other things) michael@0: if (parentData.coreFrame != mEmbellishData.coreFrame) { michael@0: // (we fetch values from the core since they may use units that depend michael@0: // on style data, and style changes could have occurred in the core since michael@0: // our last visit there) michael@0: nsEmbellishData coreData; michael@0: GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData); michael@0: michael@0: mBoundingMetrics.width += michael@0: coreData.leadingSpace + coreData.trailingSpace; michael@0: aDesiredStretchSize.Width() = mBoundingMetrics.width; michael@0: aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width; michael@0: michael@0: nscoord dx = (StyleVisibility()->mDirection ? michael@0: coreData.trailingSpace : coreData.leadingSpace); michael@0: if (dx != 0) { michael@0: mBoundingMetrics.leftBearing += dx; michael@0: mBoundingMetrics.rightBearing += dx; michael@0: aDesiredStretchSize.mBoundingMetrics.leftBearing += dx; michael@0: aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; michael@0: michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: childFrame->SetPosition(childFrame->GetPosition() michael@0: + nsPoint(dx, 0)); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Finished with these: michael@0: ClearSavedChildMetrics(); michael@0: // Set our overflow area michael@0: GatherAndStoreOverflow(&aDesiredStretchSize); michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::FinalizeReflow(nsRenderingContext& aRenderingContext, michael@0: nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: // During reflow, we use rect.x and rect.y as placeholders for the child's ascent michael@0: // and descent in expectation of a stretch command. Hence we need to ensure that michael@0: // a stretch command will actually be fired later on, after exiting from our michael@0: // reflow. If the stretch is not fired, the rect.x, and rect.y will remain michael@0: // with inappropriate data causing children to be improperly positioned. michael@0: // This helper method checks to see if our parent will fire a stretch command michael@0: // targeted at us. If not, we go ahead and fire an involutive stretch on michael@0: // ourselves. This will clear all the rect.x and rect.y, and return our michael@0: // desired size. michael@0: michael@0: michael@0: // First, complete the post-reflow hook. michael@0: // We use the information in our children rectangles to position them. michael@0: // If placeOrigin==false, then Place() will not touch rect.x, and rect.y. michael@0: // They will still be holding the ascent and descent for each child. michael@0: michael@0: // The first clause caters for any non-embellished container. michael@0: // The second clause is for a container which won't fire stretch even though it is michael@0: // embellished, e.g., as in ... ... , the test is convoluted michael@0: // because it excludes the particular case of the core ... itself. michael@0: // ( needs to fire stretch on its MathMLChar in any case to initialize it) michael@0: bool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) || michael@0: (mEmbellishData.coreFrame != this && !mPresentationData.baseFrame && michael@0: mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED); michael@0: nsresult rv = Place(aRenderingContext, placeOrigin, aDesiredSize); michael@0: michael@0: // Place() will call FinishReflowChild() when placeOrigin is true but if michael@0: // it returns before reaching FinishReflowChild() due to errors we need michael@0: // to fulfill the reflow protocol by calling DidReflow for the child frames michael@0: // that still needs it here (or we may crash - bug 366012). michael@0: // If placeOrigin is false we should reach Place() with aPlaceOrigin == true michael@0: // through Stretch() eventually. michael@0: if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { michael@0: DidReflowChildren(GetFirstPrincipalChild()); michael@0: return rv; michael@0: } michael@0: michael@0: bool parentWillFireStretch = false; michael@0: if (!placeOrigin) { michael@0: // This means the rect.x and rect.y of our children were not set!! michael@0: // Don't go without checking to see if our parent will later fire a Stretch() command michael@0: // targeted at us. The Stretch() will cause the rect.x and rect.y to clear... michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(mParent); michael@0: if (mathMLFrame) { michael@0: nsEmbellishData embellishData; michael@0: nsPresentationData presentationData; michael@0: mathMLFrame->GetEmbellishData(embellishData); michael@0: mathMLFrame->GetPresentationData(presentationData); michael@0: if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) || michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) || michael@0: (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) michael@0: && presentationData.baseFrame == this)) michael@0: { michael@0: parentWillFireStretch = true; michael@0: } michael@0: } michael@0: if (!parentWillFireStretch) { michael@0: // There is nobody who will fire the stretch for us, we do it ourselves! michael@0: michael@0: bool stretchAll = michael@0: /* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */ michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags); michael@0: michael@0: nsBoundingMetrics defaultSize; michael@0: if (mEmbellishData.coreFrame == this /* case of a bare ... itself */ michael@0: || stretchAll) { /* or ......, or friends */ michael@0: // use our current size as computed earlier by Place() michael@0: defaultSize = aDesiredSize.mBoundingMetrics; michael@0: } michael@0: else { /* case of ...... or friends */ michael@0: // compute a size that doesn't include embellishments michael@0: GetPreferredStretchSize(aRenderingContext, 0, mEmbellishData.direction, michael@0: defaultSize); michael@0: } michael@0: Stretch(aRenderingContext, NS_STRETCH_DIRECTION_DEFAULT, defaultSize, michael@0: aDesiredSize); michael@0: #ifdef DEBUG michael@0: { michael@0: // The Place() call above didn't request FinishReflowChild(), michael@0: // so let's check that we eventually did through Stretch(). michael@0: nsIFrame* childFrame = GetFirstPrincipalChild(); michael@0: for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { michael@0: NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_IN_REFLOW), michael@0: "DidReflow() was never called"); michael@0: } michael@0: } michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: // Also return our bounding metrics michael@0: aDesiredSize.mBoundingMetrics = mBoundingMetrics; michael@0: michael@0: // see if we should fix the spacing michael@0: FixInterFrameSpacing(aDesiredSize); michael@0: michael@0: if (!parentWillFireStretch) { michael@0: // Not expecting a stretch. michael@0: // Finished with these: michael@0: ClearSavedChildMetrics(); michael@0: // Set our overflow area. michael@0: GatherAndStoreOverflow(&aDesiredSize); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /* ///////////// michael@0: * nsIMathMLFrame - support methods for scripting elements (nested frames michael@0: * within msub, msup, msubsup, munder, mover, munderover, mmultiscripts, michael@0: * mfrac, mroot, mtable). michael@0: * ============================================================================= michael@0: */ michael@0: michael@0: // helper to let the update of presentation data pass through michael@0: // a subtree that may contain non-mathml container frames michael@0: /* static */ void michael@0: nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame* aFrame, michael@0: uint32_t aFlagsValues, michael@0: uint32_t aFlagsToUpdate) michael@0: { michael@0: if (!aFrame || !aFlagsToUpdate) michael@0: return; michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame); michael@0: if (mathMLFrame) { michael@0: // update michael@0: mathMLFrame->UpdatePresentationData(aFlagsValues, michael@0: aFlagsToUpdate); michael@0: // propagate using the base method to make sure that the control michael@0: // is passed on to MathML frames that may be overloading the method michael@0: mathMLFrame->UpdatePresentationDataFromChildAt(0, -1, michael@0: aFlagsValues, aFlagsToUpdate); michael@0: } michael@0: else { michael@0: // propagate down the subtrees michael@0: nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); michael@0: while (childFrame) { michael@0: PropagatePresentationDataFor(childFrame, michael@0: aFlagsValues, aFlagsToUpdate); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* static */ void michael@0: nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame* aParentFrame, michael@0: int32_t aFirstChildIndex, michael@0: int32_t aLastChildIndex, michael@0: uint32_t aFlagsValues, michael@0: uint32_t aFlagsToUpdate) michael@0: { michael@0: if (!aParentFrame || !aFlagsToUpdate) michael@0: return; michael@0: int32_t index = 0; michael@0: nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); michael@0: while (childFrame) { michael@0: if ((index >= aFirstChildIndex) && michael@0: ((aLastChildIndex <= 0) || ((aLastChildIndex > 0) && michael@0: (index <= aLastChildIndex)))) { michael@0: PropagatePresentationDataFor(childFrame, michael@0: aFlagsValues, aFlagsToUpdate); michael@0: } michael@0: index++; michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: /* ////////////////// michael@0: * Frame construction michael@0: * ============================================================================= michael@0: */ michael@0: michael@0: michael@0: void michael@0: nsMathMLContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // report an error if something wrong was found in this frame michael@0: if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { michael@0: if (!IsVisibleForPainting(aBuilder)) michael@0: return; michael@0: michael@0: aLists.Content()->AppendNewToTop( michael@0: new (aBuilder) nsDisplayMathMLError(aBuilder, this)); michael@0: return; michael@0: } michael@0: michael@0: DisplayBorderBackgroundOutline(aBuilder, aLists); michael@0: michael@0: BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists, michael@0: DISPLAY_CHILD_INLINE); michael@0: michael@0: #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX) michael@0: // for visual debug michael@0: // ---------------- michael@0: // if you want to see your bounding box, make sure to properly fill michael@0: // your mBoundingMetrics and mReference point, and set michael@0: // mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS michael@0: // in the Init() of your sub-class michael@0: DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists); michael@0: #endif michael@0: } michael@0: michael@0: // Note that this method re-builds the automatic data in the children -- not michael@0: // in aParentFrame itself (except for those particular operations that the michael@0: // parent frame may do in its TransmitAutomaticData()). michael@0: /* static */ void michael@0: nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame) michael@0: { michael@0: // 1. As we descend the tree, make each child frame inherit data from michael@0: // the parent michael@0: // 2. As we ascend the tree, transmit any specific change that we want michael@0: // down the subtrees michael@0: nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); michael@0: while (childFrame) { michael@0: nsIMathMLFrame* childMathMLFrame = do_QueryFrame(childFrame); michael@0: if (childMathMLFrame) { michael@0: childMathMLFrame->InheritAutomaticData(aParentFrame); michael@0: } michael@0: RebuildAutomaticDataForChildren(childFrame); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(aParentFrame); michael@0: if (mathMLFrame) { michael@0: mathMLFrame->TransmitAutomaticData(); michael@0: } michael@0: } michael@0: michael@0: /* static */ nsresult michael@0: nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame) michael@0: { michael@0: if (!aParentFrame) michael@0: return NS_OK; michael@0: michael@0: // walk-up to the first frame that is a MathML frame, stop if we reach michael@0: nsIFrame* frame = aParentFrame; michael@0: while (1) { michael@0: nsIFrame* parent = frame->GetParent(); michael@0: if (!parent || !parent->GetContent()) michael@0: break; michael@0: michael@0: // stop if it is a MathML frame michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame); michael@0: if (mathMLFrame) michael@0: break; michael@0: michael@0: // stop if we reach the root tag michael@0: nsIContent* content = frame->GetContent(); michael@0: NS_ASSERTION(content, "dangling frame without a content node"); michael@0: if (!content) michael@0: break; michael@0: if (content->GetNameSpaceID() == kNameSpaceID_MathML && michael@0: content->Tag() == nsGkAtoms::math) michael@0: break; michael@0: michael@0: frame = parent; michael@0: } michael@0: michael@0: // re-sync the presentation data and embellishment data of our children michael@0: RebuildAutomaticDataForChildren(frame); michael@0: michael@0: // Ask our parent frame to reflow us michael@0: nsIFrame* parent = frame->GetParent(); michael@0: NS_ASSERTION(parent, "No parent to pass the reflow request up to"); michael@0: if (!parent) michael@0: return NS_OK; michael@0: michael@0: frame->PresContext()->PresShell()-> michael@0: FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // There are precise rules governing children of a MathML frame, michael@0: // and properties such as the scriptlevel depends on those rules. michael@0: // Hence for things to work, callers must use Append/Insert/etc wisely. michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ChildListChanged(int32_t aModType) michael@0: { michael@0: // If this is an embellished frame we need to rebuild the michael@0: // embellished hierarchy by walking-up to the parent of the michael@0: // outermost embellished container. michael@0: nsIFrame* frame = this; michael@0: if (mEmbellishData.coreFrame) { michael@0: nsIFrame* parent = mParent; michael@0: nsEmbellishData embellishData; michael@0: for ( ; parent; frame = parent, parent = parent->GetParent()) { michael@0: GetEmbellishDataFrom(parent, embellishData); michael@0: if (embellishData.coreFrame != mEmbellishData.coreFrame) michael@0: break; michael@0: } michael@0: } michael@0: return ReLayoutChildren(frame); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::AppendFrames(ChildListID aListID, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: if (aListID != kPrincipalList) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: mFrames.AppendFrames(this, aFrameList); michael@0: return ChildListChanged(nsIDOMMutationEvent::ADDITION); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::InsertFrames(ChildListID aListID, michael@0: nsIFrame* aPrevFrame, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: if (aListID != kPrincipalList) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: // Insert frames after aPrevFrame michael@0: mFrames.InsertFrames(this, aPrevFrame, aFrameList); michael@0: return ChildListChanged(nsIDOMMutationEvent::ADDITION); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::RemoveFrame(ChildListID aListID, michael@0: nsIFrame* aOldFrame) michael@0: { michael@0: if (aListID != kPrincipalList) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: // remove the child frame michael@0: mFrames.DestroyFrame(aOldFrame); michael@0: return ChildListChanged(nsIDOMMutationEvent::REMOVAL); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: // XXX Since they are numerous MathML attributes that affect layout, and michael@0: // we can't check all of them here, play safe by requesting a reflow. michael@0: // XXXldb This should only do work for attributes that cause changes! michael@0: PresContext()->PresShell()-> michael@0: FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsMathMLContainerFrame::GatherAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) michael@0: { michael@0: // nsIFrame::FinishAndStoreOverflow likes the overflow area to include the michael@0: // frame rectangle. michael@0: aMetrics->SetOverflowAreasToDesiredBounds(); michael@0: michael@0: // All non-child-frame content such as nsMathMLChars (and most child-frame michael@0: // content) is included in mBoundingMetrics. michael@0: nsRect boundingBox(mBoundingMetrics.leftBearing, michael@0: aMetrics->TopAscent() - mBoundingMetrics.ascent, michael@0: mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing, michael@0: mBoundingMetrics.ascent + mBoundingMetrics.descent); michael@0: michael@0: // REVIEW: Maybe this should contribute only to visual overflow michael@0: // and not scrollable? michael@0: aMetrics->mOverflowAreas.UnionAllWith(boundingBox); michael@0: michael@0: // mBoundingMetrics does not necessarily include content of michael@0: // elements whose mBoundingMetrics may not be representative of the true michael@0: // bounds, and doesn't include the CSS2 outline rectangles of children, so michael@0: // make such to include child overflow areas. michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: ConsiderChildOverflow(aMetrics->mOverflowAreas, childFrame); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: michael@0: FinishAndStoreOverflow(aMetrics); michael@0: } michael@0: michael@0: bool michael@0: nsMathMLContainerFrame::UpdateOverflow() michael@0: { michael@0: // Our overflow areas may have changed, so reflow the frame. michael@0: PresContext()->PresShell()->FrameNeedsReflow( michael@0: this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); michael@0: michael@0: // As we're reflowing, there's no need to propagate this change. michael@0: return false; michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame, michael@0: nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: // Having foreign/hybrid children, e.g., from html markups, is not defined by michael@0: // the MathML spec. But it can happen in practice, e.g., allows us michael@0: // to do some cool demos... or we may have a child that is an nsInlineFrame michael@0: // from a generated content such as :before { content: open-quote } or michael@0: // :after { content: close-quote }. Unfortunately, the other frames out-there michael@0: // may expect their own invariants that are not met when we mix things. michael@0: // Hence we do not claim their support, but we will nevertheless attempt to keep michael@0: // them in the flow, if we can get their desired size. We observed that most michael@0: // frames may be reflowed generically, but nsInlineFrames need extra care. michael@0: michael@0: #ifdef DEBUG michael@0: nsInlineFrame* inlineFrame = do_QueryFrame(aChildFrame); michael@0: NS_ASSERTION(!inlineFrame, "Inline frames should be wrapped in blocks"); michael@0: #endif michael@0: michael@0: nsresult rv = nsContainerFrame:: michael@0: ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowState, michael@0: 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (aDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) { michael@0: // This will be suitable for inline frames, which are wrapped in a block. michael@0: nscoord ascent; michael@0: if (!nsLayoutUtils::GetLastLineBaseline(aChildFrame, michael@0: &ascent)) { michael@0: // We don't expect any other block children so just place the frame on michael@0: // the baseline instead of going through DidReflow() and michael@0: // GetBaseline(). This is what nsFrame::GetBaseline() will do anyway. michael@0: aDesiredSize.SetTopAscent(aDesiredSize.Height()); michael@0: } else { michael@0: aDesiredSize.SetTopAscent(ascent); michael@0: } michael@0: } michael@0: if (IsForeignChild(aChildFrame)) { michael@0: // use ComputeTightBounds API as aDesiredSize.mBoundingMetrics is not set. michael@0: nsRect r = aChildFrame->ComputeTightBounds(aReflowState.rendContext->ThebesContext()); michael@0: aDesiredSize.mBoundingMetrics.leftBearing = r.x; michael@0: aDesiredSize.mBoundingMetrics.rightBearing = r.XMost(); michael@0: aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.TopAscent() - r.y; michael@0: aDesiredSize.mBoundingMetrics.descent = r.YMost() - aDesiredSize.TopAscent(); michael@0: aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width(); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: aDesiredSize.Width() = aDesiredSize.Height() = 0; michael@0: aDesiredSize.SetTopAscent(0); michael@0: aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); michael@0: michael@0: ///////////// michael@0: // Reflow children michael@0: // Asking each child to cache its bounding metrics michael@0: michael@0: nsReflowStatus childStatus; michael@0: nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: nsHTMLReflowMetrics childDesiredSize(aReflowState, // ??? michael@0: aDesiredSize.mFlags); michael@0: nsHTMLReflowState childReflowState(aPresContext, aReflowState, michael@0: childFrame, availSize); michael@0: nsresult rv = ReflowChild(childFrame, aPresContext, childDesiredSize, michael@0: childReflowState, childStatus); michael@0: //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); michael@0: if (NS_FAILED(rv)) { michael@0: // Call DidReflow() for the child frames we successfully did reflow. michael@0: DidReflowChildren(mFrames.FirstChild(), childFrame); michael@0: return rv; michael@0: } michael@0: michael@0: SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, michael@0: childDesiredSize.mBoundingMetrics); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: michael@0: ///////////// michael@0: // If we are a container which is entitled to stretch its children, then we michael@0: // ask our stretchy children to stretch themselves michael@0: michael@0: // The stretching of siblings of an embellished child is _deferred_ until michael@0: // after finishing the stretching of the embellished child - bug 117652 michael@0: michael@0: if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) && michael@0: (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) { michael@0: michael@0: // get the stretchy direction michael@0: nsStretchDirection stretchDir = michael@0: NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) michael@0: ? NS_STRETCH_DIRECTION_VERTICAL michael@0: : NS_STRETCH_DIRECTION_HORIZONTAL; michael@0: michael@0: // what size should we use to stretch our stretchy children michael@0: // We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet michael@0: // We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to michael@0: // include them in the caculations of the size of stretchy elements michael@0: nsBoundingMetrics containerSize; michael@0: GetPreferredStretchSize(*aReflowState.rendContext, 0, stretchDir, michael@0: containerSize); michael@0: michael@0: // fire the stretch on each child michael@0: childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); michael@0: if (mathMLFrame) { michael@0: // retrieve the metrics that was stored at the previous pass michael@0: nsHTMLReflowMetrics childDesiredSize(aReflowState); michael@0: GetReflowAndBoundingMetricsFor(childFrame, michael@0: childDesiredSize, childDesiredSize.mBoundingMetrics); michael@0: michael@0: mathMLFrame->Stretch(*aReflowState.rendContext, stretchDir, michael@0: containerSize, childDesiredSize); michael@0: // store the updated metrics michael@0: SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, michael@0: childDesiredSize.mBoundingMetrics); michael@0: } michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: ///////////// michael@0: // Place children now by re-adjusting the origins to align the baselines michael@0: FinalizeReflow(*aReflowState.rendContext, aDesiredSize); michael@0: michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nscoord AddInterFrameSpacingToSize(nsHTMLReflowMetrics& aDesiredSize, michael@0: nsMathMLContainerFrame* aFrame); michael@0: michael@0: /* virtual */ nscoord michael@0: nsMathMLContainerFrame::GetMinWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result; michael@0: DISPLAY_MIN_WIDTH(this, result); michael@0: nsHTMLReflowMetrics desiredSize(GetWritingMode()); michael@0: GetIntrinsicWidthMetrics(aRenderingContext, desiredSize); michael@0: michael@0: // Include the additional width added by FixInterFrameSpacing to ensure michael@0: // consistent width calculations. michael@0: AddInterFrameSpacingToSize(desiredSize, this); michael@0: result = desiredSize.Width(); michael@0: return result; michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsMathMLContainerFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result; michael@0: DISPLAY_PREF_WIDTH(this, result); michael@0: nsHTMLReflowMetrics desiredSize(GetWritingMode()); michael@0: GetIntrinsicWidthMetrics(aRenderingContext, desiredSize); michael@0: michael@0: // Include the additional width added by FixInterFrameSpacing to ensure michael@0: // consistent width calculations. michael@0: AddInterFrameSpacingToSize(desiredSize, this); michael@0: result = desiredSize.Width(); michael@0: return result; michael@0: } michael@0: michael@0: /* virtual */ void michael@0: nsMathMLContainerFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: // Get child widths michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: nsHTMLReflowMetrics childDesiredSize(GetWritingMode()); // ??? michael@0: michael@0: nsMathMLContainerFrame* containerFrame = do_QueryFrame(childFrame); michael@0: if (containerFrame) { michael@0: containerFrame->GetIntrinsicWidthMetrics(aRenderingContext, michael@0: childDesiredSize); michael@0: } else { michael@0: // XXX This includes margin while Reflow currently doesn't consider michael@0: // margin, so we may end up with too much space, but, with stretchy michael@0: // characters, this is an approximation anyway. michael@0: nscoord width = michael@0: nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame, michael@0: nsLayoutUtils::PREF_WIDTH); michael@0: michael@0: childDesiredSize.Width() = width; michael@0: childDesiredSize.mBoundingMetrics.width = width; michael@0: childDesiredSize.mBoundingMetrics.leftBearing = 0; michael@0: childDesiredSize.mBoundingMetrics.rightBearing = width; michael@0: michael@0: nscoord x, xMost; michael@0: if (NS_SUCCEEDED(childFrame->GetPrefWidthTightBounds(aRenderingContext, michael@0: &x, &xMost))) { michael@0: childDesiredSize.mBoundingMetrics.leftBearing = x; michael@0: childDesiredSize.mBoundingMetrics.rightBearing = xMost; michael@0: } michael@0: } michael@0: michael@0: SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, michael@0: childDesiredSize.mBoundingMetrics); michael@0: michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: michael@0: // Measure michael@0: nsresult rv = MeasureForWidth(*aRenderingContext, aDesiredSize); michael@0: if (NS_FAILED(rv)) { michael@0: ReflowError(*aRenderingContext, aDesiredSize); michael@0: } michael@0: michael@0: ClearSavedChildMetrics(); michael@0: } michael@0: michael@0: /* virtual */ nsresult michael@0: nsMathMLContainerFrame::MeasureForWidth(nsRenderingContext& aRenderingContext, michael@0: nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: return Place(aRenderingContext, false, aDesiredSize); michael@0: } michael@0: michael@0: michael@0: // see spacing table in Chapter 18, TeXBook (p.170) michael@0: // Our table isn't quite identical to TeX because operators have michael@0: // built-in values for lspace & rspace in the Operator Dictionary. michael@0: static int32_t kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] = michael@0: { michael@0: // in units of muspace. michael@0: // upper half of the byte is set if the michael@0: // spacing is not to be used for scriptlevel > 0 michael@0: michael@0: /* Ord OpOrd OpInv OpUsr Inner Italic Upright */ michael@0: /*Ord */ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00}, michael@0: /*OpOrd*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, michael@0: /*OpInv*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, michael@0: /*OpUsr*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01}, michael@0: /*Inner*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01}, michael@0: /*Italic*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01}, michael@0: /*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00} michael@0: }; michael@0: michael@0: #define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_) \ michael@0: /* no space if there is a frame that we know nothing about */ \ michael@0: if (frametype1_ == eMathMLFrameType_UNKNOWN || \ michael@0: frametype2_ == eMathMLFrameType_UNKNOWN) \ michael@0: space_ = 0; \ michael@0: else { \ michael@0: space_ = kInterFrameSpacingTable[frametype1_][frametype2_]; \ michael@0: space_ = (scriptlevel_ > 0 && (space_ & 0xF0)) \ michael@0: ? 0 /* spacing is disabled */ \ michael@0: : space_ & 0x0F; \ michael@0: } \ michael@0: michael@0: // This function computes the inter-space between two frames. However, michael@0: // since invisible operators need special treatment, the inter-space may michael@0: // be delayed when an invisible operator is encountered. In this case, michael@0: // the function will carry the inter-space forward until it is determined michael@0: // that it can be applied properly (i.e., until we encounter a visible michael@0: // frame where to decide whether to accept or reject the inter-space). michael@0: // aFromFrameType: remembers the frame when the carry-forward initiated. michael@0: // aCarrySpace: keeps track of the inter-space that is delayed. michael@0: // @returns: current inter-space (which is 0 when the true inter-space is michael@0: // delayed -- and thus has no effect since the frame is invisible anyway). michael@0: static nscoord michael@0: GetInterFrameSpacing(int32_t aScriptLevel, michael@0: eMathMLFrameType aFirstFrameType, michael@0: eMathMLFrameType aSecondFrameType, michael@0: eMathMLFrameType* aFromFrameType, // IN/OUT michael@0: int32_t* aCarrySpace) // IN/OUT michael@0: { michael@0: eMathMLFrameType firstType = aFirstFrameType; michael@0: eMathMLFrameType secondType = aSecondFrameType; michael@0: michael@0: int32_t space; michael@0: GET_INTERSPACE(aScriptLevel, firstType, secondType, space); michael@0: michael@0: // feedback control to avoid the inter-space to be added when not necessary michael@0: if (secondType == eMathMLFrameType_OperatorInvisible) { michael@0: // see if we should start to carry the space forward until we michael@0: // encounter a visible frame michael@0: if (*aFromFrameType == eMathMLFrameType_UNKNOWN) { michael@0: *aFromFrameType = firstType; michael@0: *aCarrySpace = space; michael@0: } michael@0: // keep carrying *aCarrySpace forward, while returning 0 for this stage michael@0: space = 0; michael@0: } michael@0: else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) { michael@0: // no carry-forward anymore, get the real inter-space between michael@0: // the two frames of interest michael@0: michael@0: firstType = *aFromFrameType; michael@0: michael@0: // But... the invisible operator that we encountered earlier could michael@0: // be sitting between italic and upright identifiers, e.g., michael@0: // michael@0: // 1. sin x michael@0: // 2. x &InvisibileTime; sin michael@0: // michael@0: // the trick to get the inter-space in either situation michael@0: // is to promote "sin" and michael@0: // "&InvisibileTime;sin" to user-defined operators... michael@0: if (firstType == eMathMLFrameType_UprightIdentifier) { michael@0: firstType = eMathMLFrameType_OperatorUserDefined; michael@0: } michael@0: else if (secondType == eMathMLFrameType_UprightIdentifier) { michael@0: secondType = eMathMLFrameType_OperatorUserDefined; michael@0: } michael@0: michael@0: GET_INTERSPACE(aScriptLevel, firstType, secondType, space); michael@0: michael@0: // Now, we have two values: the computed space and the space that michael@0: // has been carried forward until now. Which value do we pick? michael@0: // If the second type is an operator (e.g., fence), it already has michael@0: // built-in lspace & rspace, so we let them win. Otherwise we pick michael@0: // the max between the two values that we have. michael@0: if (secondType != eMathMLFrameType_OperatorOrdinary && michael@0: space < *aCarrySpace) michael@0: space = *aCarrySpace; michael@0: michael@0: // reset everything now that the carry-forward is done michael@0: *aFromFrameType = eMathMLFrameType_UNKNOWN; michael@0: *aCarrySpace = 0; michael@0: } michael@0: michael@0: return space; michael@0: } michael@0: michael@0: static nscoord GetThinSpace(const nsStyleFont* aStyleFont) michael@0: { michael@0: return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18)); michael@0: } michael@0: michael@0: class nsMathMLContainerFrame::RowChildFrameIterator { michael@0: public: michael@0: explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) : michael@0: mParentFrame(aParentFrame), michael@0: mSize(aParentFrame->GetWritingMode()), // ??? michael@0: mX(0), michael@0: mCarrySpace(0), michael@0: mFromFrameType(eMathMLFrameType_UNKNOWN), michael@0: mRTL(aParentFrame->StyleVisibility()->mDirection) michael@0: { michael@0: if (!mRTL) { michael@0: mChildFrame = aParentFrame->mFrames.FirstChild(); michael@0: } else { michael@0: mChildFrame = aParentFrame->mFrames.LastChild(); michael@0: } michael@0: michael@0: if (!mChildFrame) michael@0: return; michael@0: michael@0: InitMetricsForChild(); michael@0: } michael@0: michael@0: RowChildFrameIterator& operator++() michael@0: { michael@0: // add child size + italic correction michael@0: mX += mSize.mBoundingMetrics.width + mItalicCorrection; michael@0: michael@0: if (!mRTL) { michael@0: mChildFrame = mChildFrame->GetNextSibling(); michael@0: } else { michael@0: mChildFrame = mChildFrame->GetPrevSibling(); michael@0: } michael@0: michael@0: if (!mChildFrame) michael@0: return *this; michael@0: michael@0: eMathMLFrameType prevFrameType = mChildFrameType; michael@0: InitMetricsForChild(); michael@0: michael@0: // add inter frame spacing michael@0: const nsStyleFont* font = mParentFrame->StyleFont(); michael@0: nscoord space = michael@0: GetInterFrameSpacing(font->mScriptLevel, michael@0: prevFrameType, mChildFrameType, michael@0: &mFromFrameType, &mCarrySpace); michael@0: mX += space * GetThinSpace(font); michael@0: return *this; michael@0: } michael@0: michael@0: nsIFrame* Frame() const { return mChildFrame; } michael@0: nscoord X() const { return mX; } michael@0: const nsHTMLReflowMetrics& ReflowMetrics() const { return mSize; } michael@0: nscoord Ascent() const { return mSize.TopAscent(); } michael@0: nscoord Descent() const { return mSize.Height() - mSize.TopAscent(); } michael@0: const nsBoundingMetrics& BoundingMetrics() const { michael@0: return mSize.mBoundingMetrics; michael@0: } michael@0: michael@0: private: michael@0: const nsMathMLContainerFrame* mParentFrame; michael@0: nsIFrame* mChildFrame; michael@0: nsHTMLReflowMetrics mSize; michael@0: nscoord mX; michael@0: michael@0: nscoord mItalicCorrection; michael@0: eMathMLFrameType mChildFrameType; michael@0: int32_t mCarrySpace; michael@0: eMathMLFrameType mFromFrameType; michael@0: michael@0: bool mRTL; michael@0: michael@0: void InitMetricsForChild() michael@0: { michael@0: GetReflowAndBoundingMetricsFor(mChildFrame, mSize, mSize.mBoundingMetrics, michael@0: &mChildFrameType); michael@0: nscoord leftCorrection, rightCorrection; michael@0: GetItalicCorrection(mSize.mBoundingMetrics, michael@0: leftCorrection, rightCorrection); michael@0: if (!mChildFrame->GetPrevSibling() && michael@0: mParentFrame->GetContent()->Tag() == nsGkAtoms::msqrt_) { michael@0: // Remove leading correction in because the sqrt glyph itself is michael@0: // there first. michael@0: if (!mRTL) { michael@0: leftCorrection = 0; michael@0: } else { michael@0: rightCorrection = 0; michael@0: } michael@0: } michael@0: // add left correction -- this fixes the problem of the italic 'f' michael@0: // e.g., q f I michael@0: mX += leftCorrection; michael@0: mItalicCorrection = rightCorrection; michael@0: } michael@0: }; michael@0: michael@0: /* virtual */ nsresult michael@0: nsMathMLContainerFrame::Place(nsRenderingContext& aRenderingContext, michael@0: bool aPlaceOrigin, michael@0: nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: // This is needed in case this frame is empty (i.e., no child frames) michael@0: mBoundingMetrics = nsBoundingMetrics(); michael@0: michael@0: RowChildFrameIterator child(this); michael@0: nscoord ascent = 0, descent = 0; michael@0: while (child.Frame()) { michael@0: if (descent < child.Descent()) michael@0: descent = child.Descent(); michael@0: if (ascent < child.Ascent()) michael@0: ascent = child.Ascent(); michael@0: // add the child size michael@0: mBoundingMetrics.width = child.X(); michael@0: mBoundingMetrics += child.BoundingMetrics(); michael@0: ++child; michael@0: } michael@0: // Add the italic correction at the end (including the last child). michael@0: // This gives a nice gap between math and non-math frames, and still michael@0: // gives the same math inter-spacing in case this frame connects to michael@0: // another math frame michael@0: mBoundingMetrics.width = child.X(); michael@0: michael@0: aDesiredSize.Width() = std::max(0, mBoundingMetrics.width); michael@0: aDesiredSize.Height() = ascent + descent; michael@0: aDesiredSize.SetTopAscent(ascent); michael@0: aDesiredSize.mBoundingMetrics = mBoundingMetrics; michael@0: michael@0: mReference.x = 0; michael@0: mReference.y = aDesiredSize.TopAscent(); michael@0: michael@0: ////////////////// michael@0: // Place Children michael@0: michael@0: if (aPlaceOrigin) { michael@0: PositionRowChildFrames(0, aDesiredSize.TopAscent()); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX, michael@0: nscoord aBaseline) michael@0: { michael@0: RowChildFrameIterator child(this); michael@0: while (child.Frame()) { michael@0: nscoord dx = aOffsetX + child.X(); michael@0: nscoord dy = aBaseline - child.Ascent(); michael@0: FinishReflowChild(child.Frame(), PresContext(), child.ReflowMetrics(), michael@0: nullptr, dx, dy, 0); michael@0: ++child; michael@0: } michael@0: } michael@0: michael@0: class ForceReflow : public nsIReflowCallback { michael@0: public: michael@0: virtual bool ReflowFinished() MOZ_OVERRIDE { michael@0: return true; michael@0: } michael@0: virtual void ReflowCallbackCanceled() MOZ_OVERRIDE {} michael@0: }; michael@0: michael@0: // We only need one of these so we just make it a static global, no need michael@0: // to dynamically allocate/destroy it. michael@0: static ForceReflow gForceReflow; michael@0: michael@0: void michael@0: nsMathMLContainerFrame::SetIncrementScriptLevel(int32_t aChildIndex, bool aIncrement) michael@0: { michael@0: nsIFrame* child = PrincipalChildList().FrameAt(aChildIndex); michael@0: if (!child) michael@0: return; michael@0: nsIContent* content = child->GetContent(); michael@0: if (!content->IsMathML()) michael@0: return; michael@0: nsMathMLElement* element = static_cast(content); michael@0: michael@0: if (element->GetIncrementScriptLevel() == aIncrement) michael@0: return; michael@0: michael@0: // XXXroc this does a ContentStatesChanged, is it safe to call here? If michael@0: // not we should do it in a post-reflow callback. michael@0: element->SetIncrementScriptLevel(aIncrement, true); michael@0: PresContext()->PresShell()->PostReflowCallback(&gForceReflow); michael@0: } michael@0: michael@0: // helpers to fix the inter-spacing when is the only parent michael@0: // e.g., it fixes f q f I michael@0: michael@0: static nscoord michael@0: GetInterFrameSpacingFor(int32_t aScriptLevel, michael@0: nsIFrame* aParentFrame, michael@0: nsIFrame* aChildFrame) michael@0: { michael@0: nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild(); michael@0: if (!childFrame || aChildFrame == childFrame) michael@0: return 0; michael@0: michael@0: int32_t carrySpace = 0; michael@0: eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN; michael@0: eMathMLFrameType prevFrameType = eMathMLFrameType_UNKNOWN; michael@0: eMathMLFrameType childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: while (childFrame) { michael@0: prevFrameType = childFrameType; michael@0: childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame); michael@0: nscoord space = GetInterFrameSpacing(aScriptLevel, michael@0: prevFrameType, childFrameType, &fromFrameType, &carrySpace); michael@0: if (aChildFrame == childFrame) { michael@0: // get thinspace michael@0: nsStyleContext* parentContext = aParentFrame->StyleContext(); michael@0: nscoord thinSpace = GetThinSpace(parentContext->StyleFont()); michael@0: // we are done michael@0: return space * thinSpace; michael@0: } michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: michael@0: NS_NOTREACHED("child not in the childlist of its parent"); michael@0: return 0; michael@0: } michael@0: michael@0: static nscoord michael@0: AddInterFrameSpacingToSize(nsHTMLReflowMetrics& aDesiredSize, michael@0: nsMathMLContainerFrame* aFrame) michael@0: { michael@0: nscoord gap = 0; michael@0: nsIFrame* parent = aFrame->GetParent(); michael@0: nsIContent* parentContent = parent->GetContent(); michael@0: if (MOZ_UNLIKELY(!parentContent)) { michael@0: return 0; michael@0: } michael@0: nsIAtom *parentTag = parentContent->Tag(); michael@0: if (parentContent->GetNameSpaceID() == kNameSpaceID_MathML && michael@0: (parentTag == nsGkAtoms::math || parentTag == nsGkAtoms::mtd_)) { michael@0: gap = GetInterFrameSpacingFor(aFrame->StyleFont()->mScriptLevel, michael@0: parent, aFrame); michael@0: // add our own italic correction michael@0: nscoord leftCorrection = 0, italicCorrection = 0; michael@0: aFrame->GetItalicCorrection(aDesiredSize.mBoundingMetrics, michael@0: leftCorrection, italicCorrection); michael@0: gap += leftCorrection; michael@0: if (gap) { michael@0: aDesiredSize.mBoundingMetrics.leftBearing += gap; michael@0: aDesiredSize.mBoundingMetrics.rightBearing += gap; michael@0: aDesiredSize.mBoundingMetrics.width += gap; michael@0: aDesiredSize.Width() += gap; michael@0: } michael@0: aDesiredSize.mBoundingMetrics.width += italicCorrection; michael@0: aDesiredSize.Width() += italicCorrection; michael@0: } michael@0: return gap; michael@0: } michael@0: michael@0: nscoord michael@0: nsMathMLContainerFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) michael@0: { michael@0: nscoord gap = 0; michael@0: gap = AddInterFrameSpacingToSize(aDesiredSize, this); michael@0: if (gap) { michael@0: // Shift our children to account for the correction michael@0: nsIFrame* childFrame = mFrames.FirstChild(); michael@0: while (childFrame) { michael@0: childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0)); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: return gap; michael@0: } michael@0: michael@0: /* static */ void michael@0: nsMathMLContainerFrame::DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop) michael@0: michael@0: { michael@0: if (MOZ_UNLIKELY(!aFirst)) michael@0: return; michael@0: michael@0: for (nsIFrame* frame = aFirst; michael@0: frame != aStop; michael@0: frame = frame->GetNextSibling()) { michael@0: NS_ASSERTION(frame, "aStop isn't a sibling"); michael@0: if (frame->GetStateBits() & NS_FRAME_IN_REFLOW) { michael@0: // finish off principal descendants, too michael@0: nsIFrame* grandchild = frame->GetFirstPrincipalChild(); michael@0: if (grandchild) michael@0: DidReflowChildren(grandchild, nullptr); michael@0: michael@0: frame->DidReflow(frame->PresContext(), nullptr, michael@0: nsDidReflowStatus::FINISHED); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // helper used by mstyle, mphantom, mpadded and mrow in their implementations michael@0: // of TransmitAutomaticData(). michael@0: nsresult michael@0: nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement() michael@0: { michael@0: // michael@0: // One loop to check both conditions below: michael@0: // michael@0: // 1) whether all the children of the mrow-like element are space-like. michael@0: // michael@0: // The REC defines the following elements to be "space-like": michael@0: // * an mstyle, mphantom, or mpadded element, all of whose direct michael@0: // sub-expressions are space-like; michael@0: // * an mrow all of whose direct sub-expressions are space-like. michael@0: // michael@0: // 2) whether all but one child of the mrow-like element are space-like and michael@0: // this non-space-like child is an embellished operator. michael@0: // michael@0: // The REC defines the following elements to be embellished operators: michael@0: // * one of the elements mstyle, mphantom, or mpadded, such that an mrow michael@0: // containing the same arguments would be an embellished operator; michael@0: // * an mrow whose arguments consist (in any order) of one embellished michael@0: // operator and zero or more space-like elements. michael@0: // michael@0: nsIFrame *childFrame, *baseFrame; michael@0: bool embellishedOpFound = false; michael@0: nsEmbellishData embellishData; michael@0: michael@0: for (childFrame = GetFirstPrincipalChild(); michael@0: childFrame; michael@0: childFrame = childFrame->GetNextSibling()) { michael@0: nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame); michael@0: if (!mathMLFrame) break; michael@0: if (!mathMLFrame->IsSpaceLike()) { michael@0: if (embellishedOpFound) break; michael@0: baseFrame = childFrame; michael@0: GetEmbellishDataFrom(baseFrame, embellishData); michael@0: if (!NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)) break; michael@0: embellishedOpFound = true; michael@0: } michael@0: } michael@0: michael@0: if (!childFrame) { michael@0: // we successfully went to the end of the loop. This means that one of michael@0: // condition 1) or 2) holds. michael@0: if (!embellishedOpFound) { michael@0: // the mrow-like element is space-like. michael@0: mPresentationData.flags |= NS_MATHML_SPACE_LIKE; michael@0: } else { michael@0: // the mrow-like element is an embellished operator. michael@0: // let the state of the embellished operator found bubble to us. michael@0: mPresentationData.baseFrame = baseFrame; michael@0: mEmbellishData = embellishData; michael@0: } michael@0: } michael@0: michael@0: if (childFrame || !embellishedOpFound) { michael@0: // The element is not embellished operator michael@0: mPresentationData.baseFrame = nullptr; michael@0: mEmbellishData.flags = 0; michael@0: mEmbellishData.coreFrame = nullptr; michael@0: mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; michael@0: mEmbellishData.leadingSpace = 0; michael@0: mEmbellishData.trailingSpace = 0; michael@0: } michael@0: michael@0: if (childFrame || embellishedOpFound) { michael@0: // The element is not space-like michael@0: mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /*static*/ void michael@0: nsMathMLContainerFrame::PropagateFrameFlagFor(nsIFrame* aFrame, michael@0: nsFrameState aFlags) michael@0: { michael@0: if (!aFrame || !aFlags) michael@0: return; michael@0: michael@0: aFrame->AddStateBits(aFlags); michael@0: nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); michael@0: while (childFrame) { michael@0: PropagateFrameFlagFor(childFrame, aFlags); michael@0: childFrame = childFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ReportErrorToConsole(const char* errorMsgId, michael@0: const char16_t** aParams, michael@0: uint32_t aParamCount) michael@0: { michael@0: return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, michael@0: NS_LITERAL_CSTRING("MathML"), mContent->OwnerDoc(), michael@0: nsContentUtils::eMATHML_PROPERTIES, michael@0: errorMsgId, aParams, aParamCount); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ReportParseError(const char16_t* aAttribute, michael@0: const char16_t* aValue) michael@0: { michael@0: const char16_t* argv[] = michael@0: { aValue, aAttribute, mContent->Tag()->GetUTF16String() }; michael@0: return ReportErrorToConsole("AttributeParsingError", argv, 3); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ReportChildCountError() michael@0: { michael@0: const char16_t* arg = mContent->Tag()->GetUTF16String(); michael@0: return ReportErrorToConsole("ChildCountIncorrect", &arg, 1); michael@0: } michael@0: michael@0: nsresult michael@0: nsMathMLContainerFrame::ReportInvalidChildError(nsIAtom* aChildTag) michael@0: { michael@0: const char16_t* argv[] = michael@0: { aChildTag->GetUTF16String(), mContent->Tag()->GetUTF16String() }; michael@0: return ReportErrorToConsole("InvalidChild", argv, 2); michael@0: } michael@0: michael@0: //========================== michael@0: michael@0: nsIFrame* michael@0: NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, michael@0: nsFrameState aFlags) michael@0: { michael@0: nsMathMLmathBlockFrame* it = new (aPresShell) nsMathMLmathBlockFrame(aContext); michael@0: it->SetFlags(aFlags); michael@0: return it; michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathBlockFrame) michael@0: michael@0: NS_QUERYFRAME_HEAD(nsMathMLmathBlockFrame) michael@0: NS_QUERYFRAME_ENTRY(nsMathMLmathBlockFrame) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame) michael@0: michael@0: nsIFrame* michael@0: NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsMathMLmathInlineFrame(aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathInlineFrame) michael@0: michael@0: NS_QUERYFRAME_HEAD(nsMathMLmathInlineFrame) michael@0: NS_QUERYFRAME_ENTRY(nsIMathMLFrame) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame)