summaryrefslogtreecommitdiffstats
path: root/layout/mathml/nsMathMLmfencedFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/mathml/nsMathMLmfencedFrame.cpp')
-rw-r--r--layout/mathml/nsMathMLmfencedFrame.cpp743
1 files changed, 743 insertions, 0 deletions
diff --git a/layout/mathml/nsMathMLmfencedFrame.cpp b/layout/mathml/nsMathMLmfencedFrame.cpp
new file mode 100644
index 000000000..ca780e649
--- /dev/null
+++ b/layout/mathml/nsMathMLmfencedFrame.cpp
@@ -0,0 +1,743 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#include "nsMathMLmfencedFrame.h"
+#include "nsRenderingContext.h"
+#include "nsMathMLChar.h"
+#include <algorithm>
+
+using namespace mozilla;
+
+//
+// <mfenced> -- surround content with a pair of fences
+//
+
+nsIFrame*
+NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+ return new (aPresShell) nsMathMLmfencedFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfencedFrame)
+
+nsMathMLmfencedFrame::~nsMathMLmfencedFrame()
+{
+ RemoveFencesAndSeparators();
+}
+
+NS_IMETHODIMP
+nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent)
+{
+ // let the base class get the default from our parent
+ nsMathMLContainerFrame::InheritAutomaticData(aParent);
+
+ mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
+
+ RemoveFencesAndSeparators();
+ CreateFencesAndSeparators(PresContext());
+
+ return NS_OK;
+}
+
+void
+nsMathMLmfencedFrame::SetInitialChildList(ChildListID aListID,
+ nsFrameList& aChildList)
+{
+ // First, let the base class do its work
+ nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
+
+ // InheritAutomaticData will not get called if our parent is not a mathml
+ // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for
+ // GetPreferredStretchSize() from Reflow().
+ mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
+ // No need to track the style contexts given to our MathML chars.
+ // The Style System will use Get/SetAdditionalStyleContext() to keep them
+ // up-to-date if dynamic changes arise.
+ CreateFencesAndSeparators(PresContext());
+}
+
+nsresult
+nsMathMLmfencedFrame::AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType)
+{
+ RemoveFencesAndSeparators();
+ CreateFencesAndSeparators(PresContext());
+
+ return nsMathMLContainerFrame::
+ AttributeChanged(aNameSpaceID, aAttribute, aModType);
+}
+
+nsresult
+nsMathMLmfencedFrame::ChildListChanged(int32_t aModType)
+{
+ RemoveFencesAndSeparators();
+ CreateFencesAndSeparators(PresContext());
+
+ return nsMathMLContainerFrame::ChildListChanged(aModType);
+}
+
+void
+nsMathMLmfencedFrame::RemoveFencesAndSeparators()
+{
+ delete mOpenChar;
+ delete mCloseChar;
+ if (mSeparatorsChar) delete[] mSeparatorsChar;
+
+ mOpenChar = nullptr;
+ mCloseChar = nullptr;
+ mSeparatorsChar = nullptr;
+ mSeparatorsCount = 0;
+}
+
+void
+nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
+{
+ nsAutoString value;
+
+ //////////////
+ // see if the opening fence is there ...
+ if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::open, value)) {
+ value = char16_t('('); // default as per the MathML REC
+ } else {
+ value.CompressWhitespace();
+ }
+
+ if (!value.IsEmpty()) {
+ mOpenChar = new nsMathMLChar;
+ mOpenChar->SetData(value);
+ ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar);
+ }
+
+ //////////////
+ // see if the closing fence is there ...
+ if(!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::close, value)) {
+ value = char16_t(')'); // default as per the MathML REC
+ } else {
+ value.CompressWhitespace();
+ }
+
+ if (!value.IsEmpty()) {
+ mCloseChar = new nsMathMLChar;
+ mCloseChar->SetData(value);
+ ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar);
+ }
+
+ //////////////
+ // see if separators are there ...
+ if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separators_, value)) {
+ value = char16_t(','); // default as per the MathML REC
+ } else {
+ value.StripWhitespace();
+ }
+
+ mSeparatorsCount = value.Length();
+ if (0 < mSeparatorsCount) {
+ int32_t sepCount = mFrames.GetLength() - 1;
+ if (0 < sepCount) {
+ mSeparatorsChar = new nsMathMLChar[sepCount];
+ nsAutoString sepChar;
+ for (int32_t i = 0; i < sepCount; i++) {
+ if (i < mSeparatorsCount) {
+ sepChar = value[i];
+ }
+ else {
+ sepChar = value[mSeparatorsCount-1];
+ }
+ mSeparatorsChar[i].SetData(sepChar);
+ ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i]);
+ }
+ mSeparatorsCount = sepCount;
+ } else {
+ // No separators. Note that sepCount can be -1 here, so don't
+ // set mSeparatorsCount to it.
+ mSeparatorsCount = 0;
+ }
+ }
+}
+
+void
+nsMathMLmfencedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists)
+{
+ /////////////
+ // display the content
+ nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
+
+ ////////////
+ // display fences and separators
+ uint32_t count = 0;
+ if (mOpenChar) {
+ mOpenChar->Display(aBuilder, this, aLists, count++);
+ }
+
+ if (mCloseChar) {
+ mCloseChar->Display(aBuilder, this, aLists, count++);
+ }
+
+ for (int32_t i = 0; i < mSeparatorsCount; i++) {
+ mSeparatorsChar[i].Display(aBuilder, this, aLists, count++);
+ }
+}
+
+/* @param aMetrics is an IN/OUT. Provide the current metrics for the mFenced
+ frame and it will be enlarged as necessary.
+For simplicity the width of the container is always incremented by the width
+of the nsMathMLChar. As we only stretch fences and separators in the vertical
+direction, this has no impact on overall appearance.
+*/
+static void
+ApplyUnstretchedMetrics(nsPresContext* aPresContext,
+ DrawTarget* aDrawTarget,
+ float aFontSizeInflation,
+ nsMathMLChar* aMathMLChar,
+ nsBoundingMetrics& aMetrics,
+ bool aIsRTL)
+{
+ if (aMathMLChar && 0 < aMathMLChar->Length()) {
+ nsBoundingMetrics charSize;
+ aMathMLChar->Stretch(aPresContext, aDrawTarget, aFontSizeInflation,
+ NS_STRETCH_DIRECTION_DEFAULT,
+ aMetrics, // size is unimportant as we aren't stretching
+ charSize, NS_STRETCH_NONE, aIsRTL);
+ aMetrics += charSize;
+ }
+}
+
+void
+nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus)
+{
+ MarkInReflow();
+ mPresentationData.flags &= ~NS_MATHML_ERROR;
+ aDesiredSize.ClearSize();
+ aDesiredSize.SetBlockStartAscent(0);
+ aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
+
+ int32_t i;
+ const nsStyleFont* font = StyleFont();
+ float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
+ RefPtr<nsFontMetrics> fm =
+ nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
+ nscoord axisHeight, em;
+ GetAxisHeight(aReflowInput.mRenderingContext->GetDrawTarget(), fm, axisHeight);
+ GetEmHeight(fm, em);
+ // leading to be left at the top and the bottom of stretched chars
+ nscoord leading = NSToCoordRound(0.2f * em);
+
+ /////////////
+ // Reflow children
+ // Asking each child to cache its bounding metrics
+
+ // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
+ // because we want to stretch our fences, separators and stretchy frames using
+ // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
+ // method here, our stretchy frames will be stretched and placed, and we may
+ // end up stretching our fences/separators with a different aDesiredSize.
+ // XXX The above decision was revisited in bug 121748 and this code can be
+ // refactored to use nsMathMLContainerFrame::Reflow() at some stage.
+
+ nsReflowStatus childStatus;
+ nsIFrame* firstChild = PrincipalChildList().FirstChild();
+ nsIFrame* childFrame = firstChild;
+ nscoord ascent = 0, descent = 0;
+ if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
+ // We use the ASCII metrics to get our minimum height. This way,
+ // if we have borders or a background, they will fit better with
+ // other elements on the line.
+ ascent = fm->MaxAscent();
+ descent = fm->MaxDescent();
+ }
+ while (childFrame) {
+ ReflowOutput childDesiredSize(aReflowInput,
+ aDesiredSize.mFlags
+ | NS_REFLOW_CALC_BOUNDING_METRICS);
+ WritingMode wm = childFrame->GetWritingMode();
+ LogicalSize availSize = aReflowInput.ComputedSize(wm);
+ availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
+ ReflowInput childReflowInput(aPresContext, aReflowInput,
+ childFrame, availSize);
+ ReflowChild(childFrame, aPresContext, childDesiredSize,
+ childReflowInput, childStatus);
+ //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
+ SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
+ childDesiredSize.mBoundingMetrics);
+
+ mozilla::WritingMode outerWM = aReflowInput.GetWritingMode();
+ nscoord childDescent = childDesiredSize.BSize(outerWM) -
+ childDesiredSize.BlockStartAscent();
+ if (descent < childDescent)
+ descent = childDescent;
+ if (ascent < childDesiredSize.BlockStartAscent())
+ ascent = childDesiredSize.BlockStartAscent();
+
+ childFrame = childFrame->GetNextSibling();
+ }
+
+ /////////////
+ // Ask stretchy children to stretch themselves
+
+ nsBoundingMetrics containerSize;
+ nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;
+
+ DrawTarget* drawTarget = aReflowInput.mRenderingContext->GetDrawTarget();
+
+ GetPreferredStretchSize(drawTarget,
+ 0, /* i.e., without embellishments */
+ stretchDir, containerSize);
+ childFrame = firstChild;
+ while (childFrame) {
+ nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame);
+ if (mathmlChild) {
+ ReflowOutput childDesiredSize(aReflowInput);
+ // retrieve the metrics that was stored at the previous pass
+ GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
+ childDesiredSize.mBoundingMetrics);
+
+ mathmlChild->Stretch(drawTarget,
+ stretchDir, containerSize, childDesiredSize);
+ // store the updated metrics
+ SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
+ childDesiredSize.mBoundingMetrics);
+
+ nscoord childDescent = childDesiredSize.Height() - childDesiredSize.BlockStartAscent();
+ if (descent < childDescent)
+ descent = childDescent;
+ if (ascent < childDesiredSize.BlockStartAscent())
+ ascent = childDesiredSize.BlockStartAscent();
+ }
+ childFrame = childFrame->GetNextSibling();
+ }
+
+ // bug 121748: for surrounding fences & separators, use a size that covers everything
+ GetPreferredStretchSize(drawTarget, STRETCH_CONSIDER_EMBELLISHMENTS,
+ stretchDir, containerSize);
+
+ bool isRTL = StyleVisibility()->mDirection;
+
+ // To achieve a minimum size of "1", the container should be enlarged by the
+ // unstretched metrics of the fences and separators.
+ ApplyUnstretchedMetrics(aPresContext, drawTarget,
+ fontSizeInflation, mOpenChar,
+ containerSize, isRTL);
+ for (i = 0; i < mSeparatorsCount; i++) {
+ ApplyUnstretchedMetrics(aPresContext, drawTarget,
+ fontSizeInflation, &mSeparatorsChar[i],
+ containerSize, isRTL);
+ }
+ ApplyUnstretchedMetrics(aPresContext, drawTarget,
+ fontSizeInflation, mCloseChar,
+ containerSize, isRTL);
+
+ //////////////////////////////////////////
+ // Prepare the opening fence, separators, and closing fence, and
+ // adjust the origin of children.
+
+ // we need to center around the axis
+ nscoord delta = std::max(containerSize.ascent - axisHeight,
+ containerSize.descent + axisHeight);
+ containerSize.ascent = delta + axisHeight;
+ containerSize.descent = delta - axisHeight;
+
+ /////////////////
+ // opening fence ...
+ ReflowChar(aPresContext, drawTarget, *fm,
+ fontSizeInflation, mOpenChar,
+ NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel,
+ axisHeight, leading, em, containerSize, ascent, descent, isRTL);
+ /////////////////
+ // separators ...
+ for (i = 0; i < mSeparatorsCount; i++) {
+ ReflowChar(aPresContext, drawTarget, *fm,
+ fontSizeInflation, &mSeparatorsChar[i],
+ NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
+ axisHeight, leading, em, containerSize, ascent, descent, isRTL);
+ }
+ /////////////////
+ // closing fence ...
+ ReflowChar(aPresContext, drawTarget, *fm,
+ fontSizeInflation, mCloseChar,
+ NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
+ axisHeight, leading, em, containerSize, ascent, descent, isRTL);
+
+ //////////////////
+ // Adjust the origins of each child.
+ // and update our bounding metrics
+
+ i = 0;
+ nscoord dx = 0;
+ nsBoundingMetrics bm;
+ bool firstTime = true;
+ nsMathMLChar *leftChar, *rightChar;
+ if (isRTL) {
+ leftChar = mCloseChar;
+ rightChar = mOpenChar;
+ } else {
+ leftChar = mOpenChar;
+ rightChar = mCloseChar;
+ }
+
+ if (leftChar) {
+ PlaceChar(leftChar, ascent, bm, dx);
+ aDesiredSize.mBoundingMetrics = bm;
+ firstTime = false;
+ }
+
+ if (isRTL) {
+ childFrame = this->GetChildList(nsIFrame::kPrincipalList).LastChild();
+ } else {
+ childFrame = firstChild;
+ }
+ while (childFrame) {
+ ReflowOutput childSize(aReflowInput);
+ GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
+ if (firstTime) {
+ firstTime = false;
+ aDesiredSize.mBoundingMetrics = bm;
+ }
+ else
+ aDesiredSize.mBoundingMetrics += bm;
+
+ FinishReflowChild(childFrame, aPresContext, childSize, nullptr,
+ dx, ascent - childSize.BlockStartAscent(), 0);
+ dx += childSize.Width();
+
+ if (i < mSeparatorsCount) {
+ PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i],
+ ascent, bm, dx);
+ aDesiredSize.mBoundingMetrics += bm;
+ }
+ i++;
+
+ if (isRTL) {
+ childFrame = childFrame->GetPrevSibling();
+ } else {
+ childFrame = childFrame->GetNextSibling();
+ }
+ }
+
+ if (rightChar) {
+ PlaceChar(rightChar, ascent, bm, dx);
+ if (firstTime)
+ aDesiredSize.mBoundingMetrics = bm;
+ else
+ aDesiredSize.mBoundingMetrics += bm;
+ }
+
+ aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width;
+ aDesiredSize.Height() = ascent + descent;
+ aDesiredSize.SetBlockStartAscent(ascent);
+
+ SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
+ SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
+
+ // see if we should fix the spacing
+ FixInterFrameSpacing(aDesiredSize);
+
+ // Finished with these:
+ ClearSavedChildMetrics();
+
+ // Set our overflow area
+ GatherAndStoreOverflow(&aDesiredSize);
+
+ aStatus = NS_FRAME_COMPLETE;
+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
+}
+
+static void
+GetCharSpacing(nsMathMLChar* aMathMLChar,
+ nsOperatorFlags aForm,
+ int32_t aScriptLevel,
+ nscoord em,
+ nscoord& aLeftSpace,
+ nscoord& aRightSpace)
+{
+ nsAutoString data;
+ aMathMLChar->GetData(data);
+ nsOperatorFlags flags = 0;
+ float lspace = 0.0f;
+ float rspace = 0.0f;
+ bool found = nsMathMLOperators::LookupOperator(data, aForm,
+ &flags, &lspace, &rspace);
+
+ // We don't want extra space when we are a script
+ if (found && aScriptLevel > 0) {
+ lspace /= 2.0f;
+ rspace /= 2.0f;
+ }
+
+ aLeftSpace = NSToCoordRound(lspace * em);
+ aRightSpace = NSToCoordRound(rspace * em);
+}
+
+// helper functions to perform the common task of formatting our chars
+/*static*/ nsresult
+nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
+ DrawTarget* aDrawTarget,
+ nsFontMetrics& aFontMetrics,
+ float aFontSizeInflation,
+ nsMathMLChar* aMathMLChar,
+ nsOperatorFlags aForm,
+ int32_t aScriptLevel,
+ nscoord axisHeight,
+ nscoord leading,
+ nscoord em,
+ nsBoundingMetrics& aContainerSize,
+ nscoord& aAscent,
+ nscoord& aDescent,
+ bool aRTL)
+{
+ if (aMathMLChar && 0 < aMathMLChar->Length()) {
+ nscoord leftSpace;
+ nscoord rightSpace;
+ GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
+
+ // stretch the char to the appropriate height if it is not big enough.
+ nsBoundingMetrics charSize;
+ nsresult res = aMathMLChar->Stretch(aPresContext, aDrawTarget,
+ aFontSizeInflation,
+ NS_STRETCH_DIRECTION_VERTICAL,
+ aContainerSize, charSize,
+ NS_STRETCH_NORMAL, aRTL);
+
+ if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
+ // has changed... so center the char around the axis
+ nscoord height = charSize.ascent + charSize.descent;
+ charSize.ascent = height/2 + axisHeight;
+ charSize.descent = height - charSize.ascent;
+ }
+ else {
+ // either it hasn't changed or stretching the char failed (i.e.,
+ // nsLayoutUtils::AppUnitBoundsOfString failed)
+ leading = 0;
+ if (NS_FAILED(res)) {
+ nsAutoString data;
+ aMathMLChar->GetData(data);
+ nsBoundingMetrics metrics =
+ nsLayoutUtils::AppUnitBoundsOfString(data.get(), data.Length(),
+ aFontMetrics, aDrawTarget);
+ charSize.ascent = metrics.ascent;
+ charSize.descent = metrics.descent;
+ charSize.width = metrics.width;
+ // Set this as the bounding metrics of the MathMLChar to leave
+ // the necessary room to paint the char.
+ aMathMLChar->SetBoundingMetrics(charSize);
+ }
+ }
+
+ if (aAscent < charSize.ascent + leading)
+ aAscent = charSize.ascent + leading;
+ if (aDescent < charSize.descent + leading)
+ aDescent = charSize.descent + leading;
+
+ // account the spacing
+ charSize.width += leftSpace + rightSpace;
+
+ // x-origin is used to store lspace ...
+ // y-origin is used to stored the ascent ...
+ aMathMLChar->SetRect(nsRect(leftSpace,
+ charSize.ascent, charSize.width,
+ charSize.ascent + charSize.descent));
+ }
+ return NS_OK;
+}
+
+/*static*/ void
+nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar,
+ nscoord aDesiredAscent,
+ nsBoundingMetrics& bm,
+ nscoord& dx)
+{
+ aMathMLChar->GetBoundingMetrics(bm);
+
+ // the char's x-origin was used to store lspace ...
+ // the char's y-origin was used to store the ascent ...
+ // the char's width was used to store the advance with (with spacing) ...
+ nsRect rect;
+ aMathMLChar->GetRect(rect);
+
+ nscoord dy = aDesiredAscent - rect.y;
+ if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) {
+ // the stretchy char will be centered around the axis
+ // so we adjust the returned bounding metrics accordingly
+ bm.descent = (bm.ascent + bm.descent) - rect.y;
+ bm.ascent = rect.y;
+ }
+
+ aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height));
+
+ bm.leftBearing += rect.x;
+ bm.rightBearing += rect.x;
+
+ // return rect.width since it includes lspace and rspace
+ bm.width = rect.width;
+ dx += rect.width;
+}
+
+static nscoord
+GetMaxCharWidth(nsPresContext* aPresContext,
+ DrawTarget* aDrawTarget,
+ float aFontSizeInflation,
+ nsMathMLChar* aMathMLChar,
+ nsOperatorFlags aForm,
+ int32_t aScriptLevel,
+ nscoord em)
+{
+ nscoord width = aMathMLChar->GetMaxWidth(aPresContext, aDrawTarget,
+ aFontSizeInflation);
+
+ if (0 < aMathMLChar->Length()) {
+ nscoord leftSpace;
+ nscoord rightSpace;
+ GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
+
+ width += leftSpace + rightSpace;
+ }
+
+ return width;
+}
+
+/* virtual */ void
+nsMathMLmfencedFrame::GetIntrinsicISizeMetrics(nsRenderingContext* aRenderingContext, ReflowOutput& aDesiredSize)
+{
+ nscoord width = 0;
+
+ nsPresContext* presContext = PresContext();
+ const nsStyleFont* font = StyleFont();
+ float fontSizeInflation = nsLayoutUtils:: FontSizeInflationFor(this);
+ RefPtr<nsFontMetrics> fm =
+ nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
+ nscoord em;
+ GetEmHeight(fm, em);
+
+ if (mOpenChar) {
+ width +=
+ GetMaxCharWidth(presContext, aRenderingContext->GetDrawTarget(),
+ fontSizeInflation, mOpenChar,
+ NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em);
+ }
+
+ int32_t i = 0;
+ for (nsIFrame* childFrame : PrincipalChildList()) {
+ // XXX This includes margin while Reflow currently doesn't consider
+ // margin, so we may end up with too much space, but, with stretchy
+ // characters, this is an approximation anyway.
+ width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
+ nsLayoutUtils::PREF_ISIZE);
+
+ if (i < mSeparatorsCount) {
+ width +=
+ GetMaxCharWidth(presContext, aRenderingContext->GetDrawTarget(),
+ fontSizeInflation, &mSeparatorsChar[i],
+ NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em);
+ }
+ i++;
+ }
+
+ if (mCloseChar) {
+ width +=
+ GetMaxCharWidth(presContext, aRenderingContext->GetDrawTarget(),
+ fontSizeInflation, mCloseChar,
+ NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
+ }
+
+ aDesiredSize.Width() = width;
+ aDesiredSize.mBoundingMetrics.width = width;
+ aDesiredSize.mBoundingMetrics.leftBearing = 0;
+ aDesiredSize.mBoundingMetrics.rightBearing = width;
+}
+
+nscoord
+nsMathMLmfencedFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
+{
+ nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
+ if (!gap) return 0;
+
+ nsRect rect;
+ if (mOpenChar) {
+ mOpenChar->GetRect(rect);
+ rect.MoveBy(gap, 0);
+ mOpenChar->SetRect(rect);
+ }
+ if (mCloseChar) {
+ mCloseChar->GetRect(rect);
+ rect.MoveBy(gap, 0);
+ mCloseChar->SetRect(rect);
+ }
+ for (int32_t i = 0; i < mSeparatorsCount; i++) {
+ mSeparatorsChar[i].GetRect(rect);
+ rect.MoveBy(gap, 0);
+ mSeparatorsChar[i].SetRect(rect);
+ }
+ return gap;
+}
+
+// ----------------------
+// the Style System will use these to pass the proper style context to our MathMLChar
+nsStyleContext*
+nsMathMLmfencedFrame::GetAdditionalStyleContext(int32_t aIndex) const
+{
+ int32_t openIndex = -1;
+ int32_t closeIndex = -1;
+ int32_t lastIndex = mSeparatorsCount-1;
+
+ if (mOpenChar) {
+ lastIndex++;
+ openIndex = lastIndex;
+ }
+ if (mCloseChar) {
+ lastIndex++;
+ closeIndex = lastIndex;
+ }
+ if (aIndex < 0 || aIndex > lastIndex) {
+ return nullptr;
+ }
+
+ if (aIndex < mSeparatorsCount) {
+ return mSeparatorsChar[aIndex].GetStyleContext();
+ }
+ else if (aIndex == openIndex) {
+ return mOpenChar->GetStyleContext();
+ }
+ else if (aIndex == closeIndex) {
+ return mCloseChar->GetStyleContext();
+ }
+ return nullptr;
+}
+
+void
+nsMathMLmfencedFrame::SetAdditionalStyleContext(int32_t aIndex,
+ nsStyleContext* aStyleContext)
+{
+ int32_t openIndex = -1;
+ int32_t closeIndex = -1;
+ int32_t lastIndex = mSeparatorsCount-1;
+
+ if (mOpenChar) {
+ lastIndex++;
+ openIndex = lastIndex;
+ }
+ if (mCloseChar) {
+ lastIndex++;
+ closeIndex = lastIndex;
+ }
+ if (aIndex < 0 || aIndex > lastIndex) {
+ return;
+ }
+
+ if (aIndex < mSeparatorsCount) {
+ mSeparatorsChar[aIndex].SetStyleContext(aStyleContext);
+ }
+ else if (aIndex == openIndex) {
+ mOpenChar->SetStyleContext(aStyleContext);
+ }
+ else if (aIndex == closeIndex) {
+ mCloseChar->SetStyleContext(aStyleContext);
+ }
+}