/* static */ void nsMathMLFrame::GetAxisHeight(nsIRenderingContext& aRenderingContext, nsIFontMetrics* aFontMetrics, nscoord& aAxisHeight) { // get the bounding metrics of the minus sign, the rendering context // is assumed to have been set with the font of the current style context #ifdef NS_DEBUG nsCOMPtr<nsIFontMetrics> currFontMetrics; aRenderingContext.GetFontMetrics(*getter_AddRefs(currFontMetrics)); NS_ASSERTION(currFontMetrics->Font().Equals(aFontMetrics->Font()), "unexpected state"); #endif nscoord xHeight; aFontMetrics->GetXHeight(xHeight); PRUnichar minus = 0x2212; // not '-', but official Unicode minus sign nsBoundingMetrics bm; nsresult rv = aRenderingContext.GetBoundingMetrics(&minus, PRUint32(1), bm); if (NS_SUCCEEDED(rv)) { aAxisHeight = bm.ascent - (bm.ascent + bm.descent)/2; } if (NS_FAILED(rv) || aAxisHeight <= 0 || aAxisHeight >= xHeight) { // fall-back to the other version GetAxisHeight(aFontMetrics, aAxisHeight); } }
/* static */ void nsMathMLFrame::GetRuleThickness(nsIRenderingContext& aRenderingContext, nsIFontMetrics* aFontMetrics, nscoord& aRuleThickness) { // get the bounding metrics of the overbar char, the rendering context // is assumed to have been set with the font of the current style context #ifdef NS_DEBUG nsCOMPtr<nsIFontMetrics> currFontMetrics; aRenderingContext.GetFontMetrics(*getter_AddRefs(currFontMetrics)); NS_ASSERTION(currFontMetrics->Font().Equals(aFontMetrics->Font()), "unexpected state"); #endif nscoord xHeight; aFontMetrics->GetXHeight(xHeight); PRUnichar overBar = 0x00AF; nsBoundingMetrics bm; nsresult rv = aRenderingContext.GetBoundingMetrics(&overBar, PRUint32(1), bm); if (NS_SUCCEEDED(rv)) { aRuleThickness = bm.ascent + bm.descent; } if (NS_FAILED(rv) || aRuleThickness <= 0 || aRuleThickness >= xHeight) { // fall-back to the other version GetRuleThickness(aFontMetrics, aRuleThickness); } #if 0 nscoord oldRuleThickness; GetRuleThickness(aFontMetrics, oldRuleThickness); PRUnichar sqrt = 0xE063; // a sqrt glyph from TeX's CMEX font rv = aRenderingContext.GetBoundingMetrics(&sqrt, PRUint32(1), bm); nscoord sqrtrule = bm.ascent; // according to TeX, the ascent should be the rule printf("xheight:%4d rule:%4d oldrule:%4d sqrtrule:%4d\n", xHeight, aRuleThickness, oldRuleThickness, sqrtrule); #endif }
/* virtual */ nsresult nsMathMLmencloseFrame::PlaceInternal(nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, PRBool aWidthOnly) { /////////////// // Measure the size of our content using the base class to format like an // inferred mrow. nsHTMLReflowMetrics baseSize; nsresult rv = nsMathMLContainerFrame::Place(aRenderingContext, PR_FALSE, baseSize); if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { DidReflowChildren(GetFirstChild(nsnull)); 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); nsCOMPtr<nsIFontMetrics> fm; nscoord mEmHeight; aRenderingContext.SetFont(GetStyleFont()->mFont, PresContext()->GetUserFontSet()); aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); GetRuleThickness(aRenderingContext, fm, mRuleThickness); GetEmHeight(fm, mEmHeight); nsBoundingMetrics bmOne; aRenderingContext.GetBoundingMetrics(NS_LITERAL_STRING("1").get(), 1, bmOne); /////////////// // 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)) fm->GetXHeight(phi); 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); 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)) { if (aWidthOnly) { nscoord radical_width = mMathMLChar[mRadicalCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters dx_left = NS_MAX(dx_left, 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); mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar); // Update horizontal parameters dx_left = NS_MAX(dx_left, 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)) mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx_left - bmRadicalChar.width, aDesiredSize.ascent - radicalAscent, bmRadicalChar.width, bmRadicalChar.ascent + bmRadicalChar.descent)); mContentWidth = bmBase.width; ////////////////// // Finish reflowing child frames PositionRowChildFrames(dx_left, aDesiredSize.ascent); } return NS_OK; }