diff --git a/mozilla/layout/mathml/base/src/Makefile.in b/mozilla/layout/mathml/base/src/Makefile.in index e3420f67483..19ed9f5868b 100644 --- a/mozilla/layout/mathml/base/src/Makefile.in +++ b/mozilla/layout/mathml/base/src/Makefile.in @@ -50,6 +50,7 @@ CPPSRCS = nsMathMLChar.cpp \ nsMathMLmsubsupFrame.cpp \ nsMathMLmmultiscriptsFrame.cpp \ nsMathMLmiFrame.cpp \ + nsMathMLmnFrame.cpp \ nsMathMLmtdFrame.cpp \ nsMathMLmoFrame.cpp \ nsMathMLmunderFrame.cpp \ diff --git a/mozilla/layout/mathml/base/src/makefile.win b/mozilla/layout/mathml/base/src/makefile.win index b3de52bf297..6b5aa0b6200 100644 --- a/mozilla/layout/mathml/base/src/makefile.win +++ b/mozilla/layout/mathml/base/src/makefile.win @@ -36,6 +36,7 @@ CPPSRCS= nsMathMLChar.cpp \ nsMathMLmfracFrame.cpp \ nsMathMLmsubFrame.cpp \ nsMathMLmiFrame.cpp \ + nsMathMLmnFrame.cpp \ nsMathMLmsubsupFrame.cpp \ nsMathMLmmultiscriptsFrame.cpp \ nsMathMLmsupFrame.cpp \ @@ -58,6 +59,7 @@ CPP_OBJS= .\$(OBJDIR)\nsMathMLChar.obj \ .\$(OBJDIR)\nsMathMLmfracFrame.obj \ .\$(OBJDIR)\nsMathMLmsubFrame.obj \ .\$(OBJDIR)\nsMathMLmiFrame.obj \ + .\$(OBJDIR)\nsMathMLmnFrame.obj \ .\$(OBJDIR)\nsMathMLmsubsupFrame.obj \ .\$(OBJDIR)\nsMathMLmmultiscriptsFrame.obj \ .\$(OBJDIR)\nsMathMLmsupFrame.obj \ diff --git a/mozilla/layout/mathml/base/src/nsIMathMLFrame.h b/mozilla/layout/mathml/base/src/nsIMathMLFrame.h index 6dcaa0f4704..194ed1fa8eb 100644 --- a/mozilla/layout/mathml/base/src/nsIMathMLFrame.h +++ b/mozilla/layout/mathml/base/src/nsIMathMLFrame.h @@ -22,7 +22,7 @@ #ifndef nsIMathMLFrame_h___ #define nsIMathMLFrame_h___ -struct nsEmbellishState; +struct nsEmbellishData; struct nsStretchMetrics; typedef PRInt32 nsStretchDirection; @@ -59,13 +59,13 @@ public: NS_IMETHOD SetBoundingMetrics(const nsBoundingMetrics& aBoundingMetrics) = 0; -/* + NS_IMETHOD GetReference(nsPoint& aReference) = 0; NS_IMETHOD SetReference(const nsPoint& aReference) = 0; -*/ + /* SUPPORT FOR STRETCHY ELEMENTS: */ /*====================================================================*/ @@ -161,15 +161,15 @@ public: NS_IMETHOD EmbellishOperator() = 0; - /* GetEmbellishState/SetEmbellishState : + /* GetEmbellishData/SetEmbellishData : * Get/Set the mEmbellish member data. */ NS_IMETHOD - GetEmbellishState(nsEmbellishState& aEmbellishState) = 0; + GetEmbellishData(nsEmbellishData& aEmbellishData) = 0; NS_IMETHOD - SetEmbellishState(const nsEmbellishState& aEmbellishState) = 0; + SetEmbellishData(const nsEmbellishData& aEmbellishData) = 0; /* SUPPORT FOR SCRIPTING ELEMENTS: */ @@ -199,7 +199,7 @@ public: * their mDisplayStyle to aDisplayStyle and increment their mScriptLevel * with aScriptLevelIncrement. The increment is propagated down to the * subtrees of each of these child frames. Note that is the only - * tag which allows + * tag which allows * to reset or increment the scriptlevel in a manual way. Therefore * has its own peculiar version of this method. */ @@ -259,6 +259,26 @@ struct nsStretchMetrics { } }; +// struct used by an embellished container to keep track of its embellished child +struct nsEmbellishData { + PRUint32 flags; + nsIFrame* firstChild; // handy pointer on our embellished child + nsIFrame* core; // pointer on the mo frame at the core of the embellished hierarchy + nsStretchDirection direction; + nscoord leftSpace, rightSpace; + + nsEmbellishData() + { + flags = 0; + firstChild = nsnull; + core = nsnull; + direction = NS_STRETCH_DIRECTION_UNSUPPORTED; + leftSpace = rightSpace = 0; + } +}; + +// -------------- + #define NS_MATHML_EMBELLISH_OPERATOR 0x1 #define NS_MATHML_STRETCH_FIRST_CHILD NS_MATHML_EMBELLISH_OPERATOR @@ -280,23 +300,5 @@ struct nsStretchMetrics { #define NS_MATHML_WILL_STRETCH_ALL_CHILDREN(_flags) \ (NS_MATHML_STRETCH_ALL_CHILDREN == ((_flags) & NS_MATHML_STRETCH_ALL_CHILDREN)) -// struct used by an embellished container to keep track of its embellished child -struct nsEmbellishState { - PRUint32 flags; - nsIFrame* firstChild; // handy pointer on our embellished child - nsIFrame* core; // pointer on the mo frame at the core of the embellished hierarchy - nsStretchDirection direction; - nscoord leftSpace, rightSpace; - - nsEmbellishState() - { - flags = 0; - firstChild = nsnull; - core = nsnull; - direction = NS_STRETCH_DIRECTION_UNSUPPORTED; - leftSpace = rightSpace = 0; - } -}; - #endif /* nsIMathMLFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLChar.cpp b/mozilla/layout/mathml/base/src/nsMathMLChar.cpp index 5c45a9128ed..43314698108 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLChar.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLChar.cpp @@ -61,8 +61,8 @@ Three steps are needed to extend the table: ---------------------------------------=--- - 1. Append your new section in gMathMLCharGlyph[]. - 2. Append your new enum in nsMathMLCharEnum, and kMathMLChar + 1. Append your new enum in nsMathMLCharList.h + 2. Append your new section in gMathMLCharGlyph[]. 3. Append a new pointer in gMathMLCharIndex[], so that gMathMLCharIndex[your_enum] points to the begining of your new section in gMathMLCharGlyph[]. That is, @@ -263,38 +263,18 @@ static PRInt32 gMathMLCharIndex[] = { 48, // eMathMLChar_UpArrow, 54, // eMathMLChar_LeftArrow, 60, // eMathMLChar_RightArrow, - 66, // eMathMLChar_RadicalBar, - 72, // eMathMLChar_Radical, -- placeholder for now + 66, // eMathMLChar_OverBar, 72, // eMathMLChar_VerticalBar, + 78, // eMathMLChar_Sqrt, -- placeholder for now 78, // safeguard, *must* always point at the *end* of gMathMLCharGlyph[] }; -// data to enable a clean architecture and extensibility - -#define STRETCH_UNSUPPORTED NS_STRETCH_DIRECTION_UNSUPPORTED -#define STRETCH_HORIZONTAL NS_STRETCH_DIRECTION_HORIZONTAL -#define STRETCH_VERTICAL NS_STRETCH_DIRECTION_VERTICAL - static const PRInt32 kMathMLChar[] = { - eMathMLChar_LeftParenthesis , '(', STRETCH_VERTICAL, - eMathMLChar_RightParenthesis , ')', STRETCH_VERTICAL, - eMathMLChar_Integral , 0x222B, STRETCH_VERTICAL, - eMathMLChar_LeftSquareBracket, '[', STRETCH_VERTICAL, - eMathMLChar_RightSquareBracket, ']', STRETCH_VERTICAL, - eMathMLChar_LeftCurlyBracket, '{', STRETCH_VERTICAL, - eMathMLChar_RightCurlyBracket, '}', STRETCH_VERTICAL, - eMathMLChar_DownArrow, 0x2193, STRETCH_VERTICAL, - eMathMLChar_UpArrow, 0x2191, STRETCH_VERTICAL, - eMathMLChar_LeftArrow, 0x2190, STRETCH_HORIZONTAL, - eMathMLChar_RightArrow, 0x2192, STRETCH_HORIZONTAL, - eMathMLChar_RadicalBar, 0x00AF, STRETCH_HORIZONTAL, - eMathMLChar_Radical, 0x221A, STRETCH_UNSUPPORTED, - eMathMLChar_VerticalBar, '|', STRETCH_VERTICAL, +#define MATHML_CHAR(_name, _value, _direction) eMathMLChar_##_name, _value, _direction, +#include "nsMathMLCharList.h" +#undef MATHML_CHAR }; -#undef STRETCH_UNSUPPORTED -#undef STRETCH_HORIZONTAL -#undef STRETCH_VERTICAL //--------------------------------------------- @@ -306,6 +286,7 @@ nsMathMLChar::SetData(nsString& aData) { // some assumptions until proven otherwise! mEnum = eMathMLChar_DONT_STRETCH; mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; + mBoundingMetrics.Clear(); // lookup the enum ... if (1 == mData.Length()) { PRUnichar ch = mData[0]; @@ -328,6 +309,7 @@ nsMathMLChar::SetEnum(nsMathMLCharEnum aEnum) { // some assumptions until proven otherwise! mData = ""; mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; + mBoundingMetrics.Clear(); // lookup the data ... if (mEnum != eMathMLChar_DONT_STRETCH) { PRInt32 count = sizeof(kMathMLChar) / sizeof(kMathMLChar[0]); @@ -388,8 +370,18 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, aDirection = mDirection; } - // quick return if there is nothing special about this char + // Set font + nsStyleFont font; + aStyleContext->GetStyle(eStyleStruct_Font, font); + aRenderingContext.SetFont(font.mFont); + + // cache our bounding metrics and quickly return if there is nothing + // special about this char if (eMathMLChar_DONT_STRETCH == mEnum || aDirection != mDirection) { + rv = aRenderingContext.GetBoundingMetrics(mData.GetUnicode(), + PRUint32(mData.Length()), + mBoundingMetrics); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", mData[0], mData[0]&0x00FF); /*getchar();*/ return rv; } return NS_OK; } @@ -398,12 +390,20 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, if (aDirection == NS_STRETCH_DIRECTION_VERTICAL) { if (aContainerSize.height <= aDesiredStretchSize.height) { mEnum = eMathMLChar_DONT_STRETCH; // ensure that the char later behaves like a normal char + rv = aRenderingContext.GetBoundingMetrics(mData.GetUnicode(), + PRUint32(mData.Length()), + mBoundingMetrics); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", mData[0], mData[0]&0x00FF); /*getchar();*/ return rv; } return NS_OK; } } else if (aDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { if (aContainerSize.width <= aDesiredStretchSize.width) { mEnum = eMathMLChar_DONT_STRETCH; // ensure that the char later behaves like a normal char + rv = aRenderingContext.GetBoundingMetrics(mData.GetUnicode(), + PRUint32(mData.Length()), + mBoundingMetrics); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", mData[0], mData[0]&0x00FF); /*getchar();*/ return rv; } return NS_OK; } } @@ -416,11 +416,6 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, // XXX Note: there are other symbols that just need to slightly // increase their size, like \Sum - // Set font - nsStyleFont font; - aStyleContext->GetStyle(eStyleStruct_Font, font); - aRenderingContext.SetFont(font.mFont); - nscoord height = aDesiredStretchSize.height; nscoord width = aDesiredStretchSize.width; nscoord ascent = aDesiredStretchSize.ascent; @@ -433,12 +428,16 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, // try first to see if there is a glyph of appropriate size ... PRBool sizeOK = PR_FALSE; PRUnichar ch = gMathMLCharGlyph[index++]; - nsBoundingMetrics bm; + nsBoundingMetrics bm, bm0; + PRInt32 index0 = index; while (ch && index <= limit) { // printf("Checking size of:%c index:%d\n", ch & 0x00FF, index); rv = aRenderingContext.GetBoundingMetrics(&ch, PRUint32(1), bm); if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); /*getchar();*/ return rv; } + // keep track of the default bounding metrics + if (index0 == index) bm0 = bm; + h = bm.ascent - bm.descent; w = bm.rightBearing - bm.leftBearing; @@ -453,7 +452,10 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, ascent = bm.ascent; height = bm.ascent - bm.descent; width = bm.rightBearing - bm.leftBearing; + + // cache all this information mGlyph = ch; + mBoundingMetrics = bm; break; } ch = gMathMLCharGlyph[index++]; @@ -477,12 +479,23 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, rv = aRenderingContext.GetBoundingMetrics(&ch, PRUint32(1), bm); if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); /*getchar();*/ return rv; } if (w < bm.width) w = bm.width; - if (i < 3) h += nscoord(flex[i]*(bm.ascent-bm.descent)); // sum heights of the parts... + if (i < 3) { + h += nscoord(flex[i]*(bm.ascent-bm.descent)); // sum heights of the parts... + // compute and cache our bounding metrics (vertical stacking!) + if (mBoundingMetrics.leftBearing > bm.leftBearing) + mBoundingMetrics.leftBearing = bm.leftBearing; + if (mBoundingMetrics.rightBearing < bm.rightBearing) + mBoundingMetrics.rightBearing = bm.rightBearing; + } } if (h <= aContainerSize.height) { // can nicely fit in the available space... width = w; + mBoundingMetrics.width = w; + mBoundingMetrics.ascent = aContainerSize.ascent; + mBoundingMetrics.descent = -aContainerSize.descent; } else { // sum of parts doesn't fit in the space... will use a single glyph mEnum = eMathMLChar_DONT_STRETCH; // ensure that the char behaves like a normal char + mBoundingMetrics = bm0; return NS_OK; } } @@ -497,16 +510,26 @@ nsMathMLChar::Stretch(nsIPresContext* aPresContext, ch = gMathMLCharGlyph[index+i]; rv = aRenderingContext.GetBoundingMetrics(&ch, PRUint32(1), bm); if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); /*getchar();*/ return rv; } + if (0 == i) bm0 = bm; if (a < bm.ascent) a = bm.ascent; if (d > bm.descent) d = bm.descent; - if (i < 3) w += nscoord(flex[i]*(bm.rightBearing-bm.leftBearing)); // sum widths of the parts... + if (i < 3) { + w += nscoord(flex[i]*(bm.rightBearing-bm.leftBearing)); // sum widths of the parts... + // compute and cache our bounding metrics (horizontal stacking) + if (0 == i) + mBoundingMetrics = bm; + else + mBoundingMetrics += bm; + } } if (w <= aContainerSize.width) { // can nicely fit in the available space... //printf("%04X can nicely fit in the available space...\n", ch); // ascent = a; // height = a - d; + mBoundingMetrics.width = aContainerSize.width; } else { // sum of parts doesn't fit in the space... will use a single glyph mEnum = eMathMLChar_DONT_STRETCH; // ensure that the char behaves like a normal char + mBoundingMetrics = bm0; return NS_OK; } } diff --git a/mozilla/layout/mathml/base/src/nsMathMLChar.h b/mozilla/layout/mathml/base/src/nsMathMLChar.h index 83675d0ca93..e3a7218e5e7 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLChar.h +++ b/mozilla/layout/mathml/base/src/nsMathMLChar.h @@ -25,26 +25,16 @@ #include "nsMathMLOperators.h" #include "nsIMathMLFrame.h" -// chars that we know how something about +// enum of chars that we know something about enum nsMathMLCharEnum { eMathMLChar_DONT_STRETCH = -1, - eMathMLChar_LeftParenthesis, - eMathMLChar_RightParenthesis, - eMathMLChar_Integral , - eMathMLChar_LeftSquareBracket, - eMathMLChar_RightSquareBracket, - eMathMLChar_LeftCurlyBracket, - eMathMLChar_RightCurlyBracket, - eMathMLChar_DownArrow, - eMathMLChar_UpArrow, - eMathMLChar_LeftArrow, - eMathMLChar_RightArrow, - eMathMLChar_RadicalBar, - eMathMLChar_Radical, - eMathMLChar_VerticalBar, +#define MATHML_CHAR(_name, _value, _direction) eMathMLChar_##_name, +#include "nsMathMLCharList.h" +#undef MATHML_CHAR eMathMLChar_COUNT }; + // class used to handle stretchy symbols (accent and boundary symbol) class nsMathMLChar { @@ -124,12 +114,18 @@ public: mRect = aRect; } + void + GetBoundingMetrics(nsBoundingMetrics aBoundingMetrics) { + aBoundingMetrics = mBoundingMetrics; + } + private: nsString mData; PRUnichar mGlyph; nsRect mRect; nsStretchDirection mDirection; nsMathMLCharEnum mEnum; + nsBoundingMetrics mBoundingMetrics; // helper methods diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp index ba92f60ccdd..966109415e3 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -27,6 +27,7 @@ #include "nsLineLayout.h" #include "nsHTMLIIDs.h" #include "nsIPresContext.h" +#include "nsIPresShell.h" #include "nsHTMLAtoms.h" #include "nsUnitConversion.h" #include "nsIStyleContext.h" @@ -150,28 +151,30 @@ nsMathMLContainerFrame::ReflowEmptyChild(nsIPresContext* aPresContext, NS_IMETHODIMP nsMathMLContainerFrame::GetBoundingMetrics(nsBoundingMetrics& aBoundingMetrics) { + aBoundingMetrics = mBoundingMetrics; return NS_OK; } NS_IMETHODIMP nsMathMLContainerFrame::SetBoundingMetrics(const nsBoundingMetrics& aBoundingMetrics) { + mBoundingMetrics = aBoundingMetrics; return NS_OK; } -/* -NS_IMETHOD -GetReference(nsPoint& aReference) +NS_IMETHODIMP +nsMathMLContainerFrame::GetReference(nsPoint& aReference) { + aReference = mReference; return NS_OK; } -NS_IMETHOD -SetReference(const nsPoint& aReference); +NS_IMETHODIMP +nsMathMLContainerFrame::SetReference(const nsPoint& aReference) { + mReference = aReference; return NS_OK; } -*/ /* ///////////// @@ -187,19 +190,19 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, nsStretchMetrics& aDesiredStretchSize) { nsresult rv = NS_OK; - if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellish.flags)) { + if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) { - if (NS_MATHML_STRETCH_WAS_DONE(mEmbellish.flags)) { + if (NS_MATHML_STRETCH_WAS_DONE(mEmbellishData.flags)) { printf("WARNING *** it is wrong to fire stretch more than once on a frame...\n"); // NS_ASSERTION(PR_FALSE,"Stretch() was fired more than once on a frame!"); return NS_OK; } - mEmbellish.flags |= NS_MATHML_STRETCH_DONE; + mEmbellishData.flags |= NS_MATHML_STRETCH_DONE; // Pass the stretch to the first non-empty child ... - nsIFrame* childFrame = mEmbellish.firstChild; + nsIFrame* childFrame = mEmbellishData.firstChild; NS_ASSERTION(childFrame, "Something is wrong somewhere"); if (childFrame) { @@ -209,24 +212,24 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, if (NS_SUCCEEDED(rv) && aMathMLFrame) { nsHTMLReflowMetrics aReflowMetrics(nsnull); - nsRect rect; + nsRect rect; childFrame->GetRect(rect); // And the trick is that rect.x is still holding the descent, and rect.y // is still holding the ascent ... nsStretchMetrics childSize(rect.x, rect.y, rect.width, rect.height); nsStretchMetrics container(aContainerSize); - if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && aStretchDirection != mEmbellish.direction) { + if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && aStretchDirection != mEmbellishData.direction) { // change the direction and confine the stretch to us #if 0 GetDesiredStretchSize(aPresContext, aRenderingContext, container); #endif GetRect(rect); container = nsStretchMetrics(rect.x, rect.y, rect.width, rect.height); - } + } - aMathMLFrame->Stretch(aPresContext, aRenderingContext, mEmbellish.direction, - container, childSize); + aMathMLFrame->Stretch(aPresContext, aRenderingContext, + mEmbellishData.direction, container, childSize); childFrame->SetRect(aPresContext, nsRect(childSize.descent, childSize.ascent, childSize.width, childSize.height)); @@ -249,8 +252,8 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, nscoord em = NSToCoordRound(float(font.mFont.size)); // cache these values - mEmbellish.leftSpace = nscoord( em * aDesiredStretchSize.leftSpace ); - mEmbellish.rightSpace = nscoord( em * aDesiredStretchSize.rightSpace ); + mEmbellishData.leftSpace = nscoord( em * aDesiredStretchSize.leftSpace ); + mEmbellishData.rightSpace = nscoord( em * aDesiredStretchSize.rightSpace ); aDesiredStretchSize.width += nscoord( (aDesiredStretchSize.leftSpace + aDesiredStretchSize.rightSpace) * em ); nscoord dx = nscoord( aDesiredStretchSize.leftSpace * em ); @@ -291,7 +294,7 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, // We use the information in our children rectangles to position them. // If placeOrigin==false, then Place() will not touch rect.x, and rect.y. // They will still be holding the ascent and descent for each child. - PRBool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellish.flags); + PRBool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags); Place(aPresContext, aRenderingContext, placeOrigin, aDesiredSize); if (!placeOrigin) { @@ -299,14 +302,14 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, // Don't go without checking to see if our parent will later fire a Stretch() command // targeted at us. The Stretch() will cause the rect.x and rect.y to clear... PRBool parentWillFireStretch = PR_FALSE; - nsEmbellishState parentState; + nsEmbellishData parentData; nsIMathMLFrame* aMathMLFrame = nsnull; nsresult rv = mParent->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && aMathMLFrame) { - aMathMLFrame->GetEmbellishState(parentState); - if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(parentState.flags) || - (NS_MATHML_WILL_STRETCH_FIRST_CHILD(parentState.flags) && - parentState.firstChild == this)) { + aMathMLFrame->GetEmbellishData(parentData); + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(parentData.flags) || + (NS_MATHML_WILL_STRETCH_FIRST_CHILD(parentData.flags) && + parentData.firstChild == this)) { parentWillFireStretch = PR_TRUE; } } @@ -319,7 +322,7 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, // 1) With this code, vertical stretching works. But horizontal stretching // does not work when the firstChild happens to be the core embellished mo... // nsRect rect; -// nsIFrame* childFrame = mEmbellish.firstChild; +// nsIFrame* childFrame = mEmbellishData.firstChild; // NS_ASSERTION(childFrame, "Something is wrong somewhere"); // childFrame->GetRect(rect); // nsStretchMetrics curSize(rect.x, rect.y, rect.width, rect.height); @@ -351,6 +354,8 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + // Also return our bounding metrics + aDesiredSize.mBoundingMetrics = mBoundingMetrics; return NS_OK; } @@ -369,37 +374,37 @@ nsMathMLContainerFrame::EmbellishOperator() } if (firstChild && IsEmbellishOperator(firstChild)) { // Cache the first child - mEmbellish.flags |= NS_MATHML_EMBELLISH_OPERATOR; - mEmbellish.firstChild = firstChild; + mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR; + mEmbellishData.firstChild = firstChild; // Cache also the inner-most embellished frame at the core of the hierarchy nsIMathMLFrame* aMathMLFrame = nsnull; nsresult rv = firstChild->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); - nsEmbellishState embellishState; - aMathMLFrame->GetEmbellishState(embellishState); - mEmbellish.core = embellishState.core; - mEmbellish.direction = embellishState.direction; + nsEmbellishData embellishData; + aMathMLFrame->GetEmbellishData(embellishData); + mEmbellishData.core = embellishData.core; + mEmbellishData.direction = embellishData.direction; } else { - mEmbellish.flags &= ~NS_MATHML_EMBELLISH_OPERATOR; - mEmbellish.firstChild = nsnull; - mEmbellish.core = nsnull; - mEmbellish.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_OPERATOR; + mEmbellishData.firstChild = nsnull; + mEmbellishData.core = nsnull; + mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; } return NS_OK; } NS_IMETHODIMP -nsMathMLContainerFrame::GetEmbellishState(nsEmbellishState& aEmbellishState) +nsMathMLContainerFrame::GetEmbellishData(nsEmbellishData& aEmbellishData) { - aEmbellishState = mEmbellish; + aEmbellishData = mEmbellishData; return NS_OK; } NS_IMETHODIMP -nsMathMLContainerFrame::SetEmbellishState(const nsEmbellishState& aEmbellishState) +nsMathMLContainerFrame::SetEmbellishData(const nsEmbellishData& aEmbellishData) { - mEmbellish = aEmbellishState; + mEmbellishData = aEmbellishData; return NS_OK; } @@ -411,9 +416,9 @@ nsMathMLContainerFrame::IsEmbellishOperator(nsIFrame* aFrame) nsIMathMLFrame* aMathMLFrame = nsnull; nsresult rv = aFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); if (NS_FAILED(rv) || !aMathMLFrame) return PR_FALSE; - nsEmbellishState aEmbellishState; - aMathMLFrame->GetEmbellishState(aEmbellishState); - return NS_MATHML_IS_EMBELLISH_OPERATOR(aEmbellishState.flags); + nsEmbellishData aEmbellishData; + aMathMLFrame->GetEmbellishData(aEmbellishData); + return NS_MATHML_IS_EMBELLISH_OPERATOR(aEmbellishData.flags); } /* ///////////// @@ -451,7 +456,7 @@ nsMathMLContainerFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, while (nsnull != childFrame) { if (!IsOnlyWhitespace(childFrame)) { if (0 >= aIndex--) { - nsIMathMLFrame* aMathMLFrame = nsnull; + nsIMathMLFrame* aMathMLFrame = nsnull; nsresult rv = childFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && nsnull != aMathMLFrame) { // update @@ -522,7 +527,7 @@ nsMathMLContainerFrame::InsertScriptLevelStyleContext(nsIPresContext* aPresConte nsIFrame* newFrame = nsnull; NS_NewMathMLWrapperFrame(shell, &newFrame); NS_ASSERTION(newFrame, "Failed to create new frame"); - + if (!newFrame) break; newFrame->Init(aPresContext, childContent, lastFrame, newStyleContext, nsnull); if (nsnull == firstFrame) { @@ -547,15 +552,15 @@ nsMathMLContainerFrame::InsertScriptLevelStyleContext(nsIPresContext* aPresConte // if the child was an embellished operator, // make the whole list embellished as well - nsEmbellishState embellishState; - aMathMLFrame->GetEmbellishState(embellishState); - if (0 != embellishState.flags && nsnull != embellishState.firstChild) { + nsEmbellishData embellishData; + aMathMLFrame->GetEmbellishData(embellishData); + if (0 != embellishData.flags && nsnull != embellishData.firstChild) { do { // walk the hierarchy in a bottom-up manner rv= lastFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); if (NS_FAILED(rv) || !aMathMLFrame) break; - embellishState.firstChild = childFrame; - aMathMLFrame->SetEmbellishState(embellishState); + embellishData.firstChild = childFrame; + aMathMLFrame->SetEmbellishData(embellishData); childFrame = lastFrame; lastFrame->GetParent(&lastFrame); } while (lastFrame != this); @@ -591,10 +596,12 @@ nsMathMLContainerFrame::Init(nsIPresContext* aPresContext, mScriptLevel = 0; mDisplayStyle = PR_TRUE; + mCompressed = PR_FALSE; // for compatibility with TeX rendering + mScriptSpace = 0; // = 0.5 pt in plain TeX + + mEmbellishData.flags = 0; + mEmbellishData.firstChild = nsnull; - mEmbellish.flags = 0; - mEmbellish.firstChild = nsnull; - nsIMathMLFrame* aMathMLFrame = nsnull; nsresult res = aParent->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); if (NS_SUCCEEDED(res) && nsnull != aMathMLFrame) { @@ -688,9 +695,9 @@ nsMathMLContainerFrame::GetDesiredStretchSize(nsIPresContext* aPresContext, rv = childFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsEmbellishState embellishState; - aMathMLFrame->GetEmbellishState(embellishState); - embellishState.core->GetRect(rect); + nsEmbellishData embellishData; + aMathMLFrame->GetEmbellishData(embellishData); + embellishData.core->GetRect(rect); } } if (0 == aDirection) { // for horizontal positioning of child frames like in mrow @@ -712,7 +719,7 @@ nsMathMLContainerFrame::GetDesiredStretchSize(nsIPresContext* aPresContext, } aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - // Check if embellished operators didn't have (non-empty) sibblings... + // Check if embellished operators didn't have (non-empty) siblings... if (0 < count && 0 == aDirection && 0 == aDesiredSize.height) { // Return the font ascent and font descent nsCOMPtr fm; @@ -733,6 +740,116 @@ nsMathMLContainerFrame::GetDesiredStretchSize(nsIPresContext* aPresContext, } #endif + +// helper function to reflow token elements +// note that mBoundingMetrics is computed here +nsresult +nsMathMLContainerFrame::ReflowTokenFor(nsIFrame* aFrame, + nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + NS_PRECONDITION(aFrame, "null arg"); + nsresult rv = NS_OK; + + // ask our children to compute their bounding metrics + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); + nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); + nsBoundingMetrics bm; + PRInt32 count = 0; + nsIFrame* childFrame; + aFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + if (IsOnlyWhitespace(childFrame)) { + ReflowEmptyChild(aPresContext, childFrame); + } + else { + nsHTMLReflowState childReflowState(aPresContext, aReflowState, + childFrame, availSize); + rv = NS_STATIC_CAST(nsMathMLContainerFrame*, + aFrame)->ReflowChild(childFrame, + aPresContext, childDesiredSize, + childReflowState, aStatus); + NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); + if (NS_FAILED(rv)) return rv; + + // origins are used as placeholders to store the child's ascent and descent. + childFrame->SetRect(aPresContext, + nsRect(childDesiredSize.descent, childDesiredSize.ascent, + childDesiredSize.width, childDesiredSize.height)); + // compute and cache the bounding metrics + if (0 == count) + bm = childDesiredSize.mBoundingMetrics; + else + bm += childDesiredSize.mBoundingMetrics; + + count++; + } + rv = childFrame->GetNextSibling(&childFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } + NS_STATIC_CAST(nsMathMLContainerFrame*, aFrame)->SetBoundingMetrics(bm); + + // Place and size children + NS_STATIC_CAST(nsMathMLContainerFrame*, + aFrame)->FinalizeReflow(0, aPresContext, *aReflowState.rendContext, + aDesiredSize); + return NS_OK; +} + +// helper function to place token elements +// mBoundingMetrics is computed at the ReflowToken pass, it is +// not computed here because if our children may be text frames that +// do not implement the GetBoundingMetrics() interface. +nsresult +nsMathMLContainerFrame::PlaceTokenFor(nsIFrame* aFrame, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize) +{ + aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + + nsRect rect; + nsIFrame* childFrame; + aFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + if (!IsOnlyWhitespace(childFrame)) { + childFrame->GetRect(rect); + aDesiredSize.width += rect.width; + if (aDesiredSize.descent < rect.x) aDesiredSize.descent = rect.x; + if (aDesiredSize.ascent < rect.y) aDesiredSize.ascent = rect.y; + } + childFrame->GetNextSibling(&childFrame); + } + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + + if (aPlaceOrigin) { + nscoord dy; + nscoord dx = 0; + + aFrame->FirstChild(nsnull, &childFrame); + while (childFrame) { + childFrame->GetRect(rect); + + nsHTMLReflowMetrics childSize(nsnull); + childSize.width = rect.width; + childSize.height = rect.height; + + // Place and size the child + dy = aDesiredSize.ascent - rect.y; + NS_STATIC_CAST(nsMathMLContainerFrame*, + aFrame)->FinishReflowChild(childFrame, aPresContext, + childSize, dx, dy, 0); + dx += rect.width; + childFrame->GetNextSibling(&childFrame); + } + } + return NS_OK; +} + // helper function to reflow all children NS_IMETHODIMP nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, @@ -742,11 +859,15 @@ nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, nsReflowStatus& aStatus) { NS_PRECONDITION(aDirection==0 || aDirection==1, "Unknown direction"); + nsresult rv = NS_OK; nsReflowStatus childStatus; - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); + // Asks the child to cache its bounding metrics + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); + aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; nscoord count = 0; @@ -772,7 +893,7 @@ nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, nsRect(childDesiredSize.descent, childDesiredSize.ascent, childDesiredSize.width, childDesiredSize.height)); - if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(mEmbellish.flags) && + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(mEmbellishData.flags) && IsEmbellishOperator(childFrame)) { // We have encountered an embellished operator... // It is treated as if the embellishments were not there! @@ -781,10 +902,10 @@ nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsEmbellishState embellishState; - aMathMLFrame->GetEmbellishState(embellishState); + nsEmbellishData embellishData; + aMathMLFrame->GetEmbellishData(embellishData); nsRect rect; - embellishState.core->GetRect(rect); + embellishData.core->GetRect(rect); childDesiredSize.descent = rect.x; childDesiredSize.ascent = rect.y; childDesiredSize.width = rect.width; @@ -820,7 +941,7 @@ nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, } aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - // Check if embellished operators didn't have (non-empty) sibblings... + // Check if embellished operators didn't have (non-empty) siblings... if (0 < count && 0 == aDirection && 0 == aDesiredSize.height) { // Return the font ascent and font descent nsCOMPtr fm; @@ -851,7 +972,7 @@ nsMathMLContainerFrame::StretchChildren(nsIPresContext* aPresContext, nsRect rect; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - if (mEmbellish.firstChild == childFrame) { + if (mEmbellishData.firstChild == childFrame) { // Skip this child... because: // If we are here it means we are an embellished container and // for now, we don't touch our embellished child frame. @@ -886,6 +1007,8 @@ nsMathMLContainerFrame::Reflow(nsIPresContext* aPresContext, { nsresult rv = NS_OK; + ///////////// + // Reflow children ReflowChildren(0, aPresContext, aDesiredSize, aReflowState, aStatus); ///////////// @@ -894,7 +1017,7 @@ nsMathMLContainerFrame::Reflow(nsIPresContext* aPresContext, nsIRenderingContext& renderingContext = *aReflowState.rendContext; - if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(mEmbellish.flags)) { + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(mEmbellishData.flags)) { nsStretchMetrics containerSize(aDesiredSize); nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; @@ -917,19 +1040,35 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, { aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + PRInt32 count = 0; nsRect rect; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - childFrame->GetRect(rect); + if (!IsOnlyWhitespace(childFrame)) { + childFrame->GetRect(rect); - aDesiredSize.width += rect.width; - if (aDesiredSize.descent < rect.x) aDesiredSize.descent = rect.x; - if (aDesiredSize.ascent < rect.y) aDesiredSize.ascent = rect.y; + aDesiredSize.width += rect.width; + if (aDesiredSize.descent < rect.x) aDesiredSize.descent = rect.x; + if (aDesiredSize.ascent < rect.y) aDesiredSize.ascent = rect.y; + // Compute and cache our bounding metrics + nsBoundingMetrics bm; + if (NS_FAILED(GetBoundingMetricsFor(childFrame, bm))) { + bm.ascent = rect.y; + bm.descent = -rect.x; + bm.width = rect.width; + } + if (0 == count) + mBoundingMetrics = bm; + else + mBoundingMetrics += bm; + + count++; + } childFrame->GetNextSibling(&childFrame); } aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - + if (aPlaceOrigin) { nscoord dy; nscoord dx = 0; @@ -937,16 +1076,12 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, while (childFrame) { childFrame->GetRect(rect); - dy = aDesiredSize.ascent - rect.y; - nsHTMLReflowMetrics childSize(nsnull); childSize.width = rect.width; childSize.height = rect.height; - // childSize.descent = rect.x; - // childSize.ascent = rect.y; // Place and size the child - // childFrame->MoveTo(aPresContext, dx, dy); + dy = aDesiredSize.ascent - rect.y; FinishReflowChild(childFrame, aPresContext, childSize, dx, dy, 0); dx += rect.width; @@ -961,7 +1096,7 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, // *BEWARE* of the wrapper frame! // This is the frame that is inserted to alter the style context of // scripting elements. What this means is that looking for your parent -// or your sibblings with (possible several) wrapper frames around you +// or your siblings with (possible several) wrapper frames around you // can make you wonder what is going on. For example, the direct parent // of the subscript within is not , but instead the wrapper // frame that was insterted to alter the style context of the subscript! @@ -994,32 +1129,15 @@ nsMathMLWrapperFrame::~nsMathMLWrapperFrame() { } +// For Reflow() and Place(), pretend we are a token to re-use code NS_IMETHODIMP nsMathMLWrapperFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - nsresult rv = NS_OK; - aStatus = NS_FRAME_COMPLETE; - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - if (childFrame) { - nsReflowStatus childStatus; - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); - nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); - nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); - rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); - childFrame->SetRect(aPresContext, - nsRect(childDesiredSize.descent,childDesiredSize.ascent, - childDesiredSize.width,childDesiredSize.height)); - aDesiredSize = childDesiredSize; - aStatus = childStatus; - - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - FinalizeReflow(0, aPresContext, renderingContext, aDesiredSize); - } - return rv; + return ReflowTokenFor(this, aPresContext, aDesiredSize, + aReflowState, aStatus); } NS_IMETHODIMP @@ -1028,25 +1146,6 @@ nsMathMLWrapperFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - if (childFrame) { - nsRect rect; - childFrame->GetRect(rect); - - aDesiredSize.descent = rect.x; - aDesiredSize.ascent = rect.y; - aDesiredSize.width = rect.width; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - if (aPlaceOrigin) { - nsHTMLReflowMetrics childSize(nsnull); - childSize.width = rect.width; - childSize.height = rect.height; - - // childFrame->SetRect(aPresContext, nsRect(0,0,rect.width,rect.height)); - FinishReflowChild(childFrame, aPresContext, childSize, 0, 0, 0); - } - } - return NS_OK; + return PlaceTokenFor(this, aPresContext, aRenderingContext, + aPlaceOrigin, aDesiredSize); } diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h index c0257a75f12..3a2ca85765b 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ #ifndef nsMathMLContainerFrame_h___ @@ -75,13 +76,13 @@ public: NS_IMETHOD SetBoundingMetrics(const nsBoundingMetrics& aBoundingMetrics); -/* + NS_IMETHOD GetReference(nsPoint& aReference); NS_IMETHOD SetReference(const nsPoint& aReference); -*/ + NS_IMETHOD Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -104,10 +105,10 @@ public: EmbellishOperator(); NS_IMETHOD - GetEmbellishState(nsEmbellishState& aEmbellishState); + GetEmbellishData(nsEmbellishData& aEmbellishData); NS_IMETHOD - SetEmbellishState(const nsEmbellishState& aEmbellishState); + SetEmbellishData(const nsEmbellishData& aEmbellishData); NS_IMETHOD GetPresentationData(PRInt32* aScriptLevel, @@ -147,10 +148,26 @@ public: nsDidReflowStatus aStatus) { - mEmbellish.flags &= ~NS_MATHML_STRETCH_DONE; + mEmbellishData.flags &= ~NS_MATHML_STRETCH_DONE; return nsHTMLContainerFrame::DidReflow(aPresContext, aStatus); } + // helper function to reflow token elements + static nsresult + ReflowTokenFor(nsIFrame* aFrame, + nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + // helper function to palce token elements + static nsresult + PlaceTokenFor(nsIFrame* aFrame, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize); + // helper method to reflow a child frame. We are inline frames, and we don't // know our positions until reflow is finished. That's why we ask the // base method not to worry about our position. @@ -190,7 +207,7 @@ public: nsStretchDirection aStretchDirection, nsStretchMetrics& aContainerSize); - // helper method to complete the post-reflow hook and ensure that embellish + // helper method to complete the post-reflow hook and ensure that embellished // operators don't terminate their Reflow without receiving a Stretch command. NS_IMETHOD FinalizeReflow(PRInt32 aDirection, @@ -216,6 +233,107 @@ public: ReflowEmptyChild(nsIPresContext* aPresContext, nsIFrame* aFrame); + // helper methods to facilitate getting/setting the bounding metrics + static nsresult + GetBoundingMetricsFor(nsIFrame* aFrame, + nsBoundingMetrics& aBoundingMetrics) + { + aBoundingMetrics.Clear(); + nsIMathMLFrame* aMathMLFrame = nsnull; + nsresult rv = aFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + aMathMLFrame->GetBoundingMetrics(aBoundingMetrics); + return NS_OK; + } + // if we reach here, aFrame is not a MathML frame, let the caller know that + printf("GetBoundingMetrics() failed!! ...\n"); /* getchar(); */ + return NS_ERROR_FAILURE; + } + + static nsresult + SetBoundingMetricsFor(nsIFrame* aFrame, + nsBoundingMetrics& aBoundingMetrics) + { + nsIMathMLFrame* aMathMLFrame = nsnull; + nsresult rv = aFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + aMathMLFrame->SetBoundingMetrics(aBoundingMetrics); + return NS_OK; + } + // if we reach here, aFrame is not a MathML frame, let the caller know that + printf("SetBoundingMetrics() failed!! ...\n"); /* getchar(); */ + return NS_ERROR_FAILURE; + } + + // helper methods for getting sup/subdrop's from a child + static void + GetSubDropFromChild (nsIPresContext* aPresContext, + nsIFrame* aChild, + nscoord& aSubDrop) + { + const nsStyleFont *font; + aChild->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + nsCOMPtr fm; + aPresContext->GetMetricsFor(font->mFont, getter_AddRefs(fm)); + + GetSubDrop (fm, aSubDrop); + } + + static void + GetSupDropFromChild (nsIPresContext* aPresContext, + nsIFrame* aChild, + nscoord& aSupDrop) + { + const nsStyleFont *font; + aChild->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + nsCOMPtr fm; + aPresContext->GetMetricsFor(font->mFont, getter_AddRefs(fm)); + + GetSupDrop (fm, aSupDrop); + } + + // 2 levels of subscript shifts + static void + GetSubScriptShifts (nsIFontMetrics *fm, + nscoord& aSubScriptShift1, + nscoord& aSubScriptShift2) + { + // XXX for now an alias for GetSubscriptOffset + fm->GetSubscriptOffset (aSubScriptShift1); + aSubScriptShift2 = aSubScriptShift1 + = NSToCoordRound(0.5f * aSubScriptShift1); + } + + // 3 levels of superscript shifts + static void + GetSupScriptShifts (nsIFontMetrics *fm, + nscoord& aSupScriptShift1, + nscoord& aSupScriptShift2, + nscoord& aSupScriptShift3) + { + // XXX for now an alias for GetSupscriptOffset + fm->GetSuperscriptOffset (aSupScriptShift1); + aSupScriptShift2 = aSupScriptShift3 = aSupScriptShift1 + = NSToCoordRound(0.75f * aSupScriptShift1); + } + + // these are TeX specific params not found in ordinary fonts + static void + GetSubDrop (nsIFontMetrics *fm, nscoord& aSubDrop) + { + nscoord xHeight; + fm->GetXHeight (xHeight); + aSubDrop = NSToCoordRound(0.3f * xHeight); + } + + static void + GetSupDrop (nsIFontMetrics *fm, nscoord& aSupDrop) + { + nscoord xHeight; + fm->GetXHeight (xHeight); + aSupDrop = NSToCoordRound(0.3f * xHeight); + } + protected: PRInt32 mScriptLevel; // Relevant to nested frames within: msub, msup, msubsup, munder, @@ -223,13 +341,18 @@ protected: PRBool mDisplayStyle; // displaystyle="false" is intended to slightly alter how the // rendering is done in inline mode. + + PRBool mCompressed; // for compatibility with TeX rendering + // for internal use only, cannot be set by the user. + nscoord mScriptSpace; // scriptspace from TeX for extra spacing after sup/subscript + // = 0.5pt in plain TeX - nsEmbellishState mEmbellish; // information about a container that is an embellished operator + nsEmbellishData mEmbellishData; // information about a container that is an embellished operator nsBoundingMetrics mBoundingMetrics; // Metrics that _exactly_ enclose the text of the frame -/* - nsPoint mReference; // Reference point of the frame: mReference.x is the baseline -*/ + + nsPoint mReference; // Reference point of the frame: mReference.y is the baseline + virtual PRIntn GetSkipSides() const { return 0; } }; diff --git a/mozilla/layout/mathml/base/src/nsMathMLParts.h b/mozilla/layout/mathml/base/src/nsMathMLParts.h index ff220e80f84..35621c677b9 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLParts.h +++ b/mozilla/layout/mathml/base/src/nsMathMLParts.h @@ -28,6 +28,7 @@ // Factory methods for creating MathML objects extern nsresult NS_NewMathMLmrowFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmiFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); +extern nsresult NS_NewMathMLmnFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmoFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmphantomFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmpaddedFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); diff --git a/mozilla/layout/mathml/base/src/nsMathMLmfencedFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmfencedFrame.cpp index 5a1c5f2e9c0..e27f9e83f44 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmfencedFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmfencedFrame.cpp @@ -75,12 +75,13 @@ nsMathMLmfencedFrame::Init(nsIPresContext* aPresContext, nsIFrame* aPrevInFlow) { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - return rv; mOpenChar = nsnull; mCloseChar = nsnull; mSeparatorsChar = nsnull; mSeparatorsCount = 0; + + return rv; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmfracFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmfracFrame.cpp index f0c3ae6abcd..f795eb9f7ab 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmfracFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmfracFrame.cpp @@ -167,7 +167,9 @@ nsMathMLmfracFrame::Reflow(nsIPresContext* aPresContext, { nsresult rv = NS_OK; nsReflowStatus childStatus; - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); + // ask our children to compute their bounding metrics + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); ////////////////// @@ -253,6 +255,12 @@ nsMathMLmfracFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.maxElementSize->height = aDesiredSize.height; } aStatus = NS_FRAME_COMPLETE; + + // XXX Fix me! + mBoundingMetrics.ascent = aDesiredSize.ascent; + mBoundingMetrics.descent = -aDesiredSize.descent; + mBoundingMetrics.width = aDesiredSize.width; + return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp index bf3de0033c1..93356966e65 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp @@ -42,6 +42,7 @@ #include "nsITextContent.h" #include "nsMathMLmiFrame.h" +#include "nsMathMLTextFrame.h" // // -- identifier - implementation @@ -70,7 +71,6 @@ nsMathMLmiFrame::~nsMathMLmiFrame() { } - NS_IMETHODIMP nsMathMLmiFrame::Init(nsIPresContext* aPresContext, nsIContent* aContent, @@ -97,14 +97,13 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext* aPresContext, // First, let the base class do its work rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - // Get the length of the text content that we enclose // our content can include comment-nodes, attribute-nodes, text-nodes... // we use the DOM to make sure that we are only looking at text-nodes... PRInt32 aLength = 0; PRInt32 numKids; mContent->ChildCount(numKids); - // nsAutoString aData; + nsAutoString aData; for (PRInt32 kid=0; kid kidContent; mContent->ChildAt(kid, *getter_AddRefs(kidContent)); @@ -114,9 +113,9 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext* aPresContext, PRUint32 kidLength; kidText->GetLength(&kidLength); aLength += kidLength; - // nsAutoString kidData; - // kidText->GetData(kidData); - // aData += kidData; + nsAutoString kidData; + kidText->GetData(kidData); + aData += kidData; } } } @@ -143,21 +142,40 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIFrame* newFrame = nsnull; NS_NewMathMLWrapperFrame(shell, &newFrame); NS_ASSERTION(newFrame, "Failed to create new frame"); - - newFrame->Init(aPresContext, mContent, this, newStyleContext, nsnull); - - // our children become children of the new frame - nsIFrame* childFrame = firstChild; - while (childFrame) { - childFrame->SetParent(newFrame); - aPresContext->ReParentStyleContext(childFrame, newStyleContext); - childFrame->GetNextSibling(&childFrame); + if (newFrame) { + newFrame->Init(aPresContext, mContent, this, newStyleContext, nsnull); + // our children become children of the new frame + nsIFrame* childFrame = firstChild; + while (childFrame) { + childFrame->SetParent(newFrame); + aPresContext->ReParentStyleContext(childFrame, newStyleContext); + childFrame->GetNextSibling(&childFrame); + } + newFrame->SetInitialChildList(aPresContext, nsnull, firstChild); + // the new frame becomes our sole child + mFrames.SetFrames(newFrame); } - newFrame->SetInitialChildList(aPresContext, nsnull, firstChild); - - // the new frame becomes our sole child - mFrames.SetFrames(newFrame); } } return rv; } + +NS_IMETHODIMP +nsMathMLmiFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + return ReflowTokenFor(this, aPresContext, aDesiredSize, + aReflowState, aStatus); +} + +NS_IMETHODIMP +nsMathMLmiFrame::Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize) +{ + return PlaceTokenFor(this, aPresContext, aRenderingContext, + aPlaceOrigin, aDesiredSize); +} diff --git a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.h index 8f1536066d0..c172df79e52 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.h @@ -45,6 +45,19 @@ public: SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, nsIFrame* aChildList); + + NS_IMETHOD + Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD + Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize); + protected: nsMathMLmiFrame(); virtual ~nsMathMLmiFrame(); diff --git a/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp index c57866ab5fb..65e6a480cfd 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ @@ -66,147 +67,361 @@ nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame() { } +NS_IMETHODIMP +nsMathMLmmultiscriptsFrame::Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init + (aPresContext, aContent, aParent, aContext, aPrevInFlow); + + mSubScriptShiftFactor = 0.0f; + mSupScriptShiftFactor = 0.0f; + mScriptSpace = NSFloatPointsToTwips(0.5f); // 0.5pt as in plain TeX + + // check for subscriptshift and superscriptshift attribute in ex units + nsAutoString value; + mSubUserSetFlag = mSupUserSetFlag = PR_FALSE; + mSubScriptShiftFactor = mSubScriptShiftFactor = 0.0f; + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::subscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mSubUserSetFlag = PR_TRUE; + mSubScriptShiftFactor = aUserValue; + } + } + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::superscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mSupUserSetFlag = PR_TRUE; + mSupScriptShiftFactor = aUserValue; + } + } + + return rv; +} + NS_IMETHODIMP nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nsresult rv; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + nscoord italicCorrection = 0; + nscoord minShiftFromXHeight, aSubDrop, aSupDrop; + + //////////////////////////////////////// + // Initialize super/sub shifts that + // depend only on the current font + //////////////////////////////////////// + + // get x-height (an ex) + nscoord xHeight = 0; + nsCOMPtr fm; + const nsStyleFont* aFont = + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); + fm->GetXHeight (xHeight); + + nscoord aRuleSize, dummy; + // XXX need to do update this ... + fm->GetStrikeout (dummy, aRuleSize); + + ///////////////////////////////////// + // first the shift for the subscript + + // aSubScriptShift{1,2} + // = minimum amount to shift the subscript down + // = sub{1,2} in TeXbook + // aSubScriptShift1 = subscriptshift attribute * x-height + nscoord aSubScriptShift1, aSubScriptShift2; + + // Get aSubScriptShift{1,2} default from font + GetSubScriptShifts (fm, aSubScriptShift1, aSubScriptShift2); + if (mSubUserSetFlag) { + // the user has set the subscriptshift attribute + float aFactor = ((float) aSubScriptShift2) / aSubScriptShift1; + aSubScriptShift1 = NSToCoordRound(mSubScriptShiftFactor * xHeight); + aSubScriptShift2 = NSToCoordRound(aFactor * aSubScriptShift1); + } + // the font dependent shift + nscoord aSubScriptShift = PR_MAX(aSubScriptShift1,aSubScriptShift2); + + ///////////////////////////////////// + // next the shift for the superscript + + // aSupScriptShift{1,2,3} + // = minimum amount to shift the supscript up + // = sup{1,2,3} in TeX + // aSupScriptShift1 = superscriptshift attribute * x-height + // Note that there are THREE values for supscript shifts depending + // on the current style + nscoord aSupScriptShift1, aSupScriptShift2, aSupScriptShift3; + // Set aSupScriptShift{1,2,3} default from font + GetSupScriptShifts (fm, aSupScriptShift1, aSupScriptShift2, aSupScriptShift3); + if (mSupUserSetFlag) { + // the user has set the superscriptshift attribute + float aFactor2 = ((float) aSupScriptShift2) / aSupScriptShift1; + float aFactor3 = ((float) aSupScriptShift3) / aSupScriptShift1; + aSupScriptShift1 = NSToCoordRound(mSupScriptShiftFactor * xHeight); + aSupScriptShift2 = NSToCoordRound(aFactor2 * aSupScriptShift1); + aSupScriptShift3 = NSToCoordRound(aFactor3 * aSupScriptShift1); + } + + // get sup script shift depending on current script level and display style + // Rule 18c, App. G, TeXbook + nscoord aSupScriptShift; + if (mScriptLevel == 0 && mDisplayStyle && !mCompressed) { + // Style D in TeXbook + aSupScriptShift = aSupScriptShift1; + } + else if (mCompressed) { + // Style C' in TeXbook = D',T',S',SS' + aSupScriptShift = aSupScriptShift3; + } + else { + // everything else = T,S,SS + aSupScriptShift = aSupScriptShift2; + } + + //////////////////////////////////// + // Get the children's sizes + //////////////////////////////////// + + nscoord width = 0; nsIFrame* mprescriptsFrame = nsnull; // frame of , if there. - PRBool isSubscript = PR_FALSE; - nscoord ascent, descent, width, height; - nscoord subsupWidth, subHeight, supHeight, subDescent, supAscent; - nscoord count = 0; + PRBool isSubScript = PR_FALSE; + PRBool isSubScriptPresent = PR_TRUE; + PRBool isSupScriptPresent = PR_TRUE; + nscoord minSubScriptShift = 0, minSupScriptShift = 0; + nscoord trySubScriptShift = aSubScriptShift; + nscoord trySupScriptShift = aSupScriptShift; + nscoord maxSubScriptShift = aSubScriptShift; + nscoord maxSupScriptShift = aSupScriptShift; + PRInt32 count = 0; + nsRect aRect; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics subScriptSize (nsnull); + nsHTMLReflowMetrics supScriptSize (nsnull); + nsIFrame* baseFrame; + nsIFrame* subScriptFrame; + nsIFrame* supScriptFrame; - nsIFrame* baseFrame = nsnull; - nsIFrame* childFrame = mFrames.FirstChild(); - nsRect childRect; - while (childFrame) { - if (!IsOnlyWhitespace(childFrame)) { + // XXX is there an NSPR macro for int_max ??? + aDesiredSize.ascent = aDesiredSize.descent = -100000; + aDesiredSize.width = aDesiredSize.height = 0; + nsIFrame* aChildFrame = mFrames.FirstChild(); + while (nsnull != aChildFrame) + { + if (!IsOnlyWhitespace (aChildFrame)) { nsCOMPtr childContent; nsCOMPtr childTag; - childFrame->GetContent(getter_AddRefs(childContent)); + aChildFrame->GetContent(getter_AddRefs(childContent)); childContent->GetTag(*getter_AddRefs(childTag)); if (childTag.get() == nsMathMLAtoms::mprescripts_) { - mprescriptsFrame = childFrame; + mprescriptsFrame = aChildFrame; } - else if (childTag.get() != nsMathMLAtoms::none_) { - childFrame->GetRect(childRect); + else { + if (childTag.get() == nsMathMLAtoms::none_) { + // we need to record the presence of none tag explicitly + // for correct negotiation between sup/sub shifts later + if (isSubScript) { + isSubScriptPresent = PR_FALSE; + } + else { + isSupScriptPresent = PR_FALSE; + } + aRect = nsRect (0, 0, 0, 0); + } + else { + aChildFrame->GetRect(aRect); + } if (0 == count) { - baseFrame = childFrame; - descent = childRect.x; - ascent = childRect.y; - height = childRect.height; - subsupWidth = childRect.width; - subHeight = supHeight = height; - supAscent = ascent; - subDescent = descent; - } + // base + baseFrame = aChildFrame; + baseSize.descent = aRect.x; baseSize.ascent = aRect.y; + baseSize.width = aRect.width; + baseSize.height = aRect.height; + // we update aDesiredSize.{ascent,descent} with that + // of the baseFrame only after processing all the sup/sub pairs + // XXX need italic correction here + aDesiredSize.width = aRect.width + italicCorrection; + } else { - if (isSubscript) { - subDescent = PR_MAX(subDescent, childRect.x); - subHeight = PR_MAX(subHeight, childRect.height); - width = childRect.width; - } - else { - supAscent = PR_MAX(supAscent, childRect.y); - supHeight = PR_MAX(supHeight, childRect.height); - width = PR_MAX(width, childRect.width); - subsupWidth += width; + // super/subscript block + if (isSubScript) { + if (isSubScriptPresent) { + // subscript + subScriptFrame = aChildFrame; + subScriptSize.descent = aRect.x; + subScriptSize.ascent = aRect.y; + subScriptSize.width = aRect.width; + subScriptSize.height = aRect.height; + // get the subdrop from the subscript font + GetSubDropFromChild (aPresContext, subScriptFrame, aSubDrop); + // parameter v, Rule 18a, App. G, TeXbook + minSubScriptShift = baseSize.descent + aSubDrop; + trySubScriptShift = PR_MAX(minSubScriptShift,aSubScriptShift); + aDesiredSize.descent = + PR_MAX(aDesiredSize.descent,subScriptSize.descent); + width = subScriptSize.width + mScriptSpace; + } + } + else { + if (isSupScriptPresent) { + // supscript + supScriptFrame = aChildFrame; + supScriptSize.descent = aRect.x; + supScriptSize.ascent = aRect.y; + supScriptSize.width = aRect.width; + supScriptSize.height = aRect.height; + // get the supdrop from the supscript font + GetSupDropFromChild (aPresContext, supScriptFrame, aSupDrop); + // parameter u, Rule 18a, App. G, TeXbook + minSupScriptShift = baseSize.ascent - aSupDrop; + // get min supscript shift limit from x-height + // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook + minShiftFromXHeight = NSToCoordRound + ((supScriptSize.descent + (1.0f/4.0f) * xHeight)); + trySupScriptShift = + PR_MAX(minSupScriptShift,PR_MAX(minShiftFromXHeight,aSupScriptShift)); + aDesiredSize.ascent = + PR_MAX(aDesiredSize.ascent,supScriptSize.ascent); + width = PR_MAX(width, supScriptSize.width + mScriptSpace); + } + + NS_ASSERTION((isSubScriptPresent || isSupScriptPresent),"mmultiscripts : both sup/subscripts are absent"); + aDesiredSize.width += width; + width = 0; + + if (isSubScriptPresent && isSupScriptPresent) { + // negotiate between the various shifts so that + // there is enough gap between the sup and subscripts + // Rule 18e, App. G, TeXbook + nscoord gap = + (trySupScriptShift - supScriptSize.descent) - + (subScriptSize.ascent - trySubScriptShift); + if (gap < 4.0f * aRuleSize) { + // adjust trySubScriptShift to get a gap of (4.0 * aRuleSize) + trySubScriptShift += NSToCoordRound ((4.0f * aRuleSize) - gap); + } + + // next we want to ensure that the bottom of the superscript + // will be > (4/5) * x-height above baseline + gap = NSToCoordRound ((4.0f/5.0f) * xHeight - + (trySupScriptShift - supScriptSize.descent)); + if (gap > 0.0f) { + trySupScriptShift += gap; + trySubScriptShift -= gap; + } + } + maxSubScriptShift = PR_MAX(maxSubScriptShift, trySubScriptShift); + maxSupScriptShift = PR_MAX(maxSupScriptShift, trySupScriptShift); + + trySubScriptShift = aSubScriptShift; + trySupScriptShift = aSupScriptShift; + isSubScriptPresent = PR_TRUE; + isSupScriptPresent = PR_TRUE; } } - isSubscript = !isSubscript; + isSubScript = !isSubScript; count++; } } - rv = childFrame->GetNextSibling(&childFrame); + + rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } + // we left out base during our bounding box updates, so ... + aDesiredSize.ascent = + PR_MAX(aDesiredSize.ascent+maxSupScriptShift,baseSize.ascent); + aDesiredSize.descent = + PR_MAX(aDesiredSize.descent+maxSubScriptShift,baseSize.descent); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + + ////////////////// + // Place Children - // Get the subscript and superscript offsets - nscoord subscriptOffset, superscriptOffset, leading; - nsCOMPtr fm; - const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetSubscriptOffset(subscriptOffset); - fm->GetSuperscriptOffset(superscriptOffset); - fm->GetLeading(leading); + // Place prescripts, followed by base, and then postscripts. + // The list of frames is in the order: {base} {postscripts} {prescripts} + // We go over the list in a circular manner, starting at - subHeight = PR_MAX(height, subHeight) + subscriptOffset + leading; - supHeight = PR_MAX(height, supHeight) + superscriptOffset; - - aDesiredSize.descent = subHeight - ascent; - aDesiredSize.ascent = supHeight - descent; - aDesiredSize.height = aDesiredSize.descent + aDesiredSize.ascent; - aDesiredSize.width = subsupWidth; - - nscoord offset = 0; - nsIFrame* child[2]; - nsRect rect[2]; + if (aPlaceOrigin) { + nscoord dx = 0, dy = 0; - count = 0; - nsHTMLReflowMetrics childSize(nsnull); - childFrame = mprescriptsFrame; - do { - if (nsnull == childFrame) { // end of prescripts, -//printf("Placing the base ...\n"); - childFrame = baseFrame; // place the base - childFrame->GetRect(rect[0]); - rect[0].x = offset; - rect[0].y = aDesiredSize.height - subHeight; - if (aPlaceOrigin) { - // childFrame->SetRect(aPresContext, rect[0]); - childSize.width = rect[0].width; - childSize.height = rect[0].height; - FinishReflowChild(child[0], aPresContext, childSize, rect[0].x, rect[0].y, 0); + count = 0; + aChildFrame = mprescriptsFrame; + do { + if (nsnull == aChildFrame) { // end of prescripts, + // place the base ... + aChildFrame = baseFrame; + dy = aDesiredSize.ascent - baseSize.ascent; + FinishReflowChild (baseFrame, aPresContext, baseSize, dx, dy, 0); + dx += baseSize.width + italicCorrection; } - offset += rect[0].width; - } - else if (mprescriptsFrame != childFrame) { - ////////////// - // WHITESPACE: whitespace doesn't count. Iteration over non empty frames - if (!IsOnlyWhitespace(childFrame)) { - child[count++] = childFrame; - if (2 == count) { // place a sub-sup pair -//printf("Placing the sub-sup pair...\n"); + else if (mprescriptsFrame != aChildFrame) { + // process each sup/sub pair + if (!IsOnlyWhitespace (aChildFrame)) { + if (0 == count) { + subScriptFrame = aChildFrame; + count++; + } + else if (1 == count) { + supScriptFrame = aChildFrame; + count = 0; + + // get the bounding boxes of sup/subscripts stored in their rects + // rect.x = descent, rect.y = ascent + subScriptFrame->GetRect (aRect); + subScriptSize.ascent = aRect.y; + subScriptSize.width = aRect.width; + subScriptSize.height = aRect.height; - child[0]->GetRect(rect[0]); - child[1]->GetRect(rect[1]); - rect[0].y = aDesiredSize.height - (subDescent + rect[0].y); - rect[1].y = supAscent - rect[1].y; + supScriptFrame->GetRect (aRect); + supScriptSize.ascent = aRect.y; + supScriptSize.width = aRect.width; + supScriptSize.height = aRect.height; - width = PR_MAX(rect[0].width, rect[1].width); - rect[0].x = offset + (width - rect[0].width) / 2; // centering - rect[1].x = offset + (width - rect[1].width) / 2; + // XXX should we really center the boxes + // XXX i'm leaving it as left-justified + // XXX which is consistent with what's done for + dy = aDesiredSize.ascent - + subScriptSize.ascent + + maxSubScriptShift; + FinishReflowChild (subScriptFrame, aPresContext, + subScriptSize, dx, dy, 0); - if (aPlaceOrigin) { - // child[0]->SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; iGetNextSibling(&childFrame); - NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); - } while (mprescriptsFrame != childFrame); - - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; - } + + rv = aChildFrame->GetNextSibling(&aChildFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } while (mprescriptsFrame != aChildFrame); + } + return rv; } - diff --git a/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h index 552fa0ff934..fe0c6c788b9 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ #ifndef nsMathMLmmultiscriptsFrame_h___ @@ -34,6 +35,13 @@ class nsMathMLmmultiscriptsFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -60,6 +68,11 @@ protected: virtual ~nsMathMLmmultiscriptsFrame(); virtual PRIntn GetSkipSides() const { return 0; } + + private: + float mSubScriptShiftFactor, mSupScriptShiftFactor; + PRBool mSubUserSetFlag, mSupUserSetFlag; + }; #endif /* nsMathMLmmultiscriptsFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp index 27bd300864a..fca27ba3200 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp @@ -184,10 +184,10 @@ nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, nsIFrame* firstChild = mFrames.FirstChild(); while (firstChild) { if (!IsOnlyWhitespace(firstChild)) { - mEmbellish.flags = NS_MATHML_EMBELLISH_OPERATOR; - mEmbellish.firstChild = firstChild; - mEmbellish.core = this; - mEmbellish.direction = mMathMLChar.GetStretchDirection(); + mEmbellishData.flags = NS_MATHML_EMBELLISH_OPERATOR; + mEmbellishData.firstChild = firstChild; + mEmbellishData.core = this; + mEmbellishData.direction = mMathMLChar.GetStretchDirection(); break; } firstChild->GetNextSibling(&firstChild); @@ -219,22 +219,22 @@ nsMathMLmoFrame::InitData() else { // Get our outermost embellished container and its parent nsIFrame* aParent = this; - nsIFrame* aEmbellish = this; + nsIFrame* aEmbellishAncestor = this; do { - aEmbellish = aParent; + aEmbellishAncestor = aParent; aParent->GetParent(&aParent); } while (IsEmbellishOperator(aParent)); // flag if we have an embellished ancestor - if (aEmbellish != this) { + if (aEmbellishAncestor != this) { hasEmbellishAncestor = PR_TRUE; } // Find the position of our outermost embellished container w.r.t - // its sibblings (frames are singly-linked together). + // its siblings (frames are singly-linked together). ////////////// // WHITESPACE: don't forget that whitespace doesn't count in MathML! // Here is the situation: we may have empty frames between us: - // [space*] [prev] [space*] [aEmbellish] [space*] [next] + // [space*] [prev] [space*] [aEmbellishAncestor] [space*] [next] // We want to skip them... // The problem looks like a regexp, we ask a little flag to help us. PRInt32 state = 0; @@ -244,7 +244,7 @@ nsMathMLmoFrame::InitData() aParent->FirstChild(nsnull, &aFrame); while (aFrame) { - if (aFrame == aEmbellish) { // we start looking for next + if (aFrame == aEmbellishAncestor) { // we start looking for next state++; } else if (!IsOnlyWhitespace(aFrame)) { @@ -272,8 +272,8 @@ nsMathMLmoFrame::InitData() PRBool found = nsMathMLOperators::LookupOperator(aData, aForm, &mFlags, &mLeftSpace, &mRightSpace); - // All operators are symmetric. But this symmetric flag is *not* stored in the - // operator dictionary and operaptors are treated as non-symmetric... + // All operators are symmetric. But this symmetric flag is *not* stored in + // the operator dictionary and operators are treated as non-symmetric... // Uncomment the folllowing line to change this behavior. // mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; @@ -359,11 +359,11 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, nsStretchMetrics& aContainerSize, nsStretchMetrics& aDesiredStretchSize) { - if (NS_MATHML_STRETCH_WAS_DONE(mEmbellish.flags)) { + if (NS_MATHML_STRETCH_WAS_DONE(mEmbellishData.flags)) { printf("WARNING *** it is wrong to fire stretch more than once on a frame...\n"); return NS_OK; } - mEmbellish.flags |= NS_MATHML_STRETCH_DONE; + mEmbellishData.flags |= NS_MATHML_STRETCH_DONE; // if (0 == mFlags) { // first time... InitData(); @@ -396,6 +396,10 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, if (old == aDesiredStretchSize) { // hasn't changed ! mFlags &= ~NS_MATHML_OPERATOR_MUTABLE; } + else { + // update our bounding metrics... it becomes that our MathML char + mMathMLChar.GetBoundingMetrics(mBoundingMetrics); + } } ///////// @@ -405,7 +409,7 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, // The rendering will be handled by our MathML char mMathMLChar.SetRect(nsRect(0, 0, aDesiredStretchSize.width, aDesiredStretchSize.height)); - } + } else { nsHTMLReflowMetrics aReflowMetrics(nsnull); Place(aPresContext, aRenderingContext, PR_TRUE, aReflowMetrics); @@ -453,3 +457,22 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, return NS_OK; } +NS_IMETHODIMP +nsMathMLmoFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + return ReflowTokenFor(this, aPresContext, aDesiredSize, + aReflowState, aStatus); +} + +NS_IMETHODIMP +nsMathMLmoFrame::Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize) +{ + return PlaceTokenFor(this, aPresContext, aRenderingContext, + aPlaceOrigin, aDesiredSize); +} diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h index a53fe6d1eda..df058c90927 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h @@ -52,6 +52,18 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); + NS_IMETHOD + Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD + Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize); + // This method is called by the parent frame to ask // to stretch itself. NS_IMETHOD diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp index 5466fd58c3c..ebfaf774419 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp @@ -75,7 +75,7 @@ nsMathMLmoverFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellish.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; return rv; } @@ -136,10 +136,10 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); if (NS_SUCCEEDED(rv) && aMathMLFrame) { nsRect rect; - nsEmbellishState embellishState; - aMathMLFrame->GetEmbellishState(embellishState); - embellishState.core->GetRect(rect); - width[count] = rect.width + embellishState.leftSpace + embellishState.rightSpace; + nsEmbellishData embellishData; + aMathMLFrame->GetEmbellishData(embellishData); + embellishData.core->GetRect(rect); + width[count] = rect.width + embellishData.leftSpace + embellishData.rightSpace; } } maxWidth = PR_MAX(maxWidth, width[count]); // clean up and use "if" later @@ -190,5 +190,10 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext, aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + + // XXX Fix me! + mBoundingMetrics.ascent = aDesiredSize.ascent; + mBoundingMetrics.descent = -aDesiredSize.descent; + mBoundingMetrics.width = aDesiredSize.width; return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmrootFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmrootFrame.cpp index c1e4fb6fc94..12a9fc0a3ce 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmrootFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmrootFrame.cpp @@ -63,8 +63,8 @@ nsMathMLmrootFrame::nsMathMLmrootFrame() : mSqrChar(), mBarChar() { - mSqrChar.SetEnum(eMathMLChar_Radical); - mBarChar.SetEnum(eMathMLChar_RadicalBar); + mSqrChar.SetEnum(eMathMLChar_Sqrt); + mBarChar.SetEnum(eMathMLChar_OverBar); } nsMathMLmrootFrame::~nsMathMLmrootFrame() @@ -113,7 +113,9 @@ nsMathMLmrootFrame::Reflow(nsIPresContext* aPresContext, { nsresult rv = NS_OK; nsReflowStatus childStatus; - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); + // ask our children to compute their bounding metrics + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); ////////////////// @@ -264,5 +266,11 @@ nsMathMLmrootFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.maxElementSize->height = aDesiredSize.height; } aStatus = NS_FRAME_COMPLETE; + + // XXX Fix me! + mBoundingMetrics.ascent = aDesiredSize.ascent; + mBoundingMetrics.descent = -aDesiredSize.descent; + mBoundingMetrics.width = aDesiredSize.width; + return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmrowFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmrowFrame.cpp index e4ef67df9c3..e913dcc45e3 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmrowFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmrowFrame.cpp @@ -75,7 +75,7 @@ nsMathMLmrowFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellish.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; // XXX Attributes? return rv; diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp index 439d275bfb4..35b21430bff 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp @@ -63,8 +63,8 @@ nsMathMLmsqrtFrame::nsMathMLmsqrtFrame() : mSqrChar(), mBarChar() { - mSqrChar.SetEnum(eMathMLChar_Radical); - mBarChar.SetEnum(eMathMLChar_RadicalBar); + mSqrChar.SetEnum(eMathMLChar_Sqrt); + mBarChar.SetEnum(eMathMLChar_OverBar); } nsMathMLmsqrtFrame::~nsMathMLmsqrtFrame() @@ -82,7 +82,7 @@ nsMathMLmsqrtFrame::Init(nsIPresContext* aPresContext, rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellish.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; // TODO: other attributes... return rv; diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsubFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmsubFrame.cpp index d441da5849e..303a57df177 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsubFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmsubFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ @@ -66,68 +67,171 @@ nsMathMLmsubFrame::~nsMathMLmsubFrame() { } +NS_IMETHODIMP +nsMathMLmsubFrame::Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init + (aPresContext, aContent, aParent, aContext, aPrevInFlow); + + mSubScriptShiftFactor = 0.0; + mScriptSpace = NSFloatPointsToTwips(0.5f); // 0.5pt as in plain TeX + + // check for subscriptshift attribute in ex units + nsAutoString value; + mUserSetFlag = PR_FALSE; + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::subscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mUserSetFlag = PR_TRUE; + mSubScriptShiftFactor = aUserValue; + } + } + + return rv; +} + NS_IMETHODIMP nsMathMLmsubFrame::Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nscoord count = 0; - nsRect rect[2]; - nsIFrame* child[2]; - nsIFrame* childFrame = mFrames.FirstChild(); - while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 2 > count) { - childFrame->GetRect(rect[count]); - child[count] = childFrame; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsRect aRect; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics subScriptSize (nsnull); + nsIFrame* baseFrame; + nsIFrame* subScriptFrame; + // parameter v, Rule 18a, Appendix G of the TeXbook + nscoord minSubScriptShift = 0; + + nsBoundingMetrics baseBounds, subScriptBounds; + + nsIFrame* aChildFrame = mFrames.FirstChild(); + while (nsnull != aChildFrame) + { + if (!IsOnlyWhitespace(aChildFrame)) { + aChildFrame->GetRect(aRect); + if (0 == count) { + // base + baseFrame = aChildFrame; + baseSize.descent = aRect.x; baseSize.ascent = aRect.y; + baseSize.width = aRect.width; baseSize.height = aRect.height; + if (NS_SUCCEEDED(GetBoundingMetricsFor(baseFrame, baseBounds))) { + baseBounds.descent = -baseBounds.descent; + } else { + baseBounds.descent = baseSize.descent; + baseBounds.ascent = baseSize.ascent; + baseBounds.width = baseSize.width; + } + } + else if (1 == count) { + // subscript + subScriptFrame = aChildFrame; + subScriptSize.descent = aRect.x; subScriptSize.ascent = aRect.y; + subScriptSize.width = aRect.width; subScriptSize.height = aRect.height; + if (NS_SUCCEEDED(GetBoundingMetricsFor(subScriptFrame, subScriptBounds))) { + subScriptBounds.descent = -subScriptBounds.descent; + } else { + subScriptBounds.descent = subScriptSize.descent; + subScriptBounds.ascent = subScriptSize.ascent; + subScriptBounds.width = subScriptSize.width; + } + // get the subdrop from the subscript font + nscoord aSubDrop; + GetSubDropFromChild (aPresContext, subScriptFrame, aSubDrop); + // parameter v, Rule 18a, App. G, TeXbook + minSubScriptShift = baseSize.descent + aSubDrop; + } + else { + NS_ASSERTION((count < 2),"nsMathMLmsubFrame : invalid markup"); + } count++; } - childFrame->GetNextSibling(&childFrame); + + rv = aChildFrame->GetNextSibling(&aChildFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - aDesiredSize.ascent = rect[0].y; - // Get the subscript offset - nscoord subscriptOffset, leading; + ////////////////// + // Place Children + + // get min subscript shift limit from x-height + // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook + nscoord xHeight = 0; nsCOMPtr fm; const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetSubscriptOffset(subscriptOffset); - fm->GetLeading(leading); + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); + fm->GetXHeight (xHeight); + nscoord minShiftFromXHeight = (nscoord) + (subScriptSize.ascent - (4.0f/5.0f) * xHeight); -// XXX temporary hack pending bug http://bugzilla.mozilla.org/show_bug.cgi?id=9640 -//#if 0 -nscoord fmAscent, xHeight; -fm->GetMaxAscent(fmAscent); -fm->GetXHeight(xHeight); -subscriptOffset = PR_MAX(subscriptOffset,fmAscent-(xHeight*4)/5); -//#endif + // aSubScriptShift + // = minimum amount to shift the subscript down set by user or from the font + // = sub1 in TeX + // = subscriptshift attribute * x-height + nscoord aSubScriptShift, dummy; + // get aSubScriptShift default from font + GetSubScriptShifts (fm, aSubScriptShift, dummy); + if (mUserSetFlag == PR_TRUE) { + // the user has set the subscriptshift attribute + aSubScriptShift = NSToCoordRound(mSubScriptShiftFactor * xHeight); + } -//for (int i=0; i<100; i++) { -//printf("Ascent:%d xHeight:%d subscriptOffset:%d leading: %d ", -//fmAscent, xHeight, subscriptOffset, leading); -//} + // get actual subscriptshift to be used + // Rule 18b, App. G, TeXbook + nscoord actualSubScriptShift = + PR_MAX(minSubScriptShift,PR_MAX(aSubScriptShift,minShiftFromXHeight)); +#if 0 + // get bounding box for base + subscript + aDesiredSize.ascent = + PR_MAX(baseSize.ascent,(subScriptSize.ascent-actualSubScriptShift)); + aDesiredSize.descent = + PR_MAX(baseSize.descent,(actualSubScriptShift+subScriptSize.descent)); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + // add mScriptSpace between base and subscript + aDesiredSize.width = baseSize.width + mScriptSpace + subScriptSize.width; +#endif - subscriptOffset += leading; + mBoundingMetrics.ascent = + PR_MAX(baseBounds.ascent, subScriptBounds.ascent - actualSubScriptShift); + mBoundingMetrics.descent = + PR_MAX(baseBounds.descent, subScriptBounds.descent + actualSubScriptShift); + // add mScriptSpace between base and supscript + mBoundingMetrics.width = baseBounds.width + mScriptSpace + subScriptBounds.width; - // logic derived after examining the boxes on three cases: h0==h1, h0>h1, h0

SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; i * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ #ifndef nsMathMLmsubFrame_h___ @@ -34,6 +35,13 @@ class nsMathMLmsubFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -55,11 +63,15 @@ public: return rv; } -protected: + protected: nsMathMLmsubFrame(); virtual ~nsMathMLmsubFrame(); virtual PRIntn GetSkipSides() const { return 0; } + + private: + float mSubScriptShiftFactor; + PRBool mUserSetFlag; }; #endif /* nsMathMLmsubFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp index 7132cb34cad..ce45e557eee 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ @@ -66,84 +67,259 @@ nsMathMLmsubsupFrame::~nsMathMLmsubsupFrame() { } +NS_IMETHODIMP +nsMathMLmsubsupFrame::Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init + (aPresContext, aContent, aParent, aContext, aPrevInFlow); + + mSubScriptShiftFactor = 0.0f; + mSupScriptShiftFactor = 0.0f; + mScriptSpace = 0; + + // check for subscriptshift and superscriptshift attribute in ex units + nsAutoString value; + mSubUserSetFlag = mSupUserSetFlag = PR_FALSE; + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::subscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mSubUserSetFlag = PR_TRUE; + mSubScriptShiftFactor = aUserValue; + } + } + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::superscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mSupUserSetFlag = PR_TRUE; + mSupScriptShiftFactor = aUserValue; + } + } + + return rv; +} + NS_IMETHODIMP nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nsresult rv; - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; - nscoord ascent, descent; - nscoord count = 0; - nsRect rect[3]; - nsIFrame* child[3]; - nsIFrame* childFrame = mFrames.FirstChild(); - while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 3 > count) { - child[count] = childFrame; - childFrame->GetRect(rect[count]); + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsRect aRect; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics subScriptSize (nsnull); + nsHTMLReflowMetrics supScriptSize (nsnull); + nsIFrame* baseFrame; + nsIFrame* subScriptFrame; + nsIFrame* supScriptFrame; + // parameter v, Rule 18a, Appendix G of the TeXbook + nscoord minSubScriptShift = 0; + // parameter u in Rule 18a, Appendix G of the TeXbook + nscoord minSupScriptShift = 0; + + nsIFrame* aChildFrame = mFrames.FirstChild(); + while (nsnull != aChildFrame) + { + if (!IsOnlyWhitespace(aChildFrame)) { + aChildFrame->GetRect(aRect); + if (0 == count) { + // base + baseFrame = aChildFrame; + baseSize.descent = aRect.x; baseSize.ascent = aRect.y; + baseSize.width = aRect.width; baseSize.height = aRect.height; + } + else if (1 == count) { + // subscript + subScriptFrame = aChildFrame; + subScriptSize.descent = aRect.x; subScriptSize.ascent = aRect.y; + subScriptSize.width = aRect.width; subScriptSize.height = aRect.height; + // get the subdrop from the subscript font + nscoord aSubDrop; + GetSubDropFromChild (aPresContext, subScriptFrame, aSubDrop); + // parameter v, Rule 18a, App. G, TeXbook + minSubScriptShift = baseSize.descent + aSubDrop; + } + else if (2 == count) { + // superscript + supScriptFrame = aChildFrame; + supScriptSize.descent = aRect.x; supScriptSize.ascent = aRect.y; + supScriptSize.width = aRect.width; supScriptSize.height = aRect.height; + // get the supdrop from the supscript font + nscoord aSupDrop; + GetSupDropFromChild (aPresContext, supScriptFrame, aSupDrop); + // parameter u, Rule 18a, App. G, TeXbook + minSupScriptShift = baseSize.ascent - aSupDrop; + } + else { + NS_ASSERTION((count < 2),"nsMathMLmsubFrame : invalid markup"); + } count++; } - rv = childFrame->GetNextSibling(&childFrame); + + rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - descent = rect[0].x; - ascent = rect[0].y; - // Get the subscript and superscript offsets - nscoord subscriptOffset, superscriptOffset, leading; + ////////////////// + // Place Children + ////////////////// + + ////////////////////////////////////////////////// + // Get subscript shift + // slightly different from nsMathMLmsubFrame.cpp + ////////////////////////////////////////////////// + + // aSubScriptShift{1,2} + // = minimum amount to shift the subscript down + // = sub{1,2} in TeXbook + // aSubScriptShift1 = subscriptshift attribute * x-height + nscoord aSubScriptShift1, aSubScriptShift2; + + // get x-height (an ex) + nscoord xHeight = 0; nsCOMPtr fm; const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetSubscriptOffset(subscriptOffset); - fm->GetSuperscriptOffset(superscriptOffset); - fm->GetLeading(leading); + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); + fm->GetXHeight (xHeight); -//#if 0 -// XXX temporary hack pending bug http://bugzilla.mozilla.org/show_bug.cgi?id=9640 -nscoord fmAscent, xHeight; -fm->GetMaxAscent(fmAscent); -fm->GetXHeight(xHeight); -subscriptOffset = PR_MAX(subscriptOffset,fmAscent-(xHeight*4)/5); -//#endif - - subscriptOffset += leading; - superscriptOffset += leading; - - // logic of superimposing a box with sub and the same box with sup - - rect[0].x = 0; - rect[1].x = rect[0].width; - rect[2].x = rect[0].width; - - nscoord subHeight = rect[0].height + rect[1].height - subscriptOffset; - nscoord supHeight = rect[0].height + rect[2].height - superscriptOffset; - - aDesiredSize.descent = subHeight - ascent; - aDesiredSize.ascent = supHeight - descent; - aDesiredSize.height = aDesiredSize.descent + aDesiredSize.ascent; - aDesiredSize.width = rect[0].width + PR_MAX(rect[1].width, rect[2].width); - - rect[2].y = 0; - rect[1].y = aDesiredSize.height - rect[1].height; - rect[0].y = aDesiredSize.height - subHeight; - - if (aPlaceOrigin) { - // child[0]->SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - // child[2]->SetRect(aPresContext, rect[2]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; iwidth = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; - } + + // get a tentative value for subscriptshift + // Rule 18d, App. G, TeXbook + nscoord aSubScriptShift = + PR_MAX(minSubScriptShift,PR_MAX(aSubScriptShift1,aSubScriptShift2)); + + + ////////////////////////////////////////////////// + // Get supscript shift + // same code from nsMathMLmsupFrame.cpp + ////////////////////////////////////////////////// + + // get min supscript shift limit from x-height + // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook + nscoord minShiftFromXHeight = (nscoord) + (supScriptSize.descent + (1.0f/4.0f) * xHeight); + + // aSupScriptShift{1,2,3} + // = minimum amount to shift the supscript up + // = sup{1,2,3} in TeX + // aSupScriptShift1 = superscriptshift attribute * x-height + // Note that there are THREE values for supscript shifts depending + // on the current style + nscoord aSupScriptShift1, aSupScriptShift2, aSupScriptShift3; + // Set aSupScriptShift{1,2,3} default from font + GetSupScriptShifts (fm, aSupScriptShift1, aSupScriptShift2, aSupScriptShift3); + if (mSupUserSetFlag == PR_TRUE) { + // the user has set the superscriptshift attribute + float aFactor2 = ((float) aSupScriptShift2) / aSupScriptShift1; + float aFactor3 = ((float) aSupScriptShift3) / aSupScriptShift1; + aSupScriptShift1 = NSToCoordRound(mSupScriptShiftFactor * xHeight); + aSupScriptShift2 = NSToCoordRound(aFactor2 * aSupScriptShift1); + aSupScriptShift3 = NSToCoordRound(aFactor3 * aSupScriptShift1); + } + + // get sup script shift depending on current script level and display style + // Rule 18c, App. G, TeXbook + nscoord aSupScriptShift; + if ((mScriptLevel == 0) && + (mDisplayStyle == PR_TRUE) && + (mCompressed == PR_FALSE)) { + // Style D in TeXbook + aSupScriptShift = aSupScriptShift1; + } + else if (mCompressed == PR_TRUE) { + // Style C' in TeXbook = D',T',S',SS' + aSupScriptShift = aSupScriptShift3; + } + else { + // everything else = T,S,SS + aSupScriptShift = aSupScriptShift2; + } + + // get tentative value for superscriptshift + // Rule 18c, App. G, TeXbook + aSupScriptShift = + PR_MAX(minSupScriptShift,PR_MAX(aSupScriptShift,minShiftFromXHeight)); + + + ////////////////////////////////////////////////// + // Negotiate between aSupScriptShift and aSubScriptShift + // so that there will be enough gap between them + // Rule 18e, App. G, TeXbook + ////////////////////////////////////////////////// + + nscoord aRuleSize, dummy; + // XXX need to do update this ... + fm->GetStrikeout (dummy, aRuleSize); + nscoord gap = + (aSupScriptShift - supScriptSize.descent) - + (subScriptSize.ascent - aSubScriptShift); + if (gap < 4.0f * aRuleSize) { + // adjust aSubScriptShift to get a gap of (4.0 * aRuleSize) + aSubScriptShift += NSToCoordRound ((4.0f * aRuleSize) - gap); + } + + // next we want to ensure that the bottom of the superscript + // will be > (4/5) * x-height above baseline + gap = NSToCoordRound ((4.0f/5.0f) * xHeight - + (aSupScriptShift - supScriptSize.descent)); + if (gap > 0.0f) { + aSupScriptShift += gap; + aSubScriptShift -= gap; + } + + ////////////////////////////////////////////////// + // Do the Placing + ////////////////////////////////////////////////// + + // get bounding box for base + subscript + superscript + aDesiredSize.ascent = + PR_MAX(baseSize.ascent,(supScriptSize.ascent+aSupScriptShift)); + aDesiredSize.descent = + PR_MAX(baseSize.descent,(supScriptSize.descent+aSubScriptShift)); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + // add mScriptSpace to both super/subscript + // add italicCorrection only to superscript + // XXX this will be handled properly later ... + nscoord italicCorrection = 0; + aDesiredSize.width = baseSize.width + mScriptSpace + + PR_MAX((supScriptSize.width + italicCorrection),subScriptSize.width); + + if (aPlaceOrigin) { + nscoord dx, dy; + // now place the base ... + dx = 0; dy = aDesiredSize.ascent - baseSize.ascent; + FinishReflowChild (baseFrame, aPresContext, baseSize, dx, dy, 0); + // ... and subscript + dx = baseSize.width; + dy = aDesiredSize.ascent - subScriptSize.ascent + aSubScriptShift; + FinishReflowChild (subScriptFrame, aPresContext, subScriptSize, dx, dy, 0); + // ... and the superscript + dx = baseSize.width + italicCorrection; + dy = aDesiredSize.ascent - supScriptSize.ascent - aSupScriptShift; + FinishReflowChild (supScriptFrame, aPresContext, supScriptSize, dx, dy, 0); + } + return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.h index 90488d63838..96add55b617 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmsubsupFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ #ifndef nsMathMLmsubsupFrame_h___ @@ -34,6 +35,13 @@ class nsMathMLmsubsupFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmsubsupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -60,6 +68,10 @@ protected: virtual ~nsMathMLmsubsupFrame(); virtual PRIntn GetSkipSides() const { return 0; } + + private: + float mSubScriptShiftFactor, mSupScriptShiftFactor; + PRBool mSubUserSetFlag, mSupUserSetFlag; }; #endif /* nsMathMLmsubsupFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.cpp index d36d3a5a92f..292373f96b5 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.cpp @@ -18,9 +18,9 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ - #include "nsCOMPtr.h" #include "nsHTMLParts.h" #include "nsIHTMLContent.h" @@ -66,58 +66,216 @@ nsMathMLmsupFrame::~nsMathMLmsupFrame() { } +NS_IMETHODIMP +nsMathMLmsupFrame::Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init + (aPresContext, aContent, aParent, aContext, aPrevInFlow); + + mSupScriptShiftFactor = 0.0f; + mScriptSpace = NSFloatPointsToTwips(0.5f); // 0.5pt as in plain TeX + + // check for superscriptshift attribute in ex units + nsAutoString value; + mUserSetFlag = PR_FALSE; + if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute + (kNameSpaceID_None, nsMathMLAtoms::superscriptshift_, value)) { + PRInt32 aErrorCode; + float aUserValue = value.ToFloat(&aErrorCode); + if (NS_SUCCEEDED(aErrorCode)) { + mUserSetFlag = PR_TRUE; + mSupScriptShiftFactor = aUserValue; + } + } + + return rv; +} + NS_IMETHODIMP nsMathMLmsupFrame::Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nscoord count = 0; - nsRect rect[2]; - nsIFrame* child[2]; - nsIFrame* childFrame = mFrames.FirstChild(); - while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 2 > count) { - childFrame->GetRect(rect[count]); - child[count] = childFrame; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsRect aRect; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics supScriptSize (nsnull); + nsIFrame* baseFrame; + nsIFrame* supScriptFrame; + // parameter u in Rule 18a, Appendix G of the TeXbook + nscoord minSupScriptShift = 0; + + nsBoundingMetrics bmBase, bmSupScript; + + nsIFrame* aChildFrame = mFrames.FirstChild(); + while (nsnull != aChildFrame) + { + if (!IsOnlyWhitespace(aChildFrame)) { + aChildFrame->GetRect(aRect); + if (0 == count) { + // base + baseFrame = aChildFrame; + baseSize.descent = aRect.x; baseSize.ascent = aRect.y; + baseSize.width = aRect.width; baseSize.height = aRect.height; + if (NS_SUCCEEDED(GetBoundingMetricsFor(baseFrame, bmBase))) { + bmBase.descent = -bmBase.descent; + } else { + bmBase.descent = baseSize.descent; + bmBase.ascent = baseSize.ascent; + bmBase.width = baseSize.width; + } + } + else if (1 == count) { + // superscript + supScriptFrame = aChildFrame; + supScriptSize.descent = aRect.x; supScriptSize.ascent = aRect.y; + supScriptSize.width = aRect.width; supScriptSize.height = aRect.height; + if (NS_SUCCEEDED(GetBoundingMetricsFor(supScriptFrame, bmSupScript))) { + bmSupScript.descent = -bmSupScript.descent; + } else { + bmSupScript.descent = supScriptSize.descent; + bmSupScript.ascent = supScriptSize.ascent; + bmSupScript.width = supScriptSize.width; + } + // get the supdrop from the supscript font + nscoord aSupDrop; + GetSupDropFromChild (aPresContext, supScriptFrame, aSupDrop); + // parameter u, Rule 18a, App. G, TeXbook + minSupScriptShift = bmBase.ascent - aSupDrop; + } + else { + NS_ASSERTION((count < 2),"nsMathMLmsupFrame : invalid markup"); + } count++; } - childFrame->GetNextSibling(&childFrame); + rv = aChildFrame->GetNextSibling(&aChildFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - aDesiredSize.descent = rect[0].x; - // Get the superscript offset - nscoord superscriptOffset, leading; + ////////////////// + // Place Children + + // get min supscript shift limit from x-height + // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook + nscoord xHeight = 0; nsCOMPtr fm; const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetSuperscriptOffset(superscriptOffset); - fm->GetLeading(leading); + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); + fm->GetXHeight (xHeight); + nscoord minShiftFromXHeight = (nscoord) + (supScriptSize.descent + (1.0f/4.0f) * xHeight); - superscriptOffset += leading; + // aSupScriptShift{1,2,3} + // = minimum amount to shift the supscript up + // = sup{1,2,3} in TeX + // aSupScriptShift1 = superscriptshift attribute * x-height + // Note that there are THREE values for supscript shifts depending + // on the current style + nscoord aSupScriptShift1, aSupScriptShift2, aSupScriptShift3; + // Set aSupScriptShift{1,2,3} default from font + GetSupScriptShifts (fm, aSupScriptShift1, aSupScriptShift2, aSupScriptShift3); - aDesiredSize.height = rect[0].height + rect[1].height - superscriptOffset; - aDesiredSize.width = rect[0].width + rect[1].width; - rect[0].x = 0; - rect[1].x = rect[0].width; - rect[1].y = 0; - rect[0].y = aDesiredSize.height - rect[0].height; - aDesiredSize.ascent = aDesiredSize.height - aDesiredSize.descent; + if (mUserSetFlag) { + // the user has set the supscriptshift attribute + float aFactor2 = ((float) aSupScriptShift2) / aSupScriptShift1; + float aFactor3 = ((float) aSupScriptShift3) / aSupScriptShift1; + aSupScriptShift1 = NSToCoordRound(mSupScriptShiftFactor * xHeight); + aSupScriptShift2 = NSToCoordRound(aFactor2 * aSupScriptShift1); + aSupScriptShift3 = NSToCoordRound(aFactor3 * aSupScriptShift1); + } + + // get sup script shift depending on current script level and display style + // Rule 18c, App. G, TeXbook + nscoord aSupScriptShift; + if (mScriptLevel == 0 && mDisplayStyle && !mCompressed) { + // Style D in TeXbook + aSupScriptShift = aSupScriptShift1; + } + else if (mCompressed) { + // Style C' in TeXbook = D',T',S',SS' + aSupScriptShift = aSupScriptShift3; + } + else { + // everything else = T,S,SS + aSupScriptShift = aSupScriptShift2; + } + + // get actual supscriptshift to be used + // Rule 18c, App. G, TeXbook + nscoord actualSupScriptShift = + PR_MAX(minSupScriptShift,PR_MAX(aSupScriptShift,minShiftFromXHeight)); + + // get bounding box for base + supscript +#if 0 + const nsStyleFont *font; + baseFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + PRInt32 baseStyle = font->mFont.style; + supScriptFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + PRInt32 supScriptStyle = font->mFont.style; + if (baseStyle == NS_STYLE_FONT_STYLE_ITALIC && + supScriptStyle != NS_STYLE_FONT_STYLE_ITALIC) { + // take care of italic correction + ... + } +#endif + +#if 0 + aDesiredSize.ascent = + PR_MAX(baseSize.ascent,(supScriptSize.ascent+actualSupScriptShift)); + aDesiredSize.descent = + PR_MAX(baseSize.descent,(supScriptSize.descent-actualSupScriptShift)); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + // add mScriptSpace between base and supscript + aDesiredSize.width = baseSize.width + mScriptSpace + supScriptSize.width; +#endif + + mBoundingMetrics.ascent = + PR_MAX(bmBase.ascent, bmSupScript.ascent + actualSupScriptShift); + mBoundingMetrics.descent = + PR_MAX(bmBase.descent, bmSupScript.descent - actualSupScriptShift); + // add mScriptSpace between base and supscript + mBoundingMetrics.width = bmBase.width + mScriptSpace + bmSupScript.width; +printf("bmBase.width:%d + mScriptSpace:%d + bmSupScript.width:%d = mBoundingMetrics.width:%d\n", +bmBase.width, mScriptSpace, bmSupScript.width, mBoundingMetrics.width); + aDesiredSize.ascent = + PR_MAX(baseSize.ascent, supScriptSize.ascent + actualSupScriptShift); + aDesiredSize.descent = + PR_MAX(baseSize.descent, supScriptSize.descent - actualSupScriptShift); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + + aDesiredSize.width = mBoundingMetrics.width; + + mBoundingMetrics.descent = -mBoundingMetrics.descent; if (aPlaceOrigin) { - // child[0]->SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; iwidth = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; + nscoord dx, dy; + // now place the base ... + dx = 0; dy = aDesiredSize.ascent - baseSize.ascent; + FinishReflowChild (baseFrame, aPresContext, baseSize, dx, dy, 0); + // ... and supscript + +#if 0 + float t2p; + aPresContext->GetTwipsToPixels(&t2p); + PRInt32 scriptspace = NSTwipsToIntPixels(mScriptSpace, t2p); + printf("mScriptSpace in twips:%d pixel:%d\n", mScriptSpace, scriptspace); +#endif + + dx = baseSize.width + mScriptSpace; + dy = aDesiredSize.ascent - supScriptSize.ascent - actualSupScriptShift; + FinishReflowChild (supScriptFrame, aPresContext, supScriptSize, dx, dy, 0); } + return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.h index 89fd690879d..89195f76696 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmsupFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud (added TeX rendering rules) */ #ifndef nsMathMLmsupFrame_h___ @@ -34,6 +35,13 @@ class nsMathMLmsupFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmsupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -60,6 +68,10 @@ protected: virtual ~nsMathMLmsupFrame(); virtual PRIntn GetSkipSides() const { return 0; } + + private: + float mSupScriptShiftFactor; + PRBool mUserSetFlag; }; #endif /* nsMathMLmsupFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp index 1af0b9f1d43..d251b994849 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp @@ -75,7 +75,7 @@ nsMathMLmunderFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellish.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; return rv; } @@ -168,5 +168,10 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext, aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + + // XXX Fix me! + mBoundingMetrics.ascent = aDesiredSize.ascent; + mBoundingMetrics.descent = -aDesiredSize.descent; + mBoundingMetrics.width = aDesiredSize.width; return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp index adeebf3201a..834ad856243 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp @@ -75,7 +75,7 @@ nsMathMLmunderoverFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellish.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; return rv; } @@ -171,5 +171,11 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext, FinishReflowChild(child[i], aPresContext, childSize, rect[i].x, rect[i].y, 0); } } + + // XXX Fix me! + mBoundingMetrics.ascent = aDesiredSize.ascent; + mBoundingMetrics.descent = -aDesiredSize.descent; + mBoundingMetrics.width = aDesiredSize.width; + return NS_OK; }