NS_IMETHODIMP nsMathMLmfracFrame::TransmitAutomaticData() { // 1. The REC says: // The <mfrac> element sets displaystyle to "false", or if it was already // false increments scriptlevel by 1, within numerator and denominator. // 2. The TeXbook (Ch 17. p.141) says the numerator inherits the compression // while the denominator is compressed bool increment = !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags); SetIncrementScriptLevel(0, increment); SetIncrementScriptLevel(1, increment); UpdatePresentationDataFromChildAt(0, -1, ~NS_MATHML_DISPLAYSTYLE, NS_MATHML_DISPLAYSTYLE); UpdatePresentationDataFromChildAt(1, 1, NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED); // if our numerator is an embellished operator, let its state bubble to us GetEmbellishDataFrom(mFrames.FirstChild(), mEmbellishData); if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) { // even when embellished, we need to record that <mfrac> won't fire // Stretch() on its embellished child mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; } return NS_OK; }
NS_IMETHODIMP nsMathMLFrame::InheritAutomaticData(nsIFrame* aParent) { mEmbellishData.flags = 0; mEmbellishData.coreFrame = nullptr; mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; mEmbellishData.leadingSpace = 0; mEmbellishData.trailingSpace = 0; mPresentationData.flags = 0; mPresentationData.baseFrame = nullptr; mPresentationData.mstyle = nullptr; // by default, just inherit the display of our parent nsPresentationData parentData; GetPresentationDataFrom(aParent, parentData); mPresentationData.mstyle = parentData.mstyle; if (NS_MATHML_IS_DISPLAYSTYLE(parentData.flags)) { mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE; } if (NS_MATHML_IS_RTL(parentData.flags)) { mPresentationData.flags |= NS_MATHML_RTL; } #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX) mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; #endif return NS_OK; }
NS_IMETHODIMP nsMathMLmstyleFrame::UpdatePresentationDataFromChildAt(PRInt32 aFirstIndex, PRInt32 aLastIndex, PRInt32 aScriptLevelIncrement, PRUint32 aFlagsValues, PRUint32 aFlagsToUpdate) { // mstyle is special... // Since UpdatePresentationDataFromChildAt() can be called by a parent frame, // wee need to ensure that the attributes of mstyle take precedence if (NS_MATHML_IS_DISPLAYSTYLE(aFlagsToUpdate)) { if (NS_MATHML_IS_MSTYLE_WITH_DISPLAYSTYLE(mPresentationData.flags)) { // our current state takes precedence, updating is not allowed aFlagsToUpdate &= ~NS_MATHML_DISPLAYSTYLE; aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE; } } if (NS_MATHML_IS_MSTYLE_WITH_EXPLICIT_SCRIPTLEVEL(mPresentationData.flags)) { // our current state takes precedence, updating is not allowed aScriptLevelIncrement = 0; } // let the base class worry about the update return nsMathMLContainerFrame::UpdatePresentationDataFromChildAt( aFirstIndex, aLastIndex, aScriptLevelIncrement, aFlagsValues, aFlagsToUpdate); }
NS_IMETHODIMP nsMathMLmstyleFrame::UpdatePresentationData(PRInt32 aScriptLevelIncrement, PRUint32 aFlagsValues, PRUint32 aFlagsToUpdate) { // mstyle is special... // Since UpdatePresentationData() can be called by a parent frame, the // scriptlevel and displaystyle attributes of mstyle must take precedence. // Update only if attributes are not there // see if updating the displaystyle flag is allowed if (!NS_MATHML_IS_MSTYLE_WITH_DISPLAYSTYLE(mPresentationData.flags)) { // see if the displaystyle flag is relevant to this call if (NS_MATHML_IS_DISPLAYSTYLE(aFlagsToUpdate)) { if (NS_MATHML_IS_DISPLAYSTYLE(aFlagsValues)) { mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE; } else { mPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE; } } } // see if updating the scriptlevel is allowed if (!NS_MATHML_IS_MSTYLE_WITH_EXPLICIT_SCRIPTLEVEL(mPresentationData.flags)) { mPresentationData.scriptLevel += aScriptLevelIncrement; } // see if the compression flag is relevant to this call if (NS_MATHML_IS_COMPRESSED(aFlagsToUpdate)) { if (NS_MATHML_IS_COMPRESSED(aFlagsValues)) { // 'compressed' means 'prime' style in App. G, TeXbook mPresentationData.flags |= NS_MATHML_COMPRESSED; } // no else. the flag is sticky. it retains its value once it is set } return NS_OK; }
NS_IMETHODIMP nsMathMLmoverFrame::UpdatePresentationData(PRUint32 aFlagsValues, PRUint32 aFlagsToUpdate) { nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues, aFlagsToUpdate); // disable the stretch-all flag if we are going to act like a superscript if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; } else { mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; } return NS_OK; }
NS_IMETHODIMP nsMathMLFrame::UpdatePresentationData(PRUint32 aFlagsValues, PRUint32 aWhichFlags) { // update flags that are relevant to this call if (NS_MATHML_IS_DISPLAYSTYLE(aWhichFlags)) { // updating the displaystyle flag is allowed if (NS_MATHML_IS_DISPLAYSTYLE(aFlagsValues)) { mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE; } else { mPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE; } } if (NS_MATHML_IS_COMPRESSED(aWhichFlags)) { // updating the compression flag is allowed if (NS_MATHML_IS_COMPRESSED(aFlagsValues)) { // 'compressed' means 'prime' style in App. G, TeXbook mPresentationData.flags |= NS_MATHML_COMPRESSED; } // no else. the flag is sticky. it retains its value once it is set } return NS_OK; }
static uint32_t GetStretchHint(nsOperatorFlags aFlags, nsPresentationData aPresentationData, bool aIsVertical) { uint32_t stretchHint = NS_STRETCH_NONE; // See if it is okay to stretch, // starting from what the Operator Dictionary said if (NS_MATHML_OPERATOR_IS_MUTABLE(aFlags)) { // set the largeop or largeopOnly flags to suitably cover all the // 8 possible cases depending on whether displaystyle, largeop, // stretchy are true or false (see bug 69325). // . largeopOnly is taken if largeop=true and stretchy=false // . largeop is taken if largeop=true and stretchy=true if (NS_MATHML_IS_DISPLAYSTYLE(aPresentationData.flags) && NS_MATHML_OPERATOR_IS_LARGEOP(aFlags)) { stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!) if (NS_MATHML_OPERATOR_IS_INTEGRAL(aFlags)) { stretchHint |= NS_STRETCH_INTEGRAL; } if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) { stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER; } } else if(NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) { if (aIsVertical) { // TeX hint. Can impact some sloppy markups missing <mrow></mrow> stretchHint = NS_STRETCH_NEARER; } else { stretchHint = NS_STRETCH_NORMAL; } } // else if the stretchy and largeop attributes have been disabled, // the operator is not mutable } return stretchHint; }
/* virtual */ nsresult nsMathMLmoverFrame::Place(nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { // place like superscript return nsMathMLmsupFrame::PlaceSuperScript(PresContext(), aRenderingContext, aPlaceOrigin, aDesiredSize, this, 0, nsPresContext::CSSPointsToAppUnits(0.5f)); } //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmBase, bmOver; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics overSize; nsIFrame* overFrame = nsnull; nsIFrame* baseFrame = mFrames.FirstChild(); if (baseFrame) overFrame = baseFrame->GetNextSibling(); if (!baseFrame || !overFrame || overFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order return ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver); nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); //////////////////// // Place Children aRenderingContext.SetFont(GetStyleFont()->mFont, PresContext()->GetUserFontSet()); nsCOMPtr<nsIFontMetrics> fm; aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord xHeight = 0; fm->GetXHeight (xHeight); nscoord ruleThickness; GetRuleThickness (aRenderingContext, fm, ruleThickness); // there are 2 different types of placement depending on // whether we want an accented overscript or not nscoord correction = 0; GetItalicCorrection (bmBase, correction); nscoord delta1 = 0; // gap between base and overscript nscoord delta2 = 0; // extra space above overscript if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { // Rule 13a, App. G, TeXbook nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; GetBigOpSpacings (fm, bigOpSpacing1, dummy, bigOpSpacing3, dummy, bigOpSpacing5); delta1 = NS_MAX(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent)); delta2 = bigOpSpacing5; // XXX This is not a TeX rule... // delta1 (as computed above) can become really big when bmOver.descent is // negative, e.g., if the content is &OverBar. In such case, we use the height if (bmOver.descent < 0) delta1 = NS_MAX(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent))); } else { // Rule 12, App. G, TeXbook // We are going to modify this rule to make it more general. // The idea behind Rule 12 in the TeXBook is to keep the accent // as close to the base as possible, while ensuring that the // distance between the *baseline* of the accent char and // the *baseline* of the base is atleast x-height. // The idea is that for normal use, we would like all the accents // on a line to line up atleast x-height above the baseline // if possible. // When the ascent of the base is >= x-height, // the baseline of the accent char is placed just above the base // (specifically, the baseline of the accent char is placed // above the baseline of the base by the ascent of the base). // For ease of implementation, // this assumes that the font-designer designs accents // in such a way that the bottom of the accent is atleast x-height // above its baseline, otherwise there will be collisions // with the base. Also there should be proper padding between // the bottom of the accent char and its baseline. // The above rule may not be obvious from a first // reading of rule 12 in the TeXBook !!! // The mathml <mover> tag can use accent chars that // do not follow this convention. So we modify TeX's rule // so that TeX's rule gets subsumed for accents that follow // TeX's convention, // while also allowing accents that do not follow the convention : // we try to keep the *bottom* of the accent char atleast x-height // from the baseline of the base char. we also slap on an extra // padding between the accent and base chars. delta1 = ruleThickness + onePixel/2; // we have at least the padding if (bmBase.ascent < xHeight) { // also ensure at least x-height above the baseline of the base delta1 += xHeight - bmBase.ascent; } delta2 = ruleThickness; } // empty over? if (!(bmOver.ascent + bmOver.descent)) delta1 = 0; nscoord dxBase, dxOver = 0; // Ad-hoc - This is to override fonts which have ready-made _accent_ // glyphs with negative lbearing and rbearing. We want to position // the overscript ourselves nscoord overWidth = bmOver.width; if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) { overWidth = bmOver.rightBearing - bmOver.leftBearing; dxOver = -bmOver.leftBearing; } if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { mBoundingMetrics.width = bmBase.width; dxOver += correction + (mBoundingMetrics.width - overWidth)/2; } else { mBoundingMetrics.width = NS_MAX(bmBase.width, overWidth); dxOver += correction/2 + (mBoundingMetrics.width - overWidth)/2; } dxBase = (mBoundingMetrics.width - bmBase.width) / 2; mBoundingMetrics.ascent = bmOver.ascent + bmOver.descent + delta1 + bmBase.ascent; mBoundingMetrics.descent = bmBase.descent; mBoundingMetrics.leftBearing = NS_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing); mBoundingMetrics.rightBearing = NS_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing); aDesiredSize.ascent = NS_MAX(mBoundingMetrics.ascent + delta2, overSize.ascent + bmOver.descent + delta1 + bmBase.ascent); aDesiredSize.height = aDesiredSize.ascent + baseSize.height - baseSize.ascent; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { // place base nscoord dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, PresContext(), nsnull, baseSize, dxBase, dy, 0); // place overscript dy = aDesiredSize.ascent - mBoundingMetrics.ascent + bmOver.ascent - overSize.ascent; FinishReflowChild (overFrame, PresContext(), nsnull, overSize, dxOver, dy, 0); } return NS_OK; }
NS_IMETHODIMP nsMathMLmoverFrame::TransmitAutomaticData() { // At this stage, all our children are in sync and we can fully // resolve our own mEmbellishData struct //--------------------------------------------------------------------- /* The REC says: The default value of accent is false, unless overscript is an <mo> element or an embellished operator. If overscript is an <mo> element, the value of its accent attribute is used as the default value of accent. If overscript is an embellished operator, the accent attribute of the <mo> element at its core is used as the default value. As with all attributes, an explicitly given value overrides the default. XXX The winner is the outermost in conflicting settings like these: <mover accent='true'> <mi>...</mi> <mo accent='false'> ... </mo> </mover> */ nsIFrame* overscriptFrame = nsnull; nsIFrame* baseFrame = mFrames.FirstChild(); if (baseFrame) overscriptFrame = baseFrame->GetNextSibling(); // if our base is an embellished operator, let its state bubble to us (in particular, // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags // are reset to the default values of false if the base frame isn't embellished. mPresentationData.baseFrame = baseFrame; GetEmbellishDataFrom(baseFrame, mEmbellishData); // The default value of accent is false, unless the overscript is embellished // and its core <mo> is an accent nsEmbellishData embellishData; GetEmbellishDataFrom(overscriptFrame, embellishData); if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; else mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; // if we have an accent attribute, it overrides what the overscript said static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::_true, &nsGkAtoms::_false, nsnull}; switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::accent_, strings, eCaseMatters)) { case 0: mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; break; case 1: mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; break; } // disable the stretch-all flag if we are going to act like a superscript if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; // Now transmit any change that we want to our children so that they // can update their mPresentationData structs //--------------------------------------------------------------------- /* The REC says: Within overscript, <mover> always sets displaystyle to "false", but increments scriptlevel by 1 only when accent is "false". The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a say it shouldn't be compressed. However, The TeXBook says that math accents and \overline change uncramped styles to their cramped counterparts. */ SetIncrementScriptLevel(1, !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)); PRUint32 compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ? NS_MATHML_COMPRESSED : 0; PropagatePresentationDataFor(overscriptFrame, ~NS_MATHML_DISPLAYSTYLE | compress, NS_MATHML_DISPLAYSTYLE | compress); return NS_OK; }
NS_IMETHODIMP nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); nsReflowStatus childStatus; aDesiredSize.width = aDesiredSize.height = 0; aDesiredSize.ascent = 0; nsBoundingMetrics bmSqr, bmBase, bmIndex; nsRenderingContext& renderingContext = *aReflowState.rendContext; ////////////////// // Reflow Children PRInt32 count = 0; nsIFrame* baseFrame = nsnull; nsIFrame* indexFrame = nsnull; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics indexSize; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); if (NS_FAILED(rv)) { // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(mFrames.FirstChild(), childFrame); return rv; } if (0 == count) { // base baseFrame = childFrame; baseSize = childDesiredSize; bmBase = childDesiredSize.mBoundingMetrics; } else if (1 == count) { // index indexFrame = childFrame; indexSize = childDesiredSize; bmIndex = childDesiredSize.mBoundingMetrics; } count++; childFrame = childFrame->GetNextSibling(); } if (2 != count) { // report an error, encourage people to get their markups in order rv = ReflowError(renderingContext, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(mFrames.FirstChild(), childFrame); return rv; } //////////// // Prepare the radical symbol and the overline bar renderingContext.SetFont(GetStyleFont()->mFont, aPresContext->GetUserFontSet()); nsFontMetrics* fm = renderingContext.FontMetrics(); // For radical glyphs from TeX fonts and some of the radical glyphs from // Mathematica fonts, the thickness of the overline can be obtained from the // ascent of the glyph. Most fonts however have radical glyphs above the // baseline so no assumption can be made about the meaning of the ascent. nscoord ruleThickness, leading, em; GetRuleThickness(renderingContext, fm, ruleThickness); PRUnichar one = '1'; nsBoundingMetrics bmOne = renderingContext.GetBoundingMetrics(&one, 1); // get the leading to be left at the top of the resulting frame // this seems more reliable than using fm->GetLeading() on suspicious fonts GetEmHeight(fm, em); leading = nscoord(0.2f * em); // Rule 11, App. G, TeXbook // psi = clearance between rule and content nscoord phi = 0, psi = 0; if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) phi = fm->XHeight(); else phi = ruleThickness; psi = ruleThickness + phi/4; // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131) if (bmOne.ascent > bmBase.ascent) psi += bmOne.ascent - bmBase.ascent; // make sure that the rule appears on on screen nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); if (ruleThickness < onePixel) { ruleThickness = onePixel; } // adjust clearance psi to get an exact number of pixels -- this // gives a nicer & uniform look on stacked radicals (bug 130282) nscoord delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.descent = bmBase.ascent + bmBase.descent + psi; contSize.ascent = ruleThickness; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, renderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // Update the desired size for the container (like msqrt, index is not yet included) // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = NS_MAX(bmBase.descent, (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent)); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + NS_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.height = aDesiredSize.ascent + NS_MAX(baseSize.height - baseSize.ascent, mBoundingMetrics.descent + ruleThickness); aDesiredSize.width = mBoundingMetrics.width; ///////////// // Re-adjust the desired size to include the index. // the index is raised by some fraction of the height // of the radical, see \mroot macro in App. B, TexBook nscoord raiseIndexDelta = NSToCoordRound(0.6f * (bmSqr.ascent + bmSqr.descent)); nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical - (bmSqr.ascent + bmSqr.descent) // to bottom of radical + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index nscoord indexClearance = 0; if (mBoundingMetrics.ascent < indexRaisedAscent) { indexClearance = indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index mBoundingMetrics.ascent = indexRaisedAscent; nscoord descent = aDesiredSize.height - aDesiredSize.ascent; aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.height = aDesiredSize.ascent + descent; } nscoord dxIndex, dxSqr; GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr); // place the index nscoord dx = dxIndex; nscoord dy = aDesiredSize.ascent - (indexRaisedAscent + indexSize.ascent - bmIndex.ascent); FinishReflowChild(indexFrame, aPresContext, nsnull, indexSize, dx, dy, 0); // place the radical symbol and the radical bar dx = dxSqr; dy = indexClearance + leading; // leave a leading at the top mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx += bmSqr.width; mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness); // place the base dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild(baseFrame, aPresContext, nsnull, baseSize, dx, dy, 0); mReference.x = 0; mReference.y = aDesiredSize.ascent; mBoundingMetrics.width = dx + bmBase.width; mBoundingMetrics.leftBearing = NS_MIN(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing); mBoundingMetrics.rightBearing = dx + NS_MAX(bmBase.width, bmBase.rightBearing); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; GatherAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
// exported routine that both mover and msup share. // mover uses this when movablelimits is set. nsresult nsMathMLmsupFrame::PlaceSuperScript(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, nsMathMLContainerFrame* aFrame, nscoord aUserSupScriptShift, nscoord aScriptSpace) { // force the scriptSpace to be at least 1 pixel nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); aScriptSpace = std::max(onePixel, aScriptSpace); //////////////////////////////////// // Get the children's desired sizes nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics supScriptSize; nsBoundingMetrics bmBase, bmSupScript; nsIFrame* supScriptFrame = nullptr; nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); if (baseFrame) supScriptFrame = baseFrame->GetNextSibling(); if (!baseFrame || !supScriptFrame || supScriptFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order if (aPlaceOrigin) { aFrame->ReportChildCountError(); } return aFrame->ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); // get the supdrop from the supscript font nscoord supDrop; GetSupDropFromChild(supScriptFrame, supDrop); // parameter u, Rule 18a, App. G, TeXbook nscoord minSupScriptShift = bmBase.ascent - supDrop; ////////////////// // Place Children // get min supscript shift limit from x-height // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook nscoord xHeight = 0; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); xHeight = fm->XHeight(); nscoord minShiftFromXHeight = (nscoord) (bmSupScript.descent + (1.0f/4.0f) * xHeight); nscoord italicCorrection; GetItalicCorrection(bmBase, italicCorrection); // supScriptShift{1,2,3} // = minimum amount to shift the supscript up // = sup{1,2,3} in TeX // supScriptShift1 = superscriptshift attribute * x-height // Note that there are THREE values for supscript shifts depending // on the current style nscoord supScriptShift1, supScriptShift2, supScriptShift3; // Set supScriptShift{1,2,3} default from font GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); if (0 < aUserSupScriptShift) { // the user has set the superscriptshift attribute float scaler2 = ((float) supScriptShift2) / supScriptShift1; float scaler3 = ((float) supScriptShift3) / supScriptShift1; supScriptShift1 = std::max(supScriptShift1, aUserSupScriptShift); supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1); supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1); } // get sup script shift depending on current script level and display style // Rule 18c, App. G, TeXbook nscoord supScriptShift; nsPresentationData presentationData; aFrame->GetPresentationData (presentationData); if ( aFrame->GetStyleFont()->mScriptLevel == 0 && NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) && !NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style D in TeXbook supScriptShift = supScriptShift1; } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style C' in TeXbook = D',T',S',SS' supScriptShift = supScriptShift3; } else { // everything else = T,S,SS supScriptShift = supScriptShift2; } // get actual supscriptshift to be used // Rule 18c, App. G, TeXbook nscoord actualSupScriptShift = std::max(minSupScriptShift,std::max(supScriptShift,minShiftFromXHeight)); // bounding box nsBoundingMetrics boundingMetrics; boundingMetrics.ascent = std::max(bmBase.ascent, (bmSupScript.ascent + actualSupScriptShift)); boundingMetrics.descent = std::max(bmBase.descent, (bmSupScript.descent - actualSupScriptShift)); // leave aScriptSpace after superscript // add italicCorrection between base and superscript // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we // estimate the italic creation ourselves and it isn't the same as TeX italicCorrection += onePixel; boundingMetrics.width = bmBase.width + italicCorrection + bmSupScript.width + aScriptSpace; boundingMetrics.leftBearing = bmBase.leftBearing; boundingMetrics.rightBearing = bmBase.width + italicCorrection + bmSupScript.rightBearing; aFrame->SetBoundingMetrics(boundingMetrics); // reflow metrics aDesiredSize.ascent = std::max(baseSize.ascent, (supScriptSize.ascent + actualSupScriptShift)); aDesiredSize.height = aDesiredSize.ascent + std::max(baseSize.height - baseSize.ascent, (supScriptSize.height - supScriptSize.ascent - actualSupScriptShift)); aDesiredSize.width = boundingMetrics.width; aDesiredSize.mBoundingMetrics = boundingMetrics; aFrame->SetReference(nsPoint(0, aDesiredSize.ascent)); if (aPlaceOrigin) { nscoord dx, dy; // now place the base ... dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0); dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize, dx, dy, 0); // ... and supscript dx = aFrame->MirrorIfRTL(aDesiredSize.width, supScriptSize.width, bmBase.width + italicCorrection); dy = aDesiredSize.ascent - (supScriptSize.ascent + actualSupScriptShift); FinishReflowChild (supScriptFrame, aPresContext, nullptr, supScriptSize, dx, dy, 0); } return NS_OK; }
// exported routine that both munderover and msubsup share. // munderover uses this when movablelimits is set. nsresult nsMathMLmsubsupFrame::PlaceSubSupScript(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, nsMathMLContainerFrame* aFrame, nscoord aUserSubScriptShift, nscoord aUserSupScriptShift, nscoord aScriptSpace) { // force the scriptSpace to be atleast 1 pixel nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); aScriptSpace = NS_MAX(onePixel, aScriptSpace); //////////////////////////////////// // Get the children's desired sizes nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics subScriptSize; nsHTMLReflowMetrics supScriptSize; nsBoundingMetrics bmBase, bmSubScript, bmSupScript; nsIFrame* subScriptFrame = nsnull; nsIFrame* supScriptFrame = nsnull; nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); if (baseFrame) subScriptFrame = baseFrame->GetNextSibling(); if (subScriptFrame) supScriptFrame = subScriptFrame->GetNextSibling(); if (!baseFrame || !subScriptFrame || !supScriptFrame || supScriptFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order return aFrame->ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); // get the subdrop from the subscript font nscoord subDrop; GetSubDropFromChild(subScriptFrame, subDrop); // parameter v, Rule 18a, App. G, TeXbook nscoord minSubScriptShift = bmBase.descent + subDrop; // get the supdrop from the supscript font nscoord supDrop; GetSupDropFromChild(supScriptFrame, supDrop); // parameter u, Rule 18a, App. G, TeXbook nscoord minSupScriptShift = bmBase.ascent - supDrop; ////////////////// // Place Children ////////////////// ////////////////////////////////////////////////// // Get subscript shift // slightly different from nsMathMLmsubFrame.cpp ////////////////////////////////////////////////// // subScriptShift{1,2} // = minimum amount to shift the subscript down // = sub{1,2} in TeXbook // subScriptShift1 = subscriptshift attribute * x-height nscoord subScriptShift1, subScriptShift2; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); // get x-height (an ex) nscoord xHeight = fm->XHeight(); nscoord ruleSize; GetRuleThickness (aRenderingContext, fm, ruleSize); // Get subScriptShift{1,2} default from font GetSubScriptShifts (fm, subScriptShift1, subScriptShift2); if (0 < aUserSubScriptShift) { // the user has set the subscriptshift attribute float scaler = ((float) subScriptShift2) / subScriptShift1; subScriptShift1 = NS_MAX(subScriptShift1, aUserSubScriptShift); subScriptShift2 = NSToCoordRound(scaler * subScriptShift1); } // get a tentative value for subscriptshift // Rule 18d, App. G, TeXbook nscoord subScriptShift = NS_MAX(minSubScriptShift,NS_MAX(subScriptShift1,subScriptShift2)); ////////////////////////////////////////////////// // Get supscript shift // same code from nsMathMLmsupFrame.cpp ////////////////////////////////////////////////// // get min supscript shift limit from x-height // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook nscoord minShiftFromXHeight = (nscoord) (bmSupScript.descent + (1.0f/4.0f) * xHeight); // supScriptShift{1,2,3} // = minimum amount to shift the supscript up // = sup{1,2,3} in TeX // supScriptShift1 = superscriptshift attribute * x-height // Note that there are THREE values for supscript shifts depending // on the current style nscoord supScriptShift1, supScriptShift2, supScriptShift3; // Set supScriptShift{1,2,3} default from font GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); if (0 < aUserSupScriptShift) { // the user has set the superscriptshift attribute float scaler2 = ((float) supScriptShift2) / supScriptShift1; float scaler3 = ((float) supScriptShift3) / supScriptShift1; supScriptShift1 = NS_MAX(supScriptShift1, aUserSupScriptShift); supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1); supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1); } // get sup script shift depending on current script level and display style // Rule 18c, App. G, TeXbook nscoord supScriptShift; nsPresentationData presentationData; aFrame->GetPresentationData(presentationData); if ( aFrame->GetStyleFont()->mScriptLevel == 0 && NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) && !NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style D in TeXbook supScriptShift = supScriptShift1; } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style C' in TeXbook = D',T',S',SS' supScriptShift = supScriptShift3; } else { // everything else = T,S,SS supScriptShift = supScriptShift2; } // get tentative value for superscriptshift // Rule 18c, App. G, TeXbook supScriptShift = NS_MAX(minSupScriptShift,NS_MAX(supScriptShift,minShiftFromXHeight)); ////////////////////////////////////////////////// // Negotiate between supScriptShift and subScriptShift // so that there will be enough gap between them // Rule 18e, App. G, TeXbook ////////////////////////////////////////////////// nscoord gap = (supScriptShift - bmSupScript.descent) - (bmSubScript.ascent - subScriptShift); if (gap < 4.0f * ruleSize) { // adjust subScriptShift to get a gap of (4.0 * ruleSize) subScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap); } // next we want to ensure that the bottom of the superscript // will be > (4/5) * x-height above baseline gap = NSToCoordRound ((4.0f/5.0f) * xHeight - (supScriptShift - bmSupScript.descent)); if (gap > 0) { supScriptShift += gap; subScriptShift -= gap; } ////////////////////////////////////////////////// // Do the Placing ////////////////////////////////////////////////// // get bounding box for base + subscript + superscript nsBoundingMetrics boundingMetrics; boundingMetrics.ascent = NS_MAX(bmBase.ascent, (bmSupScript.ascent + supScriptShift)); boundingMetrics.descent = NS_MAX(bmBase.descent, (bmSubScript.descent + subScriptShift)); // leave aScriptSpace after both super/subscript // add italicCorrection between base and superscript // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we // estimate the italic creation ourselves and it isn't the same as TeX nscoord italicCorrection; GetItalicCorrection(bmBase, italicCorrection); italicCorrection += onePixel; boundingMetrics.width = bmBase.width + aScriptSpace + NS_MAX((italicCorrection + bmSupScript.width), bmSubScript.width); boundingMetrics.leftBearing = bmBase.leftBearing; boundingMetrics.rightBearing = bmBase.width + NS_MAX((italicCorrection + bmSupScript.rightBearing), bmSubScript.rightBearing); aFrame->SetBoundingMetrics(boundingMetrics); // reflow metrics aDesiredSize.ascent = NS_MAX(baseSize.ascent, NS_MAX(subScriptSize.ascent - subScriptShift, supScriptSize.ascent + supScriptShift)); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(baseSize.height - baseSize.ascent, NS_MAX(subScriptSize.height - subScriptSize.ascent + subScriptShift, supScriptSize.height - subScriptSize.ascent - supScriptShift)); aDesiredSize.width = boundingMetrics.width; aDesiredSize.mBoundingMetrics = boundingMetrics; aFrame->SetReference(nsPoint(0, aDesiredSize.ascent)); if (aPlaceOrigin) { nscoord dx, dy; // now place the base ... dx = 0; dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild(baseFrame, aPresContext, nsnull, baseSize, dx, dy, 0); // ... and subscript dx = bmBase.width; dy = aDesiredSize.ascent - (subScriptSize.ascent - subScriptShift); FinishReflowChild(subScriptFrame, aPresContext, nsnull, subScriptSize, dx, dy, 0); // ... and the superscript dx = bmBase.width + italicCorrection; dy = aDesiredSize.ascent - (supScriptSize.ascent + supScriptShift); FinishReflowChild(supScriptFrame, aPresContext, nsnull, supScriptSize, dx, dy, 0); } return NS_OK; }
nsresult nsMathMLmfracFrame::PlaceInternal(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, bool aWidthOnly) { //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmNum, bmDen; nsHTMLReflowMetrics sizeNum; nsHTMLReflowMetrics sizeDen; nsIFrame* frameDen = nsnull; nsIFrame* frameNum = mFrames.FirstChild(); if (frameNum) frameDen = frameNum->GetNextSibling(); if (!frameNum || !frameDen || frameDen->GetNextSibling()) { // report an error, encourage people to get their markups in order return ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum); GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen); nsPresContext* presContext = PresContext(); nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); nscoord defaultRuleThickness, axisHeight; GetRuleThickness(aRenderingContext, fm, defaultRuleThickness); GetAxisHeight(aRenderingContext, fm, axisHeight); nsEmbellishData coreData; GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData); // see if the linethickness attribute is there nsAutoString value; GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::linethickness_, value); mLineThickness = CalcLineThickness(presContext, mStyleContext, value, onePixel, defaultRuleThickness); // bevelled attribute GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::bevelled_, value); mIsBevelled = value.EqualsLiteral("true"); if (!mIsBevelled) { mLineRect.height = mLineThickness; // by default, leave at least one-pixel padding at either end, or use // lspace & rspace that may come from <mo> if we are an embellished // container (we fetch values from the core since they may use units that // depend on style data, and style changes could have occurred in the // core since our last visit there) nscoord leftSpace = NS_MAX(onePixel, coreData.leftSpace); nscoord rightSpace = NS_MAX(onePixel, coreData.rightSpace); ////////////////// // Get shifts nscoord numShift = 0; nscoord denShift = 0; // Rule 15b, App. G, TeXbook nscoord numShift1, numShift2, numShift3; nscoord denShift1, denShift2; GetNumeratorShifts(fm, numShift1, numShift2, numShift3); GetDenominatorShifts(fm, denShift1, denShift2); if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { // C > T numShift = numShift1; denShift = denShift1; } else { numShift = (0 < mLineRect.height) ? numShift2 : numShift3; denShift = denShift2; } nscoord minClearance = 0; nscoord actualClearance = 0; nscoord actualRuleThickness = mLineThickness; if (0 == actualRuleThickness) { // Rule 15c, App. G, TeXbook // min clearance between numerator and denominator minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? 7 * defaultRuleThickness : 3 * defaultRuleThickness; actualClearance = (numShift - bmNum.descent) - (bmDen.ascent - denShift); // actualClearance should be >= minClearance if (actualClearance < minClearance) { nscoord halfGap = (minClearance - actualClearance)/2; numShift += halfGap; denShift += halfGap; } } else { // Rule 15d, App. G, TeXbook // min clearance between numerator or denominator and middle of bar // TeX has a different interpretation of the thickness. // Try $a \above10pt b$ to see. Here is what TeX does: // minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? // 3 * actualRuleThickness : actualRuleThickness; // we slightly depart from TeX here. We use the defaultRuleThickness instead // of the value coming from the linethickness attribute, i.e., we recover what // TeX does if the user hasn't set linethickness. But when the linethickness // is set, we avoid the wide gap problem. minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? 3 * defaultRuleThickness : defaultRuleThickness + onePixel; // adjust numShift to maintain minClearance if needed actualClearance = (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2); if (actualClearance < minClearance) { numShift += (minClearance - actualClearance); } // adjust denShift to maintain minClearance if needed actualClearance = (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift); if (actualClearance < minClearance) { denShift += (minClearance - actualClearance); } } ////////////////// // Place Children // XXX Need revisiting the width. TeX uses the exact width // e.g. in $$\huge\frac{\displaystyle\int}{i}$$ nscoord width = NS_MAX(bmNum.width, bmDen.width); nscoord dxNum = leftSpace + (width - sizeNum.width)/2; nscoord dxDen = leftSpace + (width - sizeDen.width)/2; width += leftSpace + rightSpace; // see if the numalign attribute is there GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::numalign_, value); if (value.EqualsLiteral("left")) dxNum = leftSpace; else if (value.EqualsLiteral("right")) dxNum = width - rightSpace - sizeNum.width; // see if the denomalign attribute is there GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::denomalign_, value); if (value.EqualsLiteral("left")) dxDen = leftSpace; else if (value.EqualsLiteral("right")) dxDen = width - rightSpace - sizeDen.width; mBoundingMetrics.rightBearing = NS_MAX(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing); if (mBoundingMetrics.rightBearing < width - rightSpace) mBoundingMetrics.rightBearing = width - rightSpace; mBoundingMetrics.leftBearing = NS_MIN(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing); if (mBoundingMetrics.leftBearing > leftSpace) mBoundingMetrics.leftBearing = leftSpace; mBoundingMetrics.ascent = bmNum.ascent + numShift; mBoundingMetrics.descent = bmDen.descent + denShift; mBoundingMetrics.width = width; aDesiredSize.ascent = sizeNum.ascent + numShift; aDesiredSize.height = aDesiredSize.ascent + sizeDen.height - sizeDen.ascent + denShift; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dy; // place numerator dy = 0; FinishReflowChild(frameNum, presContext, nsnull, sizeNum, dxNum, dy, 0); // place denominator dy = aDesiredSize.height - sizeDen.height; FinishReflowChild(frameDen, presContext, nsnull, sizeDen, dxDen, dy, 0); // place the fraction bar - dy is top of bar dy = aDesiredSize.ascent - (axisHeight + actualRuleThickness/2); mLineRect.SetRect(leftSpace, dy, width - (leftSpace + rightSpace), actualRuleThickness); } } else { nscoord numShift = 0.0; nscoord denShift = 0.0; nscoord padding = 3 * defaultRuleThickness; nscoord slashRatio = 3; // Define the constant used in the expression of the maximum width nscoord em = fm->EmHeight(); nscoord slashMaxWidthConstant = 2 * em; // For large line thicknesses the minimum slash height is limited to the // largest expected height of a fraction nscoord slashMinHeight = slashRatio * NS_MIN(2 * mLineThickness, slashMaxWidthConstant); nscoord leftSpace = NS_MAX(padding, coreData.leftSpace); nscoord rightSpace = NS_MAX(padding, coreData.rightSpace); nscoord delta; // ___________ // | | / // {|-NUMERATOR-| / // {|___________| S // { L // numShift{ A // ------------------------------------------------------- baseline // S _____________ } denShift // H | |} // / |-DENOMINATOR-|} // / |_____________| // // first, ensure that the top of the numerator is at least as high as the // top of the denominator (and the reverse for the bottoms) delta = NS_MAX(bmDen.ascent - bmNum.ascent, bmNum.descent - bmDen.descent) / 2; if (delta > 0) { numShift += delta; denShift += delta; } if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { delta = NS_MIN(bmDen.ascent + bmDen.descent, bmNum.ascent + bmNum.descent) / 2; numShift += delta; denShift += delta; } else { nscoord xHeight = fm->XHeight(); numShift += xHeight / 2; denShift += xHeight / 4; } // Set the ascent/descent of our BoundingMetrics. mBoundingMetrics.ascent = bmNum.ascent + numShift; mBoundingMetrics.descent = bmDen.descent + denShift; // At this point the height of the slash is // mBoundingMetrics.ascent + mBoundingMetrics.descent // Ensure that it is greater than slashMinHeight delta = (slashMinHeight - (mBoundingMetrics.ascent + mBoundingMetrics.descent)) / 2; if (delta > 0) { mBoundingMetrics.ascent += delta; mBoundingMetrics.descent += delta; } // Set the width of the slash if (aWidthOnly) { mLineRect.width = mLineThickness + slashMaxWidthConstant; } else { mLineRect.width = mLineThickness + NS_MIN(slashMaxWidthConstant, (mBoundingMetrics.ascent + mBoundingMetrics.descent) / slashRatio); } // Set horizontal bounding metrics mBoundingMetrics.leftBearing = leftSpace + bmNum.leftBearing; mBoundingMetrics.rightBearing = leftSpace + bmNum.width + mLineRect.width + bmDen.rightBearing; mBoundingMetrics.width = leftSpace + bmNum.width + mLineRect.width + bmDen.width + rightSpace; // Set aDesiredSize aDesiredSize.ascent = mBoundingMetrics.ascent + padding; aDesiredSize.height = mBoundingMetrics.ascent + mBoundingMetrics.descent + 2 * padding; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { FinishReflowChild(frameNum, presContext, nsnull, sizeNum, leftSpace, aDesiredSize.ascent - numShift - sizeNum.ascent, 0); mLineRect.SetRect(leftSpace + bmNum.width, aDesiredSize.ascent - mBoundingMetrics.ascent, mLineRect.width, aDesiredSize.height - 2 * padding); FinishReflowChild(frameDen, presContext, nsnull, sizeDen, leftSpace + bmNum.width + mLineRect.width, aDesiredSize.ascent + denShift - sizeDen.ascent, 0); } } return NS_OK; }
/* virtual */ nsresult nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, bool aWidthOnly) { /////////////// // Measure the size of our content using the base class to format like an // inferred mrow. nsHTMLReflowMetrics baseSize; nsresult rv = nsMathMLContainerFrame::Place(aRenderingContext, false, baseSize); if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { DidReflowChildren(GetFirstPrincipalChild()); return rv; } nsBoundingMetrics bmBase = baseSize.mBoundingMetrics; nscoord dx_left = 0, dx_right = 0; nsBoundingMetrics bmLongdivChar, bmRadicalChar; nscoord radicalAscent = 0, radicalDescent = 0; nscoord longdivAscent = 0, longdivDescent = 0; nscoord psi = 0; /////////////// // Thickness of bars and font metrics nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); nscoord mEmHeight; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); GetRuleThickness(aRenderingContext, fm, mRuleThickness); GetEmHeight(fm, mEmHeight); PRUnichar one = '1'; nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1); /////////////// // General rules: the menclose element takes the size of the enclosed content. // We add a padding when needed. // determine padding & psi nscoord padding = 3 * mRuleThickness; nscoord delta = padding % onePixel; if (delta) padding += onePixel - delta; // round up if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) { nscoord phi; // Rule 11, App. G, TeXbook // psi = clearance between rule and content if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) phi = fm->XHeight(); else phi = mRuleThickness; psi = mRuleThickness + phi / 4; delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up } if (mRuleThickness < onePixel) mRuleThickness = onePixel; // Set horizontal parameters if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) dx_left = padding; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) dx_right = padding; // Set vertical parameters if (IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_RADICAL) || IsToDraw(NOTATION_LONGDIV)) { // set a minimal value for the base height bmBase.ascent = NS_MAX(bmOne.ascent, bmBase.ascent); bmBase.descent = NS_MAX(0, bmBase.descent); } mBoundingMetrics.ascent = bmBase.ascent; mBoundingMetrics.descent = bmBase.descent; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_CIRCLE)) mBoundingMetrics.ascent += padding; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) mBoundingMetrics.descent += padding; /////////////// // circle notation: we don't want the ellipse to overlap the enclosed // content. Hence, we need to increase the size of the bounding box by a // factor of at least sqrt(2). if (IsToDraw(NOTATION_CIRCLE)) { double ratio = (sqrt(2.0) - 1.0) / 2.0; nscoord padding2; // Update horizontal parameters padding2 = ratio * bmBase.width; dx_left = NS_MAX(dx_left, padding2); dx_right = NS_MAX(dx_right, padding2); // Update vertical parameters padding2 = ratio * (bmBase.ascent + bmBase.descent); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, bmBase.ascent + padding2); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, bmBase.descent + padding2); } /////////////// // longdiv notation: if (IsToDraw(NOTATION_LONGDIV)) { if (aWidthOnly) { nscoord longdiv_width = mMathMLChar[mLongDivCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters dx_left = NS_MAX(dx_left, longdiv_width); } else { // Stretch the parenthesis to the appropriate height if it is not // big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = mRuleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(longdiv) should be >= height(base) + psi + mRuleThickness mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aRenderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, bmLongdivChar, NS_STRETCH_LARGER, false); mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar); // Update horizontal parameters dx_left = NS_MAX(dx_left, bmLongdivChar.width); // Update vertical parameters longdivAscent = bmBase.ascent + psi + mRuleThickness; longdivDescent = NS_MAX(bmBase.descent, (bmLongdivChar.ascent + bmLongdivChar.descent - longdivAscent)); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, longdivAscent); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, longdivDescent); } } /////////////// // radical notation: if (IsToDraw(NOTATION_RADICAL)) { nscoord *dx_leading = NS_MATHML_IS_RTL(mPresentationData.flags) ? &dx_right : &dx_left; if (aWidthOnly) { nscoord radical_width = mMathMLChar[mRadicalCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters *dx_leading = NS_MAX(*dx_leading, radical_width); } else { // Stretch the radical symbol to the appropriate height if it is not // big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = mRuleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(radical) should be >= height(base) + psi + mRuleThickness mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, bmRadicalChar, NS_STRETCH_LARGER, NS_MATHML_IS_RTL(mPresentationData.flags)); mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar); // Update horizontal parameters *dx_leading = NS_MAX(*dx_leading, bmRadicalChar.width); // Update vertical parameters radicalAscent = bmBase.ascent + psi + mRuleThickness; radicalDescent = NS_MAX(bmBase.descent, (bmRadicalChar.ascent + bmRadicalChar.descent - radicalAscent)); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, radicalAscent); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, radicalDescent); } } /////////////// // if (IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) { // center the menclose around the content (horizontally) dx_left = dx_right = NS_MAX(dx_left, dx_right); } /////////////// // The maximum size is now computed: set the remaining parameters mBoundingMetrics.width = dx_left + bmBase.width + dx_right; mBoundingMetrics.leftBearing = NS_MIN(0, dx_left + bmBase.leftBearing); mBoundingMetrics.rightBearing = NS_MAX(mBoundingMetrics.width, dx_left + bmBase.rightBearing); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.ascent = NS_MAX(mBoundingMetrics.ascent, baseSize.ascent); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(mBoundingMetrics.descent, baseSize.height - baseSize.ascent); if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) { // get the leading to be left at the top of the resulting frame // this seems more reliable than using fm->GetLeading() on suspicious // fonts nscoord leading = nscoord(0.2f * mEmHeight); nscoord desiredSizeAscent = aDesiredSize.ascent; nscoord desiredSizeDescent = aDesiredSize.height - aDesiredSize.ascent; if (IsToDraw(NOTATION_LONGDIV)) { desiredSizeAscent = NS_MAX(desiredSizeAscent, longdivAscent + leading); desiredSizeDescent = NS_MAX(desiredSizeDescent, longdivDescent + mRuleThickness); } if (IsToDraw(NOTATION_RADICAL)) { desiredSizeAscent = NS_MAX(desiredSizeAscent, radicalAscent + leading); desiredSizeDescent = NS_MAX(desiredSizeDescent, radicalDescent + mRuleThickness); } aDesiredSize.ascent = desiredSizeAscent; aDesiredSize.height = desiredSizeAscent + desiredSizeDescent; } if (IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) { // center the menclose around the content (vertically) nscoord dy = NS_MAX(aDesiredSize.ascent - bmBase.ascent, aDesiredSize.height - aDesiredSize.ascent - bmBase.descent); aDesiredSize.ascent = bmBase.ascent + dy; aDesiredSize.height = aDesiredSize.ascent + bmBase.descent + dy; } // Update mBoundingMetrics ascent/descent if (IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.ascent = aDesiredSize.ascent; if (IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.descent = aDesiredSize.height - aDesiredSize.ascent; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { ////////////////// // Set position and size of MathMLChars if (IsToDraw(NOTATION_LONGDIV)) mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left - bmLongdivChar.width, aDesiredSize.ascent - longdivAscent, bmLongdivChar.width, bmLongdivChar.ascent + bmLongdivChar.descent)); if (IsToDraw(NOTATION_RADICAL)) { nscoord dx = NS_MATHML_IS_RTL(mPresentationData.flags) ? dx_left + bmBase.width : dx_left - bmRadicalChar.width; mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx, aDesiredSize.ascent - radicalAscent, bmRadicalChar.width, bmRadicalChar.ascent + bmRadicalChar.descent)); } mContentWidth = bmBase.width; ////////////////// // Finish reflowing child frames PositionRowChildFrames(dx_left, aDesiredSize.ascent); } return NS_OK; }
/* virtual */ nsresult nsMathMLmfracFrame::Place(nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmNum, bmDen; nsHTMLReflowMetrics sizeNum; nsHTMLReflowMetrics sizeDen; nsIFrame* frameDen = nsnull; nsIFrame* frameNum = mFrames.FirstChild(); if (frameNum) frameDen = frameNum->GetNextSibling(); if (!frameNum || !frameDen || frameDen->GetNextSibling()) { // report an error, encourage people to get their markups in order NS_WARNING("invalid markup"); return ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum); GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen); ////////////////// // Get shifts nsPresContext* presContext = PresContext(); nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull); nsCOMPtr<nsIFontMetrics> fm; aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord defaultRuleThickness, axisHeight; GetRuleThickness(aRenderingContext, fm, defaultRuleThickness); GetAxisHeight(aRenderingContext, fm, axisHeight); // by default, leave at least one-pixel padding at either end, or use // lspace & rspace that may come from <mo> if we are an embellished container // (we fetch values from the core since they may use units that depend // on style data, and style changes could have occurred in the core since // our last visit there) nsEmbellishData coreData; GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData); nscoord leftSpace = PR_MAX(onePixel, coreData.leftSpace); nscoord rightSpace = PR_MAX(onePixel, coreData.rightSpace); // see if the linethickness attribute is there nsAutoString value; GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::linethickness_, value); mLineRect.height = CalcLineThickness(presContext, mStyleContext, value, onePixel, defaultRuleThickness); nscoord numShift = 0; nscoord denShift = 0; // Rule 15b, App. G, TeXbook nscoord numShift1, numShift2, numShift3; nscoord denShift1, denShift2; GetNumeratorShifts(fm, numShift1, numShift2, numShift3); GetDenominatorShifts(fm, denShift1, denShift2); if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { // C > T numShift = numShift1; denShift = denShift1; } else { numShift = (0 < mLineRect.height) ? numShift2 : numShift3; denShift = denShift2; } nscoord minClearance = 0; nscoord actualClearance = 0; nscoord actualRuleThickness = mLineRect.height; if (0 == actualRuleThickness) { // Rule 15c, App. G, TeXbook // min clearance between numerator and denominator minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? 7 * defaultRuleThickness : 3 * defaultRuleThickness; actualClearance = (numShift - bmNum.descent) - (bmDen.ascent - denShift); // actualClearance should be >= minClearance if (actualClearance < minClearance) { nscoord halfGap = (minClearance - actualClearance)/2; numShift += halfGap; denShift += halfGap; } } else { // Rule 15d, App. G, TeXbook // min clearance between numerator or denominator and middle of bar // TeX has a different interpretation of the thickness. // Try $a \above10pt b$ to see. Here is what TeX does: // minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? // 3 * actualRuleThickness : actualRuleThickness; // we slightly depart from TeX here. We use the defaultRuleThickness instead // of the value coming from the linethickness attribute, i.e., we recover what // TeX does if the user hasn't set linethickness. But when the linethickness // is set, we avoid the wide gap problem. minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? 3 * defaultRuleThickness : defaultRuleThickness + onePixel; // adjust numShift to maintain minClearance if needed actualClearance = (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2); if (actualClearance < minClearance) { numShift += (minClearance - actualClearance); } // adjust denShift to maintain minClearance if needed actualClearance = (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift); if (actualClearance < minClearance) { denShift += (minClearance - actualClearance); } } ////////////////// // Place Children // XXX Need revisiting the width. TeX uses the exact width // e.g. in $$\huge\frac{\displaystyle\int}{i}$$ nscoord width = PR_MAX(bmNum.width, bmDen.width); nscoord dxNum = leftSpace + (width - sizeNum.width)/2; nscoord dxDen = leftSpace + (width - sizeDen.width)/2; width += leftSpace + rightSpace; // see if the numalign attribute is there GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::numalign_, value); if (value.EqualsLiteral("left")) dxNum = leftSpace; else if (value.EqualsLiteral("right")) dxNum = width - rightSpace - sizeNum.width; // see if the denomalign attribute is there GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::denomalign_, value); if (value.EqualsLiteral("left")) dxDen = leftSpace; else if (value.EqualsLiteral("right")) dxDen = width - rightSpace - sizeDen.width; mBoundingMetrics.rightBearing = PR_MAX(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing); if (mBoundingMetrics.rightBearing < width - rightSpace) mBoundingMetrics.rightBearing = width - rightSpace; mBoundingMetrics.leftBearing = PR_MIN(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing); if (mBoundingMetrics.leftBearing > leftSpace) mBoundingMetrics.leftBearing = leftSpace; mBoundingMetrics.ascent = bmNum.ascent + numShift; mBoundingMetrics.descent = bmDen.descent + denShift; mBoundingMetrics.width = width; aDesiredSize.ascent = sizeNum.ascent + numShift; aDesiredSize.height = aDesiredSize.ascent + sizeDen.height - sizeDen.ascent + denShift; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dy; // place numerator dy = 0; FinishReflowChild(frameNum, presContext, nsnull, sizeNum, dxNum, dy, 0); // place denominator dy = aDesiredSize.height - sizeDen.height; FinishReflowChild(frameDen, presContext, nsnull, sizeDen, dxDen, dy, 0); // place the fraction bar - dy is top of bar dy = aDesiredSize.ascent - (axisHeight + actualRuleThickness/2); mLineRect.SetRect(leftSpace, dy, width - (leftSpace + rightSpace), actualRuleThickness); } return NS_OK; }
NS_IMETHODIMP nsMathMLmunderoverFrame::TransmitAutomaticData() { // At this stage, all our children are in sync and we can fully // resolve our own mEmbellishData struct //--------------------------------------------------------------------- /* The REC says: The accent and accentunder attributes have the same effect as the attributes with the same names on <mover> and <munder>, respectively. Their default values are also computed in the same manner as described for those elements, with the default value of accent depending on overscript and the default value of accentunder depending on underscript. */ nsIFrame* overscriptFrame = nsnull; nsIFrame* underscriptFrame = nsnull; nsIFrame* baseFrame = mFrames.FirstChild(); if (baseFrame) underscriptFrame = baseFrame->GetNextSibling(); if (underscriptFrame) overscriptFrame = underscriptFrame->GetNextSibling(); // if our base is an embellished operator, let its state bubble to us (in particular, // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags // are reset to the default values of false if the base frame isn't embellished. mPresentationData.baseFrame = baseFrame; GetEmbellishDataFrom(baseFrame, mEmbellishData); nsAutoString value; // The default value of accentunder is false, unless the underscript is embellished // and its core <mo> is an accent nsEmbellishData embellishData; GetEmbellishDataFrom(underscriptFrame, embellishData); if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER; else mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER; // if we have an accentunder attribute, it overrides what the underscript said if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_None, nsMathMLAtoms::accentunder_, value)) { if (value.EqualsLiteral("true")) mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER; else if (value.EqualsLiteral("false")) mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER; } // The default value of accent is false, unless the overscript is embellished // and its core <mo> is an accent GetEmbellishDataFrom(overscriptFrame, embellishData); if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; else mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; // if we have an accent attribute, it overrides what the overscript said if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_None, nsMathMLAtoms::accent_, value)) { if (value.EqualsLiteral("true")) mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; else if (value.EqualsLiteral("false")) mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; } // disable the stretch-all flag if we are going to act like a superscript if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; // Now transmit any change that we want to our children so that they // can update their mPresentationData structs //--------------------------------------------------------------------- /* The REC says: Within underscript, <munderover> always sets displaystyle to "false", but increments scriptlevel by 1 only when accentunder is "false". Within overscript, <munderover> always sets displaystyle to "false", but increments scriptlevel by 1 only when accent is "false". The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a say it shouldn't be compressed. However, The TeXBook says that math accents and \overline change uncramped styles to their cramped counterparts. */ PRInt32 increment = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ? 0 : 1; PRUint32 compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ? NS_MATHML_COMPRESSED : 0; PropagatePresentationDataFor(overscriptFrame, increment, ~NS_MATHML_DISPLAYSTYLE | compress, NS_MATHML_DISPLAYSTYLE | compress); /* The TeXBook treats 'under' like a subscript, so p.141 or Rule 13a say it should be compressed */ increment = NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags) ? 0 : 1; PropagatePresentationDataFor(underscriptFrame, increment, ~NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED, NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED); return NS_OK; }
NS_IMETHODIMP nsMathMLmunderoverFrame::Place(nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { // place like sub-superscript pair return nsMathMLmsubsupFrame::PlaceSubSupScript(GetPresContext(), aRenderingContext, aPlaceOrigin, aDesiredSize, this); } //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmBase, bmUnder, bmOver; nsHTMLReflowMetrics baseSize (nsnull); nsHTMLReflowMetrics underSize (nsnull); nsHTMLReflowMetrics overSize (nsnull); nsIFrame* overFrame = nsnull; nsIFrame* underFrame = nsnull; nsIFrame* baseFrame = mFrames.FirstChild(); if (baseFrame) underFrame = baseFrame->GetNextSibling(); if (underFrame) overFrame = underFrame->GetNextSibling(); if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order NS_WARNING("invalid markup"); return ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder); GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver); nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1); //////////////////// // Place Children aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull); nsCOMPtr<nsIFontMetrics> fm; aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord xHeight = 0; fm->GetXHeight (xHeight); nscoord ruleThickness; GetRuleThickness (aRenderingContext, fm, ruleThickness); nscoord correction = 0; GetItalicCorrection (bmBase, correction); // there are 2 different types of placement depending on // whether we want an accented under or not nscoord underDelta1 = 0; // gap between base and underscript nscoord underDelta2 = 0; // extra space beneath underscript if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { // Rule 13a, App. G, TeXbook nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; GetBigOpSpacings (fm, dummy, bigOpSpacing2, dummy, bigOpSpacing4, bigOpSpacing5); underDelta1 = PR_MAX(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent)); underDelta2 = bigOpSpacing5; } else { // No corresponding rule in TeXbook - we are on our own here // XXX tune the gap delta between base and underscript // Should we use Rule 10 like \underline does? underDelta1 = ruleThickness + onePixel/2; underDelta2 = ruleThickness; } // empty under? if (!(bmUnder.ascent + bmUnder.descent)) underDelta1 = 0; nscoord overDelta1 = 0; // gap between base and overscript nscoord overDelta2 = 0; // extra space above overscript if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { // Rule 13a, App. G, TeXbook nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; GetBigOpSpacings (fm, bigOpSpacing1, dummy, bigOpSpacing3, dummy, bigOpSpacing5); overDelta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent)); overDelta2 = bigOpSpacing5; // XXX This is not a TeX rule... // delta1 (as computed abvove) can become really big when bmOver.descent is // negative, e.g., if the content is &OverBar. In such case, we use the height if (bmOver.descent < 0) overDelta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent))); } else { // Rule 12, App. G, TeXbook overDelta1 = ruleThickness + onePixel/2; if (bmBase.ascent < xHeight) { overDelta1 += xHeight - bmBase.ascent; } overDelta2 = ruleThickness; } // empty over? if (!(bmOver.ascent + bmOver.descent)) overDelta1 = 0; nscoord dxBase, dxOver = 0, dxUnder = 0; ////////// // pass 1, do what <mover> does: attach the overscript on the base // Ad-hoc - This is to override fonts which have ready-made _accent_ // glyphs with negative lbearing and rbearing. We want to position // the overscript ourselves nscoord overWidth = bmOver.width; if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) { overWidth = bmOver.rightBearing - bmOver.leftBearing; dxOver = -bmOver.leftBearing; } if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { mBoundingMetrics.width = bmBase.width; dxOver += correction + (mBoundingMetrics.width - overWidth)/2; } else { mBoundingMetrics.width = PR_MAX(bmBase.width, overWidth); dxOver += correction/2 + (mBoundingMetrics.width - overWidth)/2; } dxBase = (mBoundingMetrics.width - bmBase.width)/2; mBoundingMetrics.ascent = bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent; mBoundingMetrics.descent = bmBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent; mBoundingMetrics.leftBearing = PR_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing); mBoundingMetrics.rightBearing = PR_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing); ////////// // pass 2, do what <munder> does: attach the underscript on the previous // result. We conceptually view the previous result as an "anynomous base" // from where to attach the underscript. Hence if the underscript is empty, // we should end up like <mover>. If the overscript is empty, we should // end up like <munder>. nsBoundingMetrics bmAnonymousBase = mBoundingMetrics; nscoord ascentAnonymousBase = PR_MAX(mBoundingMetrics.ascent + overDelta2, overSize.ascent + bmOver.descent + overDelta1 + bmBase.ascent); GetItalicCorrection(bmAnonymousBase, correction); nscoord maxWidth = PR_MAX(bmAnonymousBase.width, bmUnder.width); if (NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { dxUnder = (maxWidth - bmUnder.width)/2;; } else { dxUnder = -correction/2 + (maxWidth - bmUnder.width)/2; } nscoord dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2; // adjust the offsets of the real base and overscript since their // final offsets should be relative to us... dxOver += dxAnonymousBase; dxBase += dxAnonymousBase; mBoundingMetrics.width = PR_MAX(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width); mBoundingMetrics.leftBearing = PR_MIN(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing); mBoundingMetrics.rightBearing = PR_MAX(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing); aDesiredSize.ascent = ascentAnonymousBase; aDesiredSize.descent = PR_MAX(mBoundingMetrics.descent + underDelta2, bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + underSize.descent); aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dy; // place overscript dy = aDesiredSize.ascent - mBoundingMetrics.ascent + bmOver.ascent - overSize.ascent; FinishReflowChild (overFrame, GetPresContext(), nsnull, overSize, dxOver, dy, 0); // place base dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, GetPresContext(), nsnull, baseSize, dxBase, dy, 0); // place underscript dy = aDesiredSize.ascent + mBoundingMetrics.descent - bmUnder.descent - underSize.ascent; FinishReflowChild (underFrame, GetPresContext(), nsnull, underSize, dxUnder, dy, 0); } return NS_OK; }
/* virtual */ nsresult nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { //////////////////////////////////// // Get the children's desired sizes nscoord minShiftFromXHeight, subDrop, supDrop; //////////////////////////////////////// // Initialize super/sub shifts that // depend only on the current font //////////////////////////////////////// ProcessAttributes(); // get x-height (an ex) const nsStyleFont* font = GetStyleFont(); nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); nscoord xHeight = fm->XHeight(); nscoord ruleSize; GetRuleThickness (aRenderingContext, fm, ruleSize); // scriptspace from TeX for extra spacing after sup/subscript (0.5pt in plain TeX) // forced to be at least 1 pixel here nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); nscoord scriptSpace = NS_MAX(nsPresContext::CSSPointsToAppUnits(0.5f), onePixel); ///////////////////////////////////// // first the shift for the subscript // subScriptShift{1,2} // = minimum amount to shift the subscript down // = sub{1,2} in TeXbook // subScriptShift1 = subscriptshift attribute * x-height nscoord subScriptShift1, subScriptShift2; // Get subScriptShift{1,2} default from font GetSubScriptShifts (fm, subScriptShift1, subScriptShift2); if (0 < mSubScriptShift) { // the user has set the subscriptshift attribute float scaler = ((float) subScriptShift2) / subScriptShift1; subScriptShift1 = NS_MAX(subScriptShift1, mSubScriptShift); subScriptShift2 = NSToCoordRound(scaler * subScriptShift1); } // the font dependent shift nscoord subScriptShift = NS_MAX(subScriptShift1,subScriptShift2); ///////////////////////////////////// // next the shift for the superscript // supScriptShift{1,2,3} // = minimum amount to shift the supscript up // = sup{1,2,3} in TeX // supScriptShift1 = superscriptshift attribute * x-height // Note that there are THREE values for supscript shifts depending // on the current style nscoord supScriptShift1, supScriptShift2, supScriptShift3; // Set supScriptShift{1,2,3} default from font GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); if (0 < mSupScriptShift) { // the user has set the superscriptshift attribute float scaler2 = ((float) supScriptShift2) / supScriptShift1; float scaler3 = ((float) supScriptShift3) / supScriptShift1; supScriptShift1 = NS_MAX(supScriptShift1, mSupScriptShift); supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1); supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1); } // get sup script shift depending on current script level and display style // Rule 18c, App. G, TeXbook nscoord supScriptShift; if ( font->mScriptLevel == 0 && NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags) && !NS_MATHML_IS_COMPRESSED(mPresentationData.flags)) { // Style D in TeXbook supScriptShift = supScriptShift1; } else if (NS_MATHML_IS_COMPRESSED(mPresentationData.flags)) { // Style C' in TeXbook = D',T',S',SS' supScriptShift = supScriptShift3; } else { // everything else = T,S,SS supScriptShift = supScriptShift2; } //////////////////////////////////// // Get the children's sizes //////////////////////////////////// nscoord width = 0, prescriptsWidth = 0, rightBearing = 0; nsIFrame* mprescriptsFrame = nsnull; // frame of <mprescripts/>, if there. bool isSubScript = false; nscoord minSubScriptShift = 0, minSupScriptShift = 0; nscoord trySubScriptShift = subScriptShift; nscoord trySupScriptShift = supScriptShift; nscoord maxSubScriptShift = subScriptShift; nscoord maxSupScriptShift = supScriptShift; PRInt32 count = 0; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics subScriptSize; nsHTMLReflowMetrics supScriptSize; nsIFrame* baseFrame = nsnull; nsIFrame* subScriptFrame = nsnull; nsIFrame* supScriptFrame = nsnull; bool firstPrescriptsPair = false; nsBoundingMetrics bmBase, bmSubScript, bmSupScript; nscoord italicCorrection = 0; mBoundingMetrics.width = 0; mBoundingMetrics.ascent = mBoundingMetrics.descent = -0x7FFFFFFF; nscoord ascent = -0x7FFFFFFF, descent = -0x7FFFFFFF; aDesiredSize.width = aDesiredSize.height = 0; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) { if (mprescriptsFrame) { // duplicate <mprescripts/> found // report an error, encourage people to get their markups in order return ReflowError(aRenderingContext, aDesiredSize); } mprescriptsFrame = childFrame; firstPrescriptsPair = true; } else { if (0 == count) { // base baseFrame = childFrame; GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetItalicCorrection(bmBase, italicCorrection); // for the superscript, we always add "a little to spare" italicCorrection += onePixel; // we update mBoundingMetrics.{ascent,descent} with that // of the baseFrame only after processing all the sup/sub pairs // XXX need italic correction only *if* there are postscripts ? mBoundingMetrics.width = bmBase.width + italicCorrection; mBoundingMetrics.rightBearing = bmBase.rightBearing; mBoundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten } else { // super/subscript block if (isSubScript) { // subscript subScriptFrame = childFrame; GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); // get the subdrop from the subscript font GetSubDropFromChild (subScriptFrame, subDrop); // parameter v, Rule 18a, App. G, TeXbook minSubScriptShift = bmBase.descent + subDrop; trySubScriptShift = NS_MAX(minSubScriptShift,subScriptShift); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,bmSubScript.descent); descent = NS_MAX(descent,subScriptSize.height - subScriptSize.ascent); width = bmSubScript.width + scriptSpace; rightBearing = bmSubScript.rightBearing; } else { // supscript supScriptFrame = childFrame; GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); // get the supdrop from the supscript font GetSupDropFromChild (supScriptFrame, supDrop); // parameter u, Rule 18a, App. G, TeXbook minSupScriptShift = bmBase.ascent - supDrop; // get min supscript shift limit from x-height // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook minShiftFromXHeight = NSToCoordRound ((bmSupScript.descent + (1.0f/4.0f) * xHeight)); trySupScriptShift = NS_MAX(minSupScriptShift,NS_MAX(minShiftFromXHeight,supScriptShift)); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,bmSupScript.ascent); ascent = NS_MAX(ascent,supScriptSize.ascent); width = NS_MAX(width, bmSupScript.width + scriptSpace); rightBearing = NS_MAX(rightBearing, bmSupScript.rightBearing); if (!mprescriptsFrame) { // we are still looping over base & postscripts mBoundingMetrics.rightBearing = mBoundingMetrics.width + rightBearing; mBoundingMetrics.width += width; } else { prescriptsWidth += width; if (firstPrescriptsPair) { firstPrescriptsPair = false; mBoundingMetrics.leftBearing = NS_MIN(bmSubScript.leftBearing, bmSupScript.leftBearing); } } width = rightBearing = 0; // negotiate between the various shifts so that // there is enough gap between the sup and subscripts // Rule 18e, App. G, TeXbook nscoord gap = (trySupScriptShift - bmSupScript.descent) - (bmSubScript.ascent - trySubScriptShift); if (gap < 4.0f * ruleSize) { // adjust trySubScriptShift to get a gap of (4.0 * ruleSize) trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap); } // next we want to ensure that the bottom of the superscript // will be > (4/5) * x-height above baseline gap = NSToCoordRound ((4.0f/5.0f) * xHeight - (trySupScriptShift - bmSupScript.descent)); if (gap > 0.0f) { trySupScriptShift += gap; trySubScriptShift -= gap; } maxSubScriptShift = NS_MAX(maxSubScriptShift, trySubScriptShift); maxSupScriptShift = NS_MAX(maxSupScriptShift, trySupScriptShift); trySubScriptShift = subScriptShift; trySupScriptShift = supScriptShift; } } isSubScript = !isSubScript; } count++; childFrame = childFrame->GetNextSibling(); } // note: width=0 if all sup-sub pairs match correctly if ((0 != width) || !baseFrame || !subScriptFrame || !supScriptFrame) { // report an error, encourage people to get their markups in order return ReflowError(aRenderingContext, aDesiredSize); } // we left out the width of prescripts, so ... mBoundingMetrics.rightBearing += prescriptsWidth; mBoundingMetrics.width += prescriptsWidth; // we left out the base during our bounding box updates, so ... mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent+maxSupScriptShift,bmBase.ascent); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent+maxSubScriptShift,bmBase.descent); // get the reflow metrics ... aDesiredSize.ascent = NS_MAX(ascent+maxSupScriptShift,baseSize.ascent); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(descent+maxSubScriptShift,baseSize.height - baseSize.ascent); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; ////////////////// // Place Children // Place prescripts, followed by base, and then postscripts. // The list of frames is in the order: {base} {postscripts} {prescripts} // We go over the list in a circular manner, starting at <prescripts/> if (aPlaceOrigin) { nscoord dx = 0, dy = 0; count = 0; childFrame = mprescriptsFrame; do { if (!childFrame) { // end of prescripts, // place the base ... childFrame = baseFrame; dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, PresContext(), nsnull, baseSize, MirrorIfRTL(aDesiredSize.width, baseSize.width, dx), dy, 0); dx += bmBase.width + italicCorrection; } else if (mprescriptsFrame != childFrame) { // process each sup/sub pair if (0 == count) { subScriptFrame = childFrame; count = 1; } else if (1 == count) { supScriptFrame = childFrame; count = 0; // get the ascent/descent of sup/subscripts stored in their rects // rect.x = descent, rect.y = ascent GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); // center w.r.t. largest width width = NS_MAX(subScriptSize.width, supScriptSize.width); dy = aDesiredSize.ascent - subScriptSize.ascent + maxSubScriptShift; FinishReflowChild (subScriptFrame, PresContext(), nsnull, subScriptSize, MirrorIfRTL(aDesiredSize.width, subScriptSize.width, dx + (width-subScriptSize.width)/2), dy, 0); dy = aDesiredSize.ascent - supScriptSize.ascent - maxSupScriptShift; FinishReflowChild (supScriptFrame, PresContext(), nsnull, supScriptSize, MirrorIfRTL(aDesiredSize.width, supScriptSize.width, dx + (width-supScriptSize.width)/2), dy, 0); dx += width + scriptSpace; } } childFrame = childFrame->GetNextSibling(); } while (mprescriptsFrame != childFrame); } return NS_OK; }
NS_IMETHODIMP nsMathMLmsqrtFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { /////////////// // Let the base class format our content like an inferred mrow nsHTMLReflowMetrics baseSize(aDesiredSize); nsresult rv = nsMathMLContainerFrame::Reflow(aPresContext, baseSize, aReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); if (NS_FAILED(rv)) return rv; nsBoundingMetrics bmSqr, bmBase; bmBase = baseSize.mBoundingMetrics; //////////// // Prepare the radical symbol and the overline bar nsIRenderingContext& renderingContext = *aReflowState.rendContext; renderingContext.SetFont(GetStyleFont()->mFont, nsnull); nsCOMPtr<nsIFontMetrics> fm; renderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord ruleThickness, leading, em; GetRuleThickness(renderingContext, fm, ruleThickness); nsBoundingMetrics bmOne; renderingContext.GetBoundingMetrics(NS_LITERAL_STRING("1").get(), 1, bmOne); // get the leading to be left at the top of the resulting frame // this seems more reliable than using fm->GetLeading() on suspicious fonts GetEmHeight(fm, em); leading = nscoord(0.2f * em); // Rule 11, App. G, TeXbook // psi = clearance between rule and content nscoord phi = 0, psi = 0; if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) fm->GetXHeight(phi); else phi = ruleThickness; psi = ruleThickness + phi/4; // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131) if (bmOne.ascent > bmBase.ascent) psi += bmOne.ascent - bmBase.ascent; // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = ruleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, renderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // According to TeX, the ascent of the returned radical should be // the thickness of the overline ruleThickness = bmSqr.ascent; // make sure that the rule appears on the screen nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1); if (ruleThickness < onePixel) { ruleThickness = onePixel; } // adjust clearance psi to get an exact number of pixels -- this // gives a nicer & uniform look on stacked radicals (bug 130282) nscoord delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up nscoord dx = 0, dy = 0; // place the radical symbol and the radical bar dy = leading; // leave a leading at the top mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx = bmSqr.width; mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness); // Update the desired size for the container. // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = PR_MAX(bmBase.descent, (bmSqr.descent - (bmBase.ascent + psi))); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + PR_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.descent = PR_MAX(baseSize.descent, (mBoundingMetrics.descent + ruleThickness)); aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; ////////////////// // Adjust the origins to leave room for the sqrt char and the overline bar dx = radicalSize.width; dy = aDesiredSize.ascent - baseSize.ascent; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { childFrame->SetPosition(childFrame->GetPosition() + nsPoint(dx, dy)); childFrame = childFrame->GetNextSibling(); } if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = aDesiredSize.width; } aDesiredSize.mBoundingMetrics = mBoundingMetrics; aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
/* virtual */ nsresult nsMathMLmunderFrame::Place(nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { // place like subscript return nsMathMLmsubFrame::PlaceSubScript(PresContext(), aRenderingContext, aPlaceOrigin, aDesiredSize, this, 0, nsPresContext::CSSPointsToAppUnits(0.5f)); } //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmBase, bmUnder; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics underSize; nsIFrame* underFrame = nsnull; nsIFrame* baseFrame = mFrames.FirstChild(); if (baseFrame) underFrame = baseFrame->GetNextSibling(); if (!baseFrame || !underFrame || underFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order return ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder); nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); //////////////////// // Place Children aRenderingContext.SetFont(GetStyleFont()->mFont, PresContext()->GetUserFontSet()); nsCOMPtr<nsIFontMetrics> fm; aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord xHeight = 0; fm->GetXHeight (xHeight); nscoord ruleThickness; GetRuleThickness (aRenderingContext, fm, ruleThickness); // there are 2 different types of placement depending on // whether we want an accented under or not nscoord correction = 0; GetItalicCorrection (bmBase, correction); nscoord delta1 = 0; // gap between base and underscript nscoord delta2 = 0; // extra space beneath underscript if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { // Rule 13a, App. G, TeXbook nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; GetBigOpSpacings (fm, dummy, bigOpSpacing2, dummy, bigOpSpacing4, bigOpSpacing5); delta1 = NS_MAX(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent)); delta2 = bigOpSpacing5; } else { // No corresponding rule in TeXbook - we are on our own here // XXX tune the gap delta between base and underscript // Should we use Rule 10 like \underline does? delta1 = ruleThickness + onePixel/2; delta2 = ruleThickness; } // empty under? if (!(bmUnder.ascent + bmUnder.descent)) delta1 = 0; nscoord dxBase, dxUnder = 0; // Width of non-spacing marks is zero so use left and right bearing. nscoord underWidth = bmUnder.width; if (!underWidth) { underWidth = bmUnder.rightBearing - bmUnder.leftBearing; dxUnder = -bmUnder.leftBearing; } nscoord maxWidth = NS_MAX(bmBase.width, underWidth); if (NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { dxUnder += (maxWidth - underWidth)/2; } else { dxUnder += -correction/2 + (maxWidth - underWidth)/2; } dxBase = (maxWidth - bmBase.width)/2; mBoundingMetrics.width = NS_MAX(dxBase + bmBase.width, dxUnder + bmUnder.width); mBoundingMetrics.ascent = bmBase.ascent; mBoundingMetrics.descent = bmBase.descent + delta1 + bmUnder.ascent + bmUnder.descent; mBoundingMetrics.leftBearing = NS_MIN(dxBase + bmBase.leftBearing, dxUnder + bmUnder.leftBearing); mBoundingMetrics.rightBearing = NS_MAX(dxBase + bmBase.rightBearing, dxUnder + bmUnder.rightBearing); aDesiredSize.ascent = baseSize.ascent; aDesiredSize.height = aDesiredSize.ascent + NS_MAX(mBoundingMetrics.descent + delta2, bmBase.descent + delta1 + bmUnder.ascent + underSize.height - underSize.ascent); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dy = 0; // place base FinishReflowChild(baseFrame, PresContext(), nsnull, baseSize, dxBase, dy, 0); // place underscript dy = aDesiredSize.ascent + mBoundingMetrics.descent - bmUnder.descent - underSize.ascent; FinishReflowChild(underFrame, PresContext(), nsnull, underSize, dxUnder, dy, 0); } return NS_OK; }