From e13641fddfc045654539619f20f74ba61689bca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Fri, 29 May 2009 13:08:35 +0200 Subject: [PATCH] b=297467 menclose r=karlt rs=roc --- layout/base/nsCSSFrameConstructor.cpp | 3 +- layout/mathml/Makefile.in | 1 + layout/mathml/nsMathMLContainerFrame.cpp | 6 +- layout/mathml/nsMathMLContainerFrame.h | 12 +- layout/mathml/nsMathMLParts.h | 1 + layout/mathml/nsMathMLmencloseFrame.cpp | 826 +++++++++++++++++++++++ layout/mathml/nsMathMLmencloseFrame.h | 158 +++++ layout/mathml/nsMathMLmsqrtFrame.cpp | 269 +------- layout/mathml/nsMathMLmsqrtFrame.h | 55 +- 9 files changed, 1014 insertions(+), 317 deletions(-) create mode 100644 layout/mathml/nsMathMLmencloseFrame.cpp create mode 100644 layout/mathml/nsMathMLmencloseFrame.h diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 5dd632518fb4..696ee4fc71b4 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -4822,7 +4822,8 @@ nsCSSFrameConstructor::FindMathMLData(nsIContent* aContent, SIMPLE_MATHML_CREATE(mroot_, NS_NewMathMLmrootFrame), SIMPLE_MATHML_CREATE(maction_, NS_NewMathMLmactionFrame), SIMPLE_MATHML_CREATE(mrow_, NS_NewMathMLmrowFrame), - SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame) + SIMPLE_MATHML_CREATE(merror_, NS_NewMathMLmrowFrame), + SIMPLE_MATHML_CREATE(menclose_, NS_NewMathMLmencloseFrame) }; return FindDataByTag(aTag, aContent, aStyleContext, sMathMLData, diff --git a/layout/mathml/Makefile.in b/layout/mathml/Makefile.in index 18a7855faeb9..97d624914344 100644 --- a/layout/mathml/Makefile.in +++ b/layout/mathml/Makefile.in @@ -103,6 +103,7 @@ CPPSRCS = nsMathMLChar.cpp \ nsMathMLmsqrtFrame.cpp \ nsMathMLmrootFrame.cpp \ nsMathMLmactionFrame.cpp \ + nsMathMLmencloseFrame.cpp \ $(NULL) include $(topsrcdir)/config/config.mk diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp index 28f023255b73..7c98d14511dd 100644 --- a/layout/mathml/nsMathMLContainerFrame.cpp +++ b/layout/mathml/nsMathMLContainerFrame.cpp @@ -1063,7 +1063,7 @@ nsMathMLContainerFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext // Measure nsHTMLReflowMetrics desiredSize; - nsresult rv = MeasureChildFrames(*aRenderingContext, desiredSize); + nsresult rv = MeasureForWidth(*aRenderingContext, desiredSize); if (NS_FAILED(rv)) { ReflowError(*aRenderingContext, desiredSize); } @@ -1074,8 +1074,8 @@ nsMathMLContainerFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext } /* virtual */ nsresult -nsMathMLContainerFrame::MeasureChildFrames(nsIRenderingContext& aRenderingContext, - nsHTMLReflowMetrics& aDesiredSize) +nsMathMLContainerFrame::MeasureForWidth(nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize) { return Place(aRenderingContext, PR_FALSE, aDesiredSize); } diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h index 2257798a2e71..7ef531ba9300 100644 --- a/layout/mathml/nsMathMLContainerFrame.h +++ b/layout/mathml/nsMathMLContainerFrame.h @@ -229,17 +229,17 @@ protected: PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize); - // MeasureChildFrames: + // MeasureForWidth: // // A method used by nsMathMLContainerFrame::GetIntrinsicWidth to get the // width that a particular Place method desires. For most frames, this will - // just call the object's Place method. However uses + // just call the object's Place method. However and use // nsMathMLContainerFrame::GetIntrinsicWidth to measure the child frames as - // if in an , and so frames implement MeasureChildFrames to - // use nsMathMLContainerFrame::Place. + // if in an , and so their frames implement MeasureForWidth to use + // nsMathMLContainerFrame::Place. virtual nsresult - MeasureChildFrames(nsIRenderingContext& aRenderingContext, - nsHTMLReflowMetrics& aDesiredSize); + MeasureForWidth(nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize); // helper to re-sync the automatic data in our children and notify our parent to diff --git a/layout/mathml/nsMathMLParts.h b/layout/mathml/nsMathMLParts.h index 82f73452e9e8..edd67b9a70ce 100644 --- a/layout/mathml/nsMathMLParts.h +++ b/layout/mathml/nsMathMLParts.h @@ -69,6 +69,7 @@ nsIFrame* NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aC nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmactionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); +nsIFrame* NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags); nsIFrame* NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); diff --git a/layout/mathml/nsMathMLmencloseFrame.cpp b/layout/mathml/nsMathMLmencloseFrame.cpp new file mode 100644 index 000000000000..fb350f7708ef --- /dev/null +++ b/layout/mathml/nsMathMLmencloseFrame.cpp @@ -0,0 +1,826 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla MathML Project. + * + * The Initial Developer of the Original Code is + * The University Of Queensland. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roger B. Sidje + * David J. Fiddes + * Vilya Harvey + * Shyjan Mahamud + * Karl Tomlinson , Mozilla Corporation + * Frederic Wang - extension of to + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsCOMPtr.h" +#include "nsFrame.h" +#include "nsPresContext.h" +#include "nsStyleContext.h" +#include "nsStyleConsts.h" +#include "nsIRenderingContext.h" +#include "nsIFontMetrics.h" +#include "nsWhitespaceTokenizer.h" + +#include "nsMathMLmencloseFrame.h" +#include "nsDisplayList.h" +#include "gfxContext.h" + +// +// -- enclose content with a stretching symbol such +// as a long division sign. - implementation + +// longdiv: +// Unicode 5.1 assigns U+27CC to LONG DIVISION, but a right parenthesis +// renders better with current font support. +static const PRUnichar kLongDivChar = ')'; + +// radical: 'SQUARE ROOT' +static const PRUnichar kRadicalChar = 0x221A; + +nsIFrame* +NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) nsMathMLmencloseFrame(aContext); +} + +nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext* aContext) : + nsMathMLContainerFrame(aContext), mNotationsToDraw(0), + mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0) +{ +} + +nsMathMLmencloseFrame::~nsMathMLmencloseFrame() +{ +} + +nsresult nsMathMLmencloseFrame::AllocateMathMLChar(nsMencloseNotation mask) +{ + // Is the char already allocated? + if ((mask == NOTATION_LONGDIV && mLongDivCharIndex >= 0) || + (mask == NOTATION_RADICAL && mRadicalCharIndex >= 0)) + return NS_OK; + + // No need to track the style context given to our MathML chars. + // The Style System will use Get/SetAdditionalStyleContext() to keep it + // up-to-date if dynamic changes arise. + PRUint32 i = mMathMLChar.Length(); + nsAutoString Char; + + if (!mMathMLChar.AppendElement()) + return NS_ERROR_OUT_OF_MEMORY; + + if (mask == NOTATION_LONGDIV) { + Char.Assign(kLongDivChar); + mLongDivCharIndex = i; + } else if (mask == NOTATION_RADICAL) { + Char.Assign(kRadicalChar); + mRadicalCharIndex = i; + } + + nsPresContext *presContext = PresContext(); + mMathMLChar[i].SetData(presContext, Char); + ResolveMathMLCharStyle(presContext, mContent, mStyleContext, + &mMathMLChar[i], + PR_TRUE); + + return NS_OK; +} + +/* + * Add a notation to draw, if the argument is the name of a known notation. + * @param aNotation string name of a notation + */ +nsresult nsMathMLmencloseFrame::AddNotation(const nsAString& aNotation) +{ + nsresult rv; + + if (aNotation.EqualsLiteral("longdiv")) { + rv = AllocateMathMLChar(NOTATION_LONGDIV); + NS_ENSURE_SUCCESS(rv, rv); + mNotationsToDraw |= NOTATION_LONGDIV; + } else if (aNotation.EqualsLiteral("actuarial")) { + mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_TOP); + } else if (aNotation.EqualsLiteral("radical")) { + rv = AllocateMathMLChar(NOTATION_RADICAL); + NS_ENSURE_SUCCESS(rv, rv); + mNotationsToDraw |= NOTATION_RADICAL; + } else if (aNotation.EqualsLiteral("box")) { + mNotationsToDraw |= (NOTATION_LEFT | NOTATION_RIGHT | + NOTATION_TOP | NOTATION_BOTTOM); + } else if (aNotation.EqualsLiteral("roundedbox")) { + mNotationsToDraw |= NOTATION_ROUNDEDBOX; + } else if (aNotation.EqualsLiteral("circle")) { + mNotationsToDraw |= NOTATION_CIRCLE; + } else if (aNotation.EqualsLiteral("left")) { + mNotationsToDraw |= NOTATION_LEFT; + } else if (aNotation.EqualsLiteral("right")) { + mNotationsToDraw |= NOTATION_RIGHT; + } else if (aNotation.EqualsLiteral("top")) { + mNotationsToDraw |= NOTATION_TOP; + } else if (aNotation.EqualsLiteral("bottom")) { + mNotationsToDraw |= NOTATION_BOTTOM; + } else if (aNotation.EqualsLiteral("updiagonalstrike")) { + mNotationsToDraw |= NOTATION_UPDIAGONALSTRIKE; + } else if (aNotation.EqualsLiteral("downdiagonalstrike")) { + mNotationsToDraw |= NOTATION_DOWNDIAGONALSTRIKE; + } else if (aNotation.EqualsLiteral("verticalstrike")) { + mNotationsToDraw |= NOTATION_VERTICALSTRIKE; + } else if (aNotation.EqualsLiteral("horizontalstrike")) { + mNotationsToDraw |= NOTATION_HORIZONTALSTRIKE; + } + + return NS_OK; +} + +/* + * Initialize the list of notations to draw + */ +void nsMathMLmencloseFrame::InitNotations() +{ + nsAutoString value; + + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::notation_, value)) { + // parse the notation attribute + nsWhitespaceTokenizer tokenizer(value); + + while (tokenizer.hasMoreTokens()) + AddNotation(tokenizer.nextToken()); + } else { + // default: longdiv + if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV))) + return; + mNotationsToDraw = NOTATION_LONGDIV; + } +} + +NS_IMETHODIMP +nsMathMLmencloseFrame::Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow); + NS_ENSURE_SUCCESS(rv, rv); + + InitNotations(); + + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmencloseFrame::InheritAutomaticData(nsIFrame* aParent) +{ + // let the base class get the default from our parent + nsMathMLContainerFrame::InheritAutomaticData(aParent); + + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; + + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmencloseFrame::TransmitAutomaticData() +{ + if (IsToDraw(NOTATION_RADICAL)) { + // The TeXBook (Ch 17. p.141) says that \sqrt is cramped + UpdatePresentationDataFromChildAt(0, -1, + NS_MATHML_COMPRESSED, + NS_MATHML_COMPRESSED); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + ///////////// + // paint the menclosed content + nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, + aLists); + + NS_ENSURE_SUCCESS(rv, rv); + + if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) + return rv; + + nsRect mencloseRect = nsIFrame::GetRect(); + mencloseRect.x = mencloseRect.y = 0; + + if (IsToDraw(NOTATION_RADICAL)) { + rv = mMathMLChar[mRadicalCharIndex].Display(aBuilder, this, aLists); + NS_ENSURE_SUCCESS(rv, rv); + + nsRect rect; + mMathMLChar[mRadicalCharIndex].GetRect(rect); + rect.MoveBy(rect.width, 0); + rect.SizeTo(mContentWidth, mRuleThickness); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_LONGDIV)) { + rv = mMathMLChar[mLongDivCharIndex].Display(aBuilder, this, aLists); + NS_ENSURE_SUCCESS(rv, rv); + + nsRect rect; + mMathMLChar[mLongDivCharIndex].GetRect(rect); + rect.SizeTo(rect.width + mContentWidth, mRuleThickness); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_TOP)) { + nsRect rect(0, 0, mencloseRect.width, mRuleThickness); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_BOTTOM)) { + nsRect rect(0, mencloseRect.height - mRuleThickness, + mencloseRect.width, mRuleThickness); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_LEFT)) { + nsRect rect(0, 0, mRuleThickness, mencloseRect.height); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_RIGHT)) { + nsRect rect(mencloseRect.width - mRuleThickness, 0, + mRuleThickness, mencloseRect.height); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_ROUNDEDBOX)) { + rv = DisplayNotation(aBuilder, this, mencloseRect, aLists, + mRuleThickness, NOTATION_ROUNDEDBOX); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_CIRCLE)) { + rv = DisplayNotation(aBuilder, this, mencloseRect, aLists, + mRuleThickness, NOTATION_CIRCLE); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_UPDIAGONALSTRIKE)) { + rv = DisplayNotation(aBuilder, this, mencloseRect, aLists, + mRuleThickness, NOTATION_UPDIAGONALSTRIKE); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE)) { + rv = DisplayNotation(aBuilder, this, mencloseRect, aLists, + mRuleThickness, NOTATION_DOWNDIAGONALSTRIKE); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_HORIZONTALSTRIKE)) { + nsRect rect(0, mencloseRect.height / 2 - mRuleThickness / 2, + mencloseRect.width, mRuleThickness); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (IsToDraw(NOTATION_VERTICALSTRIKE)) { + nsRect rect(mencloseRect.width / 2 - mRuleThickness / 2, 0, + mRuleThickness, mencloseRect.height); + rv = DisplayBar(aBuilder, this, rect, aLists); + NS_ENSURE_SUCCESS(rv, rv); + } + return rv; +} + +/* virtual */ nsresult +nsMathMLmencloseFrame::MeasureForWidth(nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize) +{ + return PlaceInternal(aRenderingContext, PR_FALSE, aDesiredSize, PR_TRUE); +} + +/* virtual */ nsresult +nsMathMLmencloseFrame::Place(nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize) +{ + return PlaceInternal(aRenderingContext, aPlaceOrigin, aDesiredSize, PR_FALSE); +} + +/* 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 fm; + nscoord mEmHeight; + aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull, + 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 = PR_MAX(bmOne.ascent, bmBase.ascent); + bmBase.descent = PR_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) - 1) / 2; + nscoord padding2; + + // Update horizontal parameters + padding2 = ratio * bmBase.width; + + dx_left = PR_MAX(dx_left, padding2); + dx_right = PR_MAX(dx_right, padding2); + + // Update vertical parameters + padding2 = ratio * (bmBase.ascent + bmBase.descent); + + mBoundingMetrics.ascent = PR_MAX(mBoundingMetrics.ascent, + bmBase.ascent + padding2); + mBoundingMetrics.descent = PR_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 = PR_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 = PR_MAX(dx_left, bmLongdivChar.width); + + // Update vertical parameters + longdivAscent = bmBase.ascent + psi + mRuleThickness; + longdivDescent = PR_MAX(bmBase.descent, + (bmLongdivChar.ascent + bmLongdivChar.descent - + longdivAscent)); + + mBoundingMetrics.ascent = PR_MAX(mBoundingMetrics.ascent, + longdivAscent); + mBoundingMetrics.descent = PR_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 = PR_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 = PR_MAX(dx_left, bmRadicalChar.width); + + // Update vertical parameters + radicalAscent = bmBase.ascent + psi + mRuleThickness; + radicalDescent = PR_MAX(bmBase.descent, + (bmRadicalChar.ascent + bmRadicalChar.descent - + radicalAscent)); + + mBoundingMetrics.ascent = PR_MAX(mBoundingMetrics.ascent, + radicalAscent); + mBoundingMetrics.descent = PR_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 = PR_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 = PR_MIN(0, dx_left + bmBase.leftBearing); + mBoundingMetrics.rightBearing = + PR_MAX(mBoundingMetrics.width, dx_left + bmBase.rightBearing); + + aDesiredSize.width = mBoundingMetrics.width; + + aDesiredSize.ascent = PR_MAX(mBoundingMetrics.ascent, baseSize.ascent); + aDesiredSize.height = aDesiredSize.ascent + + PR_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 = PR_MAX(desiredSizeAscent, + longdivAscent + leading); + desiredSizeDescent = PR_MAX(desiredSizeDescent, + longdivDescent + mRuleThickness); + } + + if (IsToDraw(NOTATION_RADICAL)) { + desiredSizeAscent = PR_MAX(desiredSizeAscent, + radicalAscent + leading); + desiredSizeDescent = PR_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 = PR_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; +} + +nscoord +nsMathMLmencloseFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) +{ + nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize); + if (!gap) + return 0; + + // Move the MathML characters + nsRect rect; + for (PRUint32 i = 0; i < mMathMLChar.Length(); i++) { + mMathMLChar[i].GetRect(rect); + rect.MoveBy(gap, 0); + mMathMLChar[i].SetRect(rect); + } + + return gap; +} + +NS_IMETHODIMP +nsMathMLmencloseFrame::AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) +{ + if (aAttribute == nsGkAtoms::notation_) { + mNotationsToDraw = 0; + mLongDivCharIndex = mRadicalCharIndex = -1; + mMathMLChar.Clear(); + + InitNotations(); + } + + return nsMathMLContainerFrame:: + AttributeChanged(aNameSpaceID, aAttribute, aModType); +} + +////////////////// +// the Style System will use these to pass the proper style context to our +// MathMLChar +nsStyleContext* +nsMathMLmencloseFrame::GetAdditionalStyleContext(PRInt32 aIndex) const +{ + PRInt32 len = mMathMLChar.Length(); + if (aIndex >= 0 && aIndex < len) + return mMathMLChar[aIndex].GetStyleContext(); + else + return nsnull; +} + +void +nsMathMLmencloseFrame::SetAdditionalStyleContext(PRInt32 aIndex, + nsStyleContext* aStyleContext) +{ + PRInt32 len = mMathMLChar.Length(); + if (aIndex >= 0 && aIndex < len) + mMathMLChar[aIndex].SetStyleContext(aStyleContext); +} + +class nsDisplayNotation : public nsDisplayItem +{ +public: + nsDisplayNotation(nsIFrame* aFrame, const nsRect& aRect, + nscoord aThickness, nsMencloseNotation aType) + : nsDisplayItem(aFrame), mRect(aRect), + mThickness(aThickness), mType(aType) { + MOZ_COUNT_CTOR(nsDisplayNotation); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayNotation() { + MOZ_COUNT_DTOR(nsDisplayNotation); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, + const nsRect& aDirtyRect); + NS_DISPLAY_DECL_NAME("MathMLMencloseNotation") + +private: + nsRect mRect; + nscoord mThickness; + nsMencloseNotation mType; +}; + +void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder, + nsIRenderingContext* aCtx, + const nsRect& aDirtyRect) +{ + // get the gfxRect + nsPresContext* presContext = mFrame->PresContext(); + gfxRect rect = presContext-> + AppUnitsToGfxUnits(mRect + aBuilder->ToReferenceFrame(mFrame)); + + // paint the frame with the current text color + aCtx->SetColor(mFrame->GetStyleColor()->mColor); + + // change line width to mThickness + gfxContext *gfxCtx = aCtx->ThebesContext(); + gfxFloat currentLineWidth = gfxCtx->CurrentLineWidth(); + gfxFloat e = presContext->AppUnitsToGfxUnits(mThickness); + gfxCtx->SetLineWidth(e); + + rect.Inset(e / 2.0); + + gfxCtx->NewPath(); + + switch(mType) + { + case NOTATION_CIRCLE: + gfxCtx->Ellipse(rect.pos + rect.size / 2.0, rect.size); + break; + + case NOTATION_ROUNDEDBOX: + gfxCtx->RoundedRectangle(rect, gfxCornerSizes(3 * e), PR_TRUE); + break; + + case NOTATION_UPDIAGONALSTRIKE: + gfxCtx->Line(rect.BottomLeft(), rect.TopRight()); + break; + + case NOTATION_DOWNDIAGONALSTRIKE: + gfxCtx->Line(rect.TopLeft(), rect.BottomRight()); + break; + + default: + NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation"); + break; + } + + gfxCtx->Stroke(); + + // restore previous line width + gfxCtx->SetLineWidth(currentLineWidth); +} + +nsresult +nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, const nsRect& aRect, + const nsDisplayListSet& aLists, + nscoord aThickness, + nsMencloseNotation aType) +{ + if (!aFrame->GetStyleVisibility()->IsVisible() || aRect.IsEmpty() || + aThickness <= 0) + return NS_OK; + + return aLists.Content()->AppendNewToTop(new (aBuilder) + nsDisplayNotation(aFrame, aRect, + aThickness, + aType)); +} diff --git a/layout/mathml/nsMathMLmencloseFrame.h b/layout/mathml/nsMathMLmencloseFrame.h new file mode 100644 index 000000000000..e4cba9be9b9e --- /dev/null +++ b/layout/mathml/nsMathMLmencloseFrame.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla MathML Project. + * + * The Initial Developer of the Original Code is + * The University Of Queensland. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roger B. Sidje + * David J. Fiddes + * Vilya Harvey + * Shyjan Mahamud + * Frederic Wang - extension of to + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef nsMathMLmencloseFrame_h___ +#define nsMathMLmencloseFrame_h___ + +#include "nsCOMPtr.h" +#include "nsMathMLContainerFrame.h" + +// +// -- enclose content with a stretching symbol such +// as a long division sign. +// + +/* + The MathML REC describes: + + The menclose element renders its content inside the enclosing notation + specified by its notation attribute. menclose accepts any number of arguments; + if this number is not 1, its contents are treated as a single "inferred mrow" + containing its arguments, as described in Section 3.1.3 Required Arguments. +*/ + +enum nsMencloseNotation + { + NOTATION_LONGDIV = 0x1, + NOTATION_RADICAL = 0x2, + NOTATION_ROUNDEDBOX = 0x4, + NOTATION_CIRCLE = 0x8, + NOTATION_LEFT = 0x10, + NOTATION_RIGHT = 0x20, + NOTATION_TOP = 0x40, + NOTATION_BOTTOM = 0x80, + NOTATION_UPDIAGONALSTRIKE = 0x100, + NOTATION_DOWNDIAGONALSTRIKE = 0x200, + NOTATION_VERTICALSTRIKE = 0x400, + NOTATION_HORIZONTALSTRIKE = 0x800 + // NOTATION_MADRUWB = 0x1000 + }; + +class nsMathMLmencloseFrame : public nsMathMLContainerFrame { +public: + friend nsIFrame* NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); + + virtual nsresult + Place(nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize); + + virtual nsresult + MeasureForWidth(nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize); + + NS_IMETHOD + AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); + + virtual void + SetAdditionalStyleContext(PRInt32 aIndex, + nsStyleContext* aStyleContext); + virtual nsStyleContext* + GetAdditionalStyleContext(PRInt32 aIndex) const; + + NS_IMETHOD + Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow); + + NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists); + + NS_IMETHOD + InheritAutomaticData(nsIFrame* aParent); + + NS_IMETHOD + TransmitAutomaticData(); + + virtual nscoord + FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize); + +protected: + nsMathMLmencloseFrame(nsStyleContext* aContext); + virtual ~nsMathMLmencloseFrame(); + + nsresult PlaceInternal(nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize, + PRBool aWidthOnly); + + // functions to parse the "notation" attribute. + nsresult AddNotation(const nsAString& aNotation); + void InitNotations(); + + // Description of the notations to draw + PRUint32 mNotationsToDraw; + PRBool IsToDraw(nsMencloseNotation mask) + { + return mask & mNotationsToDraw; + } + + nscoord mRuleThickness; + nsTArray mMathMLChar; + PRInt8 mLongDivCharIndex, mRadicalCharIndex; + nscoord mContentWidth; + nsresult AllocateMathMLChar(nsMencloseNotation mask); + + // Display a frame of the specified type. + // @param aType Type of frame to display + nsresult DisplayNotation(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, const nsRect& aRect, + const nsDisplayListSet& aLists, + nscoord aThickness, nsMencloseNotation aType); +}; + +#endif /* nsMathMLmencloseFrame_h___ */ diff --git a/layout/mathml/nsMathMLmsqrtFrame.cpp b/layout/mathml/nsMathMLmsqrtFrame.cpp index 86e0769abd4b..170a00e99cc7 100644 --- a/layout/mathml/nsMathMLmsqrtFrame.cpp +++ b/layout/mathml/nsMathMLmsqrtFrame.cpp @@ -40,19 +40,10 @@ * * ***** END LICENSE BLOCK ***** */ - -#include "nsCOMPtr.h" -#include "nsFrame.h" -#include "nsPresContext.h" -#include "nsStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIRenderingContext.h" -#include "nsIFontMetrics.h" - #include "nsMathMLmsqrtFrame.h" // -// and -- form a radical - implementation +// -- form a radical - implementation // //NOTE: @@ -64,11 +55,6 @@ // MathML engine. Assuming that authors have the free fonts is part of the // deal. We are not responsible for cases of misconfigurations out there. -// additional style context to be used by our MathMLChar. -#define NS_SQR_CHAR_STYLE_CONTEXT_INDEX 0 - -static const PRUnichar kSqrChar = PRUnichar(0x221A); - nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { @@ -76,9 +62,7 @@ NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) } nsMathMLmsqrtFrame::nsMathMLmsqrtFrame(nsStyleContext* aContext) : - nsMathMLContainerFrame(aContext), - mSqrChar(), - mBarRect() + nsMathMLmencloseFrame(aContext) { } @@ -92,252 +76,17 @@ nsMathMLmsqrtFrame::Init(nsIContent* aContent, nsIFrame* aPrevInFlow) { nsresult rv = nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow); - - nsPresContext *presContext = PresContext(); - - // No need to tract the style context given to our MathML char. - // The Style System will use Get/SetAdditionalStyleContext() to keep it - // up-to-date if dynamic changes arise. - nsAutoString sqrChar; sqrChar.Assign(kSqrChar); - mSqrChar.SetData(presContext, sqrChar); - ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mSqrChar, PR_TRUE); + AllocateMathMLChar(NOTATION_RADICAL); + mNotationsToDraw |= NOTATION_RADICAL; return rv; } NS_IMETHODIMP -nsMathMLmsqrtFrame::InheritAutomaticData(nsIFrame* aParent) +nsMathMLmsqrtFrame::AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) { - // let the base class get the default from our parent - nsMathMLContainerFrame::InheritAutomaticData(aParent); - - mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; - - return NS_OK; -} - - -NS_IMETHODIMP -nsMathMLmsqrtFrame::TransmitAutomaticData() -{ - // 1. The REC says: - // The element leaves both attributes [displaystyle and scriptlevel] - // unchanged within all its arguments. - // 2. The TeXBook (Ch 17. p.141) says that \sqrt is cramped - UpdatePresentationDataFromChildAt(0, -1, - NS_MATHML_COMPRESSED, - NS_MATHML_COMPRESSED); - - return NS_OK; -} - -NS_IMETHODIMP -nsMathMLmsqrtFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) -{ - ///////////// - // paint the content we are square-rooting - nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); - NS_ENSURE_SUCCESS(rv, rv); - - ///////////// - // paint the sqrt symbol - if (!NS_MATHML_HAS_ERROR(mPresentationData.flags)) { - rv = mSqrChar.Display(aBuilder, this, aLists); - NS_ENSURE_SUCCESS(rv, rv); - - rv = DisplayBar(aBuilder, this, mBarRect, aLists); - NS_ENSURE_SUCCESS(rv, rv); - -#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) - // for visual debug - nsRect rect; - mSqrChar.GetRect(rect); - nsBoundingMetrics bm; - mSqrChar.GetBoundingMetrics(bm); - rv = DisplayBoundingMetrics(aBuilder, this, rect.TopLeft(), bm, aLists); -#endif - } - - return rv; -} - -/* virtual */ nsresult -nsMathMLmsqrtFrame::Place(nsIRenderingContext& aRenderingContext, - PRBool aPlaceOrigin, - nsHTMLReflowMetrics& aDesiredSize) -{ - /////////////// - // 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 bmSqr, bmBase; - bmBase = baseSize.mBoundingMetrics; - - //////////// - // Prepare the radical symbol and the overline bar - - aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull, - PresContext()->GetUserFontSet()); - nsCOMPtr fm; - aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); - - // 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(aRenderingContext, fm, ruleThickness); - - nsBoundingMetrics bmOne; - aRenderingContext.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; - - // make sure that the rule appears on the 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.ascent = ruleThickness; - contSize.descent = bmBase.ascent + bmBase.descent + psi; - - // height(radical) should be >= height(base) + psi + ruleThickness - nsBoundingMetrics radicalSize; - mSqrChar.Stretch(PresContext(), aRenderingContext, - 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); - - 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.ascent + bmSqr.descent - mBoundingMetrics.ascent)); - 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.height = aDesiredSize.ascent + - PR_MAX(baseSize.height - baseSize.ascent, - mBoundingMetrics.descent + ruleThickness); - aDesiredSize.width = mBoundingMetrics.width; - aDesiredSize.mBoundingMetrics = mBoundingMetrics; - - mReference.x = 0; - mReference.y = aDesiredSize.ascent; - - if (aPlaceOrigin) { - ////////////////// - // Finish reflowing child frames, positioning their origins so as to leave - // room for the sqrt char and the overline bar. - PositionRowChildFrames(radicalSize.width, aDesiredSize.ascent); - } - - return NS_OK; -} - -/* virtual */ nscoord -nsMathMLmsqrtFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext) -{ - // The child frames form an mrow - nscoord width = nsMathMLContainerFrame::GetIntrinsicWidth(aRenderingContext); - // Add the width of the radical symbol - width += mSqrChar.GetMaxWidth(PresContext(), *aRenderingContext); - - return width; -} - -/* virtual */ nsresult -nsMathMLmsqrtFrame::MeasureChildFrames(nsIRenderingContext& aRenderingContext, - nsHTMLReflowMetrics& aDesiredSize) -{ - return nsMathMLContainerFrame::Place(aRenderingContext, PR_FALSE, - aDesiredSize); -} - - -nscoord -nsMathMLmsqrtFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) -{ - nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize); - if (!gap) return 0; - - nsRect rect; - mSqrChar.GetRect(rect); - rect.MoveBy(gap, 0); - mSqrChar.SetRect(rect); - mBarRect.MoveBy(gap, 0); - return gap; -} - -// ---------------------- -// the Style System will use these to pass the proper style context to our MathMLChar -nsStyleContext* -nsMathMLmsqrtFrame::GetAdditionalStyleContext(PRInt32 aIndex) const -{ - switch (aIndex) { - case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: - return mSqrChar.GetStyleContext(); - break; - default: - return nsnull; - } -} - -void -nsMathMLmsqrtFrame::SetAdditionalStyleContext(PRInt32 aIndex, - nsStyleContext* aStyleContext) -{ - switch (aIndex) { - case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: - mSqrChar.SetStyleContext(aStyleContext); - break; - } + return nsMathMLContainerFrame:: + AttributeChanged(aNameSpaceID, aAttribute, aModType); } diff --git a/layout/mathml/nsMathMLmsqrtFrame.h b/layout/mathml/nsMathMLmsqrtFrame.h index 43b67ee21a57..0623e6c68b38 100644 --- a/layout/mathml/nsMathMLmsqrtFrame.h +++ b/layout/mathml/nsMathMLmsqrtFrame.h @@ -42,11 +42,10 @@ #ifndef nsMathMLmsqrtFrame_h___ #define nsMathMLmsqrtFrame_h___ -#include "nsCOMPtr.h" -#include "nsMathMLContainerFrame.h" +#include "nsMathMLmencloseFrame.h" // -// -- form a fraction from two subexpressions +// -- form a radical // /* @@ -68,62 +67,24 @@ These attributes are inherited by every element from its rendering environment, but can be set explicitly only on . (See Section 3.3.4.) */ -/* -TODO: -*/ - -class nsMathMLmsqrtFrame : public nsMathMLContainerFrame { +class nsMathMLmsqrtFrame : public nsMathMLmencloseFrame { public: - friend nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); - - virtual void - SetAdditionalStyleContext(PRInt32 aIndex, - nsStyleContext* aStyleContext); - virtual nsStyleContext* - GetAdditionalStyleContext(PRInt32 aIndex) const; + friend nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); NS_IMETHOD Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow); - virtual nsresult - Place(nsIRenderingContext& aRenderingContext, - PRBool aPlaceOrigin, - nsHTMLReflowMetrics& aDesiredSize); - - virtual nscoord - GetIntrinsicWidth(nsIRenderingContext* aRenderingContext); - - NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists); - NS_IMETHOD - InheritAutomaticData(nsIFrame* aParent); - - NS_IMETHOD - TransmitAutomaticData(); - - // the base method doesn't deal fully with because it only - // slides child frames and has no idea that we have a sqrt glyph that - // is part of the flow without being a frame. We need to shift our - // sqrt glyph too. - virtual nscoord - FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize); + AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); protected: nsMathMLmsqrtFrame(nsStyleContext* aContext); virtual ~nsMathMLmsqrtFrame(); - - virtual PRIntn GetSkipSides() const { return 0; } - - virtual nsresult - MeasureChildFrames(nsIRenderingContext& aRenderingContext, - nsHTMLReflowMetrics& aDesiredSize); - - nsMathMLChar mSqrChar; - nsRect mBarRect; }; #endif /* nsMathMLmsqrtFrame_h___ */