From da41db0cc45d6edbf26ce822b21c8c981c802b84 Mon Sep 17 00:00:00 2001 From: "rbs%maths.uq.edu.au" Date: Wed, 27 Feb 2002 01:35:27 +0000 Subject: [PATCH] bug 126619 - fixups for the final metrics of certain MathML characters, and add transliteration for U+2212 the official Unicode minus sign (ongoing bug 119664), r=roc+moz, rs=attinasi/blizzard, a=shaver --- .../tables/transliterate.properties | 2 + intl/unicharutil/tools/gentransliterate.pl | 2 + layout/mathml/base/src/mathfont.properties | 1 + layout/mathml/base/src/nsMathMLChar.cpp | 42 +++--- .../base/src/nsMathMLContainerFrame.cpp | 19 ++- .../mathml/base/src/nsMathMLContainerFrame.h | 46 ++++++- layout/mathml/base/src/nsMathMLFrame.cpp | 40 ++---- .../mathml/base/src/nsMathMLmfencedFrame.cpp | 61 +++++---- layout/mathml/base/src/nsMathMLmfencedFrame.h | 1 + layout/mathml/base/src/nsMathMLmoFrame.cpp | 120 ++++++++++++------ layout/mathml/base/src/nsMathMLmsqrtFrame.h | 11 ++ layout/mathml/content/src/mathml.css | 10 +- 12 files changed, 237 insertions(+), 118 deletions(-) diff --git a/intl/unicharutil/tables/transliterate.properties b/intl/unicharutil/tables/transliterate.properties index 8bcf6fb7751f..96c489fe0c37 100644 --- a/intl/unicharutil/tables/transliterate.properties +++ b/intl/unicharutil/tables/transliterate.properties @@ -87,6 +87,8 @@ entity.8289= entity.8290= # U+2146, DifferentialD, d for use in differentials, e.g., within integrals entity.8518=d +# U+2212, MINUS SIGN, official Unicode minus sign +entity.8722=- ## ## End of hand coded section ## Below are generated from the unicode character database diff --git a/intl/unicharutil/tools/gentransliterate.pl b/intl/unicharutil/tools/gentransliterate.pl index 0aeba173984d..6909bd46f9a6 100644 --- a/intl/unicharutil/tools/gentransliterate.pl +++ b/intl/unicharutil/tools/gentransliterate.pl @@ -110,6 +110,8 @@ entity.8289= entity.8290= # U+2146, DifferentialD, d for use in differentials, e.g., within integrals entity.8518=d +# U+2212, MINUS SIGN, official Unicode minus sign +entity.8722=- ## ## End of hand coded section ## Below are generated from the unicode character database diff --git a/layout/mathml/base/src/mathfont.properties b/layout/mathml/base/src/mathfont.properties index 0ed220c39af3..e8fd53230712 100644 --- a/layout/mathml/base/src/mathfont.properties +++ b/layout/mathml/base/src/mathfont.properties @@ -437,6 +437,7 @@ operator.\u21A9.infix = stretchy:horizontal lspace:thickmathspace rspace:thickma operator.\u21AA.infix = stretchy:horizontal lspace:thickmathspace rspace:thickmathspace # ↪ ↪ operator.\u23B0.prefix = stretchy:vertical fence:true lspace:0em rspace:0em # ⎰ ⎰ operator.\u23B1.postfix = stretchy:vertical fence:true lspace:0em rspace:0em # ⎱ ⎱ +operator.\u22C5.infix = lspace:thinmathspace rspace:thinmathspace # ċ ################################################################################## diff --git a/layout/mathml/base/src/nsMathMLChar.cpp b/layout/mathml/base/src/nsMathMLChar.cpp index ccf21d27a7c2..3ab2099de6aa 100644 --- a/layout/mathml/base/src/nsMathMLChar.cpp +++ b/layout/mathml/base/src/nsMathMLChar.cpp @@ -918,7 +918,7 @@ nsGlyphTableList::GetPreferredListAt(nsIPresContext* aPresContext, aGlyphTableList->Clear(); } aGlyphTableList->AppendElement(glyphTable); - *aCount++; + ++*aCount; } glyphTable = TableAt(++index); } @@ -1851,36 +1851,38 @@ nsMathMLChar::Paint(nsIPresContext* aPresContext, const nsStyleVisibility *visib = NS_STATIC_CAST(const nsStyleVisibility*, styleContext->GetStyleData(eStyleStruct_Visibility)); - if (visib->IsVisible() && NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) - { + // if the leaf style context that we use for stretchy chars has a background + // color we use it -- this feature is mostly used for testing and debugging + // purposes. Normally, users will set the background on the container frame. + if (visib->IsVisible() && NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { if (mRect.width && mRect.height) { - // Paint our background and border - PRIntn skipSides = 0; //aForFrame->GetSkipSides(); const nsStyleBorder *border = NS_STATIC_CAST(const nsStyleBorder*, styleContext->GetStyleData(eStyleStruct_Border)); - const nsStyleOutline *outline = NS_STATIC_CAST(const nsStyleOutline*, - styleContext->GetStyleData(eStyleStruct_Outline)); - - // if the leaf style context that we use for stretchy chars has a background color - // we use it, otherwise we let the rendering code lookup in our parent context const nsStyleBackground *backg = NS_STATIC_CAST(const nsStyleBackground*, styleContext->GetStyleData(eStyleStruct_Background)); nsRect rect(mRect); //0, 0, mRect.width, mRect.height); - if (0 == (backg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) + if (styleContext != parentContext.get() && + 0 == (backg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT)) nsCSSRendering::PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame, aDirtyRect, rect, *backg, *border, 0, 0); - else - nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, aForFrame, - aDirtyRect, rect, *border, 0, 0); + //else + // our container frame will take care of painting its background + // nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, aForFrame, + // aDirtyRect, rect, *border, 0, 0); +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + // for visual debug + PRIntn skipSides = 0; //aForFrame->GetSkipSides(); + const nsStyleOutline *outline = NS_STATIC_CAST(const nsStyleOutline*, + styleContext->GetStyleData(eStyleStruct_Outline)); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, aForFrame, aDirtyRect, rect, *border, styleContext, skipSides); nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, aForFrame, aDirtyRect, rect, *border, *outline, styleContext, 0); +#endif } } - if (visib->IsVisible() && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) - { + if (visib->IsVisible() && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Set color ... const nsStyleColor *color = NS_STATIC_CAST(const nsStyleColor*, styleContext->GetStyleData(eStyleStruct_Color)); @@ -2072,7 +2074,7 @@ nsMathMLChar::PaintVertically(nsIPresContext* aPresContext, rbearing = bmdata[first].rightBearing; } else { - NS_ASSERTION(PR_FALSE, "Cannot stretch - All parts missing"); + NS_ERROR("Cannot stretch - All parts missing"); return NS_ERROR_UNEXPECTED; } // paint the rule between the parts @@ -2108,7 +2110,7 @@ nsMathMLChar::PaintVertically(nsIPresContext* aPresContext, count++; dy += stride; aGlyphTable->DrawGlyph(aRenderingContext, aFont, glue, dx, dy); - // NS_ASSERTION(5000 == count, "Error - glyph table is incorrectly set"); + NS_ASSERTION(1000 != count, "something is probably wrong somewhere"); if (1000 == count) return NS_ERROR_UNEXPECTED; } aRenderingContext.PopState(clipState); @@ -2250,7 +2252,7 @@ nsMathMLChar::PaintHorizontally(nsIPresContext* aPresContext, descent = bmdata[first].descent; } else { - NS_ASSERTION(PR_FALSE, "Cannot stretch - All parts missing"); + NS_ERROR("Cannot stretch - All parts missing"); return NS_ERROR_UNEXPECTED; } // paint the rule between the parts @@ -2286,7 +2288,7 @@ nsMathMLChar::PaintHorizontally(nsIPresContext* aPresContext, count++; dx += stride; aGlyphTable->DrawGlyph(aRenderingContext, aFont, glue, dx, dy); - // NS_ASSERTION(5000 == count, "Error - glyph table is incorrectly set"); + NS_ASSERTION(1000 != count, "something is probably wrong somewhere"); if (1000 == count) return NS_ERROR_UNEXPECTED; } aRenderingContext.PopState(clipState); diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/layout/mathml/base/src/nsMathMLContainerFrame.cpp index 21dab98d30c4..d58828981f1d 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -1463,7 +1463,13 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, aDesiredSize.descent = childSize.descent; mBoundingMetrics = bmChild; // update to include the left correction - mBoundingMetrics.leftBearing += leftCorrection; + // but leave alone because the sqrt glyph itself is there first + nsCOMPtr tag; + mContent->GetTag(*getter_AddRefs(tag)); + if (tag.get() == nsMathMLAtoms::msqrt_) + leftCorrection = 0; + else + mBoundingMetrics.leftBearing += leftCorrection; } else { if (aDesiredSize.descent < childSize.descent) @@ -1510,8 +1516,16 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, nsCOMPtr childFrameType; childFrame->GetFrameType(getter_AddRefs(childFrameType)); GetReflowAndBoundingMetricsFor(childFrame, childSize, bmChild); + GetItalicCorrection(bmChild, leftCorrection, italicCorrection); dy = aDesiredSize.ascent - childSize.ascent; - if (0 < count) { + if (0 == count) { + // for , the sqrt glyph itself is there first + nsCOMPtr tag; + mContent->GetTag(*getter_AddRefs(tag)); + if (tag.get() == nsMathMLAtoms::msqrt_) + leftCorrection = 0; + } + else { // add inter frame spacing nscoord space = GetInterFrameSpacing(mPresentationData.scriptLevel, prevFrameType, childFrameType); @@ -1519,7 +1533,6 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, } count++; prevFrameType = childFrameType; - GetItalicCorrection(bmChild, leftCorrection, italicCorrection); // add left correction dx += leftCorrection; FinishReflowChild(childFrame, aPresContext, nsnull, childSize, dx, dy, 0); diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.h b/layout/mathml/base/src/nsMathMLContainerFrame.h index 89d39a4d0d17..0b2104face8f 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -369,10 +369,22 @@ public: // re-resolve our subtree to set any mathml-expected data nsMathMLContainerFrame::MapAttributesIntoCSS(aPresContext, this); nsMathMLContainerFrame::RebuildAutomaticDataForChildren(aPresContext, this); - nsMathMLContainerFrame::PropagateScriptStyleFor(aPresContext, this, 0); return rv; } + NS_IMETHOD + Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) + { + if (mScriptStyleChanged) { + mScriptStyleChanged = PR_FALSE; + nsMathMLContainerFrame::PropagateScriptStyleFor(aPresContext, this, 0); + } + return nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } + NS_IMETHOD AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -422,6 +434,15 @@ public: protected: nsMathMLmathBlockFrame() {} virtual ~nsMathMLmathBlockFrame() {} + + NS_IMETHOD + DidSetStyleContext(nsIPresContext* aPresContext) + { + mScriptStyleChanged = PR_TRUE; + return nsBlockFrame::DidSetStyleContext(aPresContext); + } + + PRBool mScriptStyleChanged; }; // -------------- @@ -439,10 +460,22 @@ public: // re-resolve our subtree to set any mathml-expected data nsMathMLContainerFrame::MapAttributesIntoCSS(aPresContext, this); nsMathMLContainerFrame::RebuildAutomaticDataForChildren(aPresContext, this); - nsMathMLContainerFrame::PropagateScriptStyleFor(aPresContext, this, 0); return rv; } + NS_IMETHOD + Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) + { + if (mScriptStyleChanged) { + mScriptStyleChanged = PR_FALSE; + nsMathMLContainerFrame::PropagateScriptStyleFor(aPresContext, this, 0); + } + return nsInlineFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } + NS_IMETHOD AppendFrames(nsIPresContext* aPresContext, nsIPresShell& aPresShell, @@ -492,6 +525,15 @@ public: protected: nsMathMLmathInlineFrame() {} virtual ~nsMathMLmathInlineFrame() {} + + NS_IMETHOD + DidSetStyleContext(nsIPresContext* aPresContext) + { + mScriptStyleChanged = PR_TRUE; + return nsInlineFrame::DidSetStyleContext(aPresContext); + } + + PRBool mScriptStyleChanged; }; #endif /* nsMathMLContainerFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLFrame.cpp b/layout/mathml/base/src/nsMathMLFrame.cpp index 9e0fb0a9655e..2a29f4ee6b42 100644 --- a/layout/mathml/base/src/nsMathMLFrame.cpp +++ b/layout/mathml/base/src/nsMathMLFrame.cpp @@ -304,7 +304,7 @@ nsMathMLFrame::GetAxisHeight(nsIRenderingContext& aRenderingContext, #endif nscoord xHeight; aFontMetrics->GetXHeight(xHeight); - PRUnichar minus = '-'; + PRUnichar minus = 0x2212; // not '-', but official Unicode minus sign nsBoundingMetrics bm; nsresult rv = aRenderingContext.GetBoundingMetrics(&minus, PRUint32(1), bm); if (NS_SUCCEEDED(rv)) { @@ -314,18 +314,6 @@ nsMathMLFrame::GetAxisHeight(nsIRenderingContext& aRenderingContext, // fall-back to the other version GetAxisHeight(aFontMetrics, aAxisHeight); } - -#if 0 - nscoord oldAxis; - GetAxisHeight(aFontMetrics, oldAxis); - - PRUnichar plus = '+'; - rv = aRenderingContext.GetBoundingMetrics(&plus, PRUint32(1), bm); - nscoord plusAxis = bm.ascent - (bm.ascent + bm.descent)/2;; - - printf("xheight:%4d Axis:%4d oldAxis:%4d plusAxis:%4d\n", - xHeight, aAxisHeight, oldAxis, plusAxis); -#endif } // ================ @@ -536,23 +524,26 @@ nsCSSMapping { }; static void -GetMathMLAttributeStyleSheet(nsIDocument* aDocument, +GetMathMLAttributeStyleSheet(nsIPresContext* aPresContext, nsIStyleSheet** aSheet) { static const char kTitle[] = "Internal MathML/CSS Attribute Style Sheet"; *aSheet = nsnull; // first, look if the attribute stylesheet is already there + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + nsCOMPtr styleSet; + presShell->GetStyleSet(getter_AddRefs(styleSet)); + if (!styleSet) + return; nsAutoString title; - PRInt32 count; - aDocument->GetNumberOfStyleSheets(&count); - for (PRInt32 i = 0; i < count; ++i) { - nsCOMPtr sheet; - aDocument->GetStyleSheetAt(i, getter_AddRefs(sheet)); + for (PRInt32 i = styleSet->GetNumberOfAgentStyleSheets() - 1; i >= 0; --i) { + nsCOMPtr sheet = getter_AddRefs(styleSet->GetAgentStyleSheetAt(i)); nsCOMPtr cssSheet(do_QueryInterface(sheet)); if (cssSheet) { cssSheet->GetTitle(title); - if (title.EqualsIgnoreCase(kTitle)) { + if (title.Equals(NS_ConvertASCIItoUCS2(kTitle))) { *aSheet = sheet; NS_IF_ADDREF(*aSheet); return; @@ -573,11 +564,8 @@ GetMathMLAttributeStyleSheet(nsIDocument* aDocument, cssSheet->SetDefaultNameSpaceID(nsMathMLAtoms::nameSpaceID); nsCOMPtr sheet(do_QueryInterface(cssSheet)); - // insert the stylesheet into the document without notifying observers - // (discovered that it will actually be inserted at position 1 since style - // sheets are internally arrayed between a nsIHTMLStyleSheet attribute sheet - // at the beginning and a nsIHTMLCSSStyleSheet inline sheet at the end...) - aDocument->InsertStyleSheetAt(sheet, 0, PR_FALSE); + // insert the stylesheet into the styleset without notifying observers + styleSet->AppendAgentStyleSheet(sheet); *aSheet = sheet; NS_ADDREF(*aSheet); } @@ -659,7 +647,7 @@ nsMathMLFrame::MapAttributesIntoCSS(nsIPresContext* aPresContext, aContent->GetDocument(*getter_AddRefs(doc)); if (!doc) return 0; - GetMathMLAttributeStyleSheet(doc, getter_AddRefs(sheet)); + GetMathMLAttributeStyleSheet(aPresContext, getter_AddRefs(sheet)); if (!sheet) return 0; // by construction, these cannot be null at this point diff --git a/layout/mathml/base/src/nsMathMLmfencedFrame.cpp b/layout/mathml/base/src/nsMathMLmfencedFrame.cpp index 09d34c6a17a0..74590547fe8a 100644 --- a/layout/mathml/base/src/nsMathMLmfencedFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmfencedFrame.cpp @@ -268,7 +268,19 @@ nsMathMLmfencedFrame::doReflow(nsIPresContext* aPresContext, nsMathMLContainerFrame* mathMLFrame = NS_STATIC_CAST(nsMathMLContainerFrame*, aForFrame); - + + PRInt32 i; + const nsStyleFont* font; + aForFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + nsCOMPtr fm; + aReflowState.rendContext->SetFont(font->mFont); + aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); + nscoord axisHeight, em; + GetAxisHeight(*aReflowState.rendContext, fm, axisHeight); + GetEmHeight(fm, em); + // leading to be left at the top and the bottom of stretched chars + nscoord leading = NSToCoordRound(0.2f * em); + ///////////// // Reflow children // Asking each child to cache its bounding metrics @@ -287,6 +299,12 @@ nsMathMLmfencedFrame::doReflow(nsIPresContext* aPresContext, nsIFrame* firstChild; aForFrame->FirstChild(aPresContext, nsnull, &firstChild); nsIFrame* childFrame = firstChild; + if (firstChild || aOpenChar || aCloseChar || aSeparatorsCount > 0) { + // We use the ASCII metrics to get our minimum height. This way, if we have + // borders or a background, they will fit better with other elements on the line + fm->GetMaxAscent(aDesiredSize.ascent); + fm->GetMaxDescent(aDesiredSize.descent); + } while (childFrame) { nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); @@ -360,16 +378,6 @@ nsMathMLmfencedFrame::doReflow(nsIPresContext* aPresContext, // Prepare the opening fence, separators, and closing fence, and // adjust the origin of children. - PRInt32 i; - const nsStyleFont* font; - aForFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); - nsCOMPtr fm; - aReflowState.rendContext->SetFont(font->mFont); - aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); - nscoord axisHeight, em; - GetAxisHeight(*aReflowState.rendContext, fm, axisHeight); - GetEmHeight(fm, em); - // we need to center around the axis if (firstChild) { // do nothing for an empty nscoord delta = PR_MAX(containerSize.ascent - axisHeight, @@ -382,19 +390,19 @@ nsMathMLmfencedFrame::doReflow(nsIPresContext* aPresContext, // opening fence ... ReflowChar(aPresContext, *aReflowState.rendContext, aOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, presentationData.scriptLevel, - axisHeight, em, containerSize, aDesiredSize); + axisHeight, leading, em, containerSize, aDesiredSize); ///////////////// // separators ... for (i = 0; i < aSeparatorsCount; i++) { ReflowChar(aPresContext, *aReflowState.rendContext, &aSeparatorsChar[i], NS_MATHML_OPERATOR_FORM_INFIX, presentationData.scriptLevel, - axisHeight, em, containerSize, aDesiredSize); + axisHeight, leading, em, containerSize, aDesiredSize); } ///////////////// // closing fence ... ReflowChar(aPresContext, *aReflowState.rendContext, aCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, presentationData.scriptLevel, - axisHeight, em, containerSize, aDesiredSize); + axisHeight, leading, em, containerSize, aDesiredSize); ////////////////// // Adjust the origins of each child. @@ -465,6 +473,7 @@ nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, nsOperatorFlags aForm, PRInt32 aScriptLevel, nscoord axisHeight, + nscoord leading, nscoord em, nsBoundingMetrics& aContainerSize, nsHTMLReflowMetrics& aDesiredSize) @@ -473,7 +482,7 @@ nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, nsOperatorFlags flags = 0; float leftSpace = 0.0f; float rightSpace = 0.0f; - + nsAutoString data; aMathMLChar->GetData(data); PRBool found = nsMathMLOperators::LookupOperator(data, aForm, @@ -491,8 +500,7 @@ nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, NS_STRETCH_DIRECTION_VERTICAL, aContainerSize, charSize); - if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) - { + if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) { // has changed... so center the char around the axis nscoord height = charSize.ascent + charSize.descent; charSize.ascent = height/2 + axisHeight; @@ -501,6 +509,7 @@ nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, else { // either it hasn't changed or stretching the char failed (i.e., // GetBoundingMetrics failed) + leading = 0; if (NS_FAILED(res)) { nsTextDimensions dimensions; aRenderingContext.GetTextDimensions(data.get(), data.Length(), dimensions); @@ -513,10 +522,10 @@ nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, } } - if (aDesiredSize.ascent < charSize.ascent) - aDesiredSize.ascent = charSize.ascent; - if (aDesiredSize.descent < charSize.descent) - aDesiredSize.descent = charSize.descent; + if (aDesiredSize.ascent < charSize.ascent + leading) + aDesiredSize.ascent = charSize.ascent + leading; + if (aDesiredSize.descent < charSize.descent + leading) + aDesiredSize.descent = charSize.descent + leading; // account the spacing charSize.width += NSToCoordRound((leftSpace + rightSpace) * em); @@ -542,22 +551,20 @@ nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar, // the char's y-origin was used to store the ascent ... nsRect rect; aMathMLChar->GetRect(rect); - + nscoord dy = aDesiredAscent - rect.y; - if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) - { + if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) { // the stretchy char will be centered around the axis // so we adjust the returned bounding metrics accordingly bm.descent = (bm.ascent + bm.descent) - rect.y; bm.ascent = rect.y; } - aMathMLChar->SetRect(nsRect(dx + rect.x, dy, - bm.width, rect.height)); + aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height)); bm.leftBearing += rect.x; bm.rightBearing += rect.x; - + // return rect.width since it includes lspace and rspace bm.width = rect.width; dx += rect.width; diff --git a/layout/mathml/base/src/nsMathMLmfencedFrame.h b/layout/mathml/base/src/nsMathMLmfencedFrame.h index 4d97844eee1b..0015115b6234 100644 --- a/layout/mathml/base/src/nsMathMLmfencedFrame.h +++ b/layout/mathml/base/src/nsMathMLmfencedFrame.h @@ -92,6 +92,7 @@ public: nsOperatorFlags aForm, PRInt32 aScriptLevel, nscoord axisHeight, + nscoord leading, nscoord em, nsBoundingMetrics& aContainerSize, nsHTMLReflowMetrics& aDesiredSize); diff --git a/layout/mathml/base/src/nsMathMLmoFrame.cpp b/layout/mathml/base/src/nsMathMLmoFrame.cpp index c8e6a2af2580..bb213c951bc6 100644 --- a/layout/mathml/base/src/nsMathMLmoFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmoFrame.cpp @@ -80,8 +80,15 @@ nsMathMLmoFrame::Paint(nsIPresContext* aPresContext, PRUint32 aFlags) { nsresult rv = NS_OK; - if (NS_MATHML_OPERATOR_GET_FORM(mFlags) || - NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { + PRBool useMathMLChar = + NS_MATHML_OPERATOR_GET_FORM(mFlags) || + NS_MATHML_OPERATOR_IS_CENTERED(mFlags); + if (!useMathMLChar || NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { + // let the base class paint the background, border, outline + rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); + } + if (useMathMLChar) { rv = mMathMLChar.Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, this); #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) @@ -97,10 +104,6 @@ nsMathMLmoFrame::Paint(nsIPresContext* aPresContext, } #endif } - else { // let the base class worry about the painting - rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, - aDirtyRect, aWhichLayer); - } return rv; } @@ -127,6 +130,15 @@ nsMathMLmoFrame::ProcessTextData(nsIPresContext* aPresContext) } } } + PRInt32 length = data.Length(); + + // special... in math mode, the usual minus sign '-' looks too short, so + // what we do here is to remap - to the official Unicode minus + // sign (U+2212) which looks much better. For background on this, see + // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1 + if (1 == length && data[0] == '-') { + data = PRUnichar(0x2212); + } // cache the special bits: mutable, accent, movablelimits, centered. // we need to do this in anticipation of other requirements, and these @@ -153,7 +165,7 @@ nsMathMLmoFrame::ProcessTextData(nsIPresContext* aPresContext) // see if this is an operator that should be centered to cater for // fonts that are not math-aware - if (1 == data.Length()) { + if (1 == length) { PRUnichar ch = data[0]; if ((ch == '+') || (ch == '=') || (ch == '*') || (ch == 0x00D7)) { // × @@ -167,9 +179,10 @@ nsMathMLmoFrame::ProcessTextData(nsIPresContext* aPresContext) } // get our 'form' and lookup in the Operator Dictionary to fetch -// our default data that may come from there, the look our attributes. -// The function has to be called during reflow because certain value -// before, we will re-use unchanged things that we computed earlier +// our default data that may come from there. Then complete our setup +// using attributes that we may have. To stay in sync, this function is +// called very often. We depend on many things that may change around us. +// However, we re-use unchanged values. void nsMathMLmoFrame::ProcessOperatorData(nsIPresContext* aPresContext) { @@ -302,7 +315,7 @@ nsMathMLmoFrame::ProcessOperatorData(nsIPresContext* aPresContext) nsAutoString data; mMathMLChar.GetData(data); PRBool found = nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace); - if (found) { + if (found && (lspace || rspace)) { // cache the default values of lspace & rspace that we get from the dictionary. // since these values are relative to the 'em' unit, convert to twips now nscoord em; @@ -349,7 +362,8 @@ nsMathMLmoFrame::ProcessOperatorData(nsIPresContext* aPresContext) leftSpace = CalcLength(aPresContext, mStyleContext, cssValue); } } - else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { + else if (mPresentationData.scriptLevel > 0 && + NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { leftSpace = 0; } @@ -367,15 +381,28 @@ nsMathMLmoFrame::ProcessOperatorData(nsIPresContext* aPresContext) rightSpace = CalcLength(aPresContext, mStyleContext, cssValue); } } - else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { + else if (mPresentationData.scriptLevel > 0 && + NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { rightSpace = 0; } + // little extra tuning to round lspace & rspace to at least a pixel so that + // operators don't look as if they are colliding with their operands + if (leftSpace || rightSpace) { + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + if (leftSpace && leftSpace < onePixel) + leftSpace = onePixel; + if (rightSpace && rightSpace < onePixel) + rightSpace = onePixel; + } + // the values that we get from our attributes override the dictionary mEmbellishData.leftSpace = leftSpace; mEmbellishData.rightSpace = rightSpace; - // Nows see if there are user-defined attributes that override the dictionary. + // Now see if there are user-defined attributes that override the dictionary. // XXX If an attribute can be forced to be true when it is false in the // dictionary, then the following code has to change... @@ -505,15 +532,17 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, nsCOMPtr fm; aRenderingContext.SetFont(font->mFont); aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); - nscoord leading, axisHeight, height; + nscoord leading = 0, axisHeight, height; GetAxisHeight(aRenderingContext, fm, axisHeight); // Operators that exist in the dictionary, or those that are to be centered // to cater for fonts that are not math-aware, are handled by the MathMLChar + PRBool useMathMLChar = + NS_MATHML_OPERATOR_GET_FORM(mFlags) || + NS_MATHML_OPERATOR_IS_CENTERED(mFlags);; - if (NS_MATHML_OPERATOR_GET_FORM(mFlags) || - NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { - nsBoundingMetrics charSize; + nsBoundingMetrics charSize; + if (useMathMLChar) { nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics; nsBoundingMetrics container = initialSize; @@ -644,15 +673,16 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed) // clear our 'form' to behave as if the operator wasn't in the dictionary mFlags &= ~NS_MATHML_OPERATOR_FORM; + useMathMLChar = PR_FALSE; } else { // update our bounding metrics... it becomes that of our MathML char - mMathMLChar.GetBoundingMetrics(mBoundingMetrics); + mBoundingMetrics = charSize; // if the returned direction is 'unsupported', the char didn't actually change. // So we do the centering only if necessary - if ((mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) - || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { + if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED || + NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { // the desired size returned by mMathMLChar maybe different @@ -677,30 +707,44 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, // this seems more reliable than using fm->GetLeading() on suspicious fonts nscoord em; GetEmHeight(fm, em); - leading = NSToCoordRound(0.2f * em); - - aDesiredStretchSize.ascent = mBoundingMetrics.ascent + leading; - aDesiredStretchSize.descent = mBoundingMetrics.descent + leading; + leading = NSToCoordRound(0.2f * em); // so, leading remains 0 if we don't get here } - aDesiredStretchSize.height = aDesiredStretchSize.ascent + aDesiredStretchSize.descent; - aDesiredStretchSize.width = mBoundingMetrics.width; - aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; - - nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent; - mMathMLChar.SetRect( - nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent)); - - mReference.x = 0; - mReference.y = aDesiredStretchSize.ascent; } } - if (!NS_MATHML_OPERATOR_GET_FORM(mFlags) && - !NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { + if (!useMathMLChar) { // Place our children using the default method Place(aPresContext, aRenderingContext, PR_TRUE, aDesiredStretchSize); } + // Fixup for the final height. + // On one hand, our stretchy height can sometimes be shorter than surrounding + // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading| + // that is smaller than the ASCII's ascent, hence when painting the background + // later, it won't look uniform along the line. + // On the other hand, sometimes we may leave too much gap when our glyph happens + // to come from a font with tall glyphs. For example, since CMEX10 has very tall + // glyphs, its natural font metrics are large, even if we pick a small glyph + // whose size is comparable to the size of a normal ASCII glyph. + // So to avoid uneven spacing in either of these two cases, we use the height + // of the ASCII font as a reference and try to match it if possible. + nscoord ascent, descent; + fm->GetMaxAscent(ascent); + fm->GetMaxDescent(descent); + aDesiredStretchSize.ascent = PR_MAX(mBoundingMetrics.ascent + leading, ascent); + aDesiredStretchSize.descent = PR_MAX(mBoundingMetrics.descent + leading, descent); + aDesiredStretchSize.height = aDesiredStretchSize.ascent + aDesiredStretchSize.descent; + aDesiredStretchSize.width = mBoundingMetrics.width; + aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; + mReference.x = 0; + mReference.y = aDesiredStretchSize.ascent; + // Place our mMathMLChar, its origin is in our coordinate system + if (useMathMLChar) { + nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent; + mMathMLChar.GetBoundingMetrics(charSize); + mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent)); + } + // Before we leave... there is a last item in the check-list: // If our parent is not embellished, it means we are the outermost embellished // container and so we put the spacing, otherwise we don't include the spacing, @@ -723,7 +767,7 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; nsRect rect; - if (NS_MATHML_OPERATOR_GET_FORM(mFlags)) { + if (useMathMLChar) { mMathMLChar.GetRect(rect); mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y, rect.width, rect.height)); } diff --git a/layout/mathml/base/src/nsMathMLmsqrtFrame.h b/layout/mathml/base/src/nsMathMLmsqrtFrame.h index 47936a151d02..1592d0ce1bac 100644 --- a/layout/mathml/base/src/nsMathMLmsqrtFrame.h +++ b/layout/mathml/base/src/nsMathMLmsqrtFrame.h @@ -92,6 +92,17 @@ public: NS_IMETHOD TransmitAutomaticData(nsIPresContext* aPresContext); + virtual nsresult + FixInterFrameSpacing(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize) + { + // XXX the base method doesn't work properly 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, but since m0.9.9 is going out... do nothing for now + return NS_OK; + } + protected: nsMathMLmsqrtFrame(); virtual ~nsMathMLmsqrtFrame(); diff --git a/layout/mathml/content/src/mathml.css b/layout/mathml/content/src/mathml.css index 7804a654f67b..7797e932351e 100644 --- a/layout/mathml/content/src/mathml.css +++ b/layout/mathml/content/src/mathml.css @@ -378,18 +378,24 @@ mtd[-moz-math-columnline="dashed"] { Authors can make elements on a document to be stretched with different fonts, e.g., - To request the use of TeX fonts, you can do: + To request the use of TeX fonts, you can add a with: ... with the associated CSS declaration mo[myfonts="tex"]:-moz-math-font-style-stretchy { font-family: CMSY10, CMEX10; } - To request the use of Mathematica fonts, you can do: + To request the use of Mathematica fonts, you can add a with: ... with the associated CSS declaration mo[myfonts="mathematica"]:-moz-math-font-style-stretchy { font-family: Math1, Math2, Math4; } + Of course, if you just want all of the stretchy characters in your + document to be stretched with your preferred list, you can just do: + :-moz-math-font-style-stretchy { + font-family: [your-particular-list] + } + Note that like other fonts in the document, users can override this by clicking the pref to override document fonts. /**************************************************************************/