From 4f4d69e8948f2ed4b8fcd2ec5197efa79284c7bb Mon Sep 17 00:00:00 2001 From: "rbs%maths.uq.edu.au" Date: Wed, 17 Nov 1999 00:49:37 +0000 Subject: [PATCH] Code to support stretchy MathML symbols! git-svn-id: svn://10.0.0.236/trunk@53715 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/mathml/base/src/Makefile.in | 1 + mozilla/layout/mathml/base/src/makefile.win | 2 + .../layout/mathml/base/src/nsIMathMLFrame.h | 9 +- .../layout/mathml/base/src/nsMathMLChar.cpp | 699 +++++++++++++++++- mozilla/layout/mathml/base/src/nsMathMLChar.h | 75 +- .../base/src/nsMathMLContainerFrame.cpp | 79 +- .../mathml/base/src/nsMathMLContainerFrame.h | 36 +- .../layout/mathml/base/src/nsMathMLParts.h | 1 + .../mathml/base/src/nsMathMLmiFrame.cpp | 4 +- .../mathml/base/src/nsMathMLmoFrame.cpp | 74 +- .../layout/mathml/base/src/nsMathMLmoFrame.h | 10 +- .../mathml/base/src/nsMathMLmoverFrame.cpp | 23 + .../mathml/base/src/nsMathMLmunderFrame.cpp | 23 + .../base/src/nsMathMLmunderoverFrame.cpp | 22 + 14 files changed, 940 insertions(+), 118 deletions(-) diff --git a/mozilla/layout/mathml/base/src/Makefile.in b/mozilla/layout/mathml/base/src/Makefile.in index ae158fb2fb7..e076a54b2f0 100644 --- a/mozilla/layout/mathml/base/src/Makefile.in +++ b/mozilla/layout/mathml/base/src/Makefile.in @@ -57,6 +57,7 @@ CPPSRCS = nsMathMLChar.cpp \ nsMathMLmunderoverFrame.cpp \ nsMathMLmpaddedFrame.cpp \ nsMathMLmstyleFrame.cpp \ + nsMathMLmsqrtFrame.cpp \ $(NULL) include $(topsrcdir)/config/config.mk diff --git a/mozilla/layout/mathml/base/src/makefile.win b/mozilla/layout/mathml/base/src/makefile.win index 1583cc2cff1..94cbe72b375 100644 --- a/mozilla/layout/mathml/base/src/makefile.win +++ b/mozilla/layout/mathml/base/src/makefile.win @@ -46,6 +46,7 @@ CPPSRCS= nsMathMLChar.cpp \ nsMathMLmunderoverFrame.cpp \ nsMathMLmpaddedFrame.cpp \ nsMathMLmstyleFrame.cpp \ + nsMathMLmsqrtFrame.cpp \ $(NULL) CPP_OBJS= .\$(OBJDIR)\nsMathMLChar.obj \ @@ -66,6 +67,7 @@ CPP_OBJS= .\$(OBJDIR)\nsMathMLChar.obj \ .\$(OBJDIR)\nsMathMLmunderoverFrame.obj \ .\$(OBJDIR)\nsMathMLmpaddedFrame.obj \ .\$(OBJDIR)\nsMathMLmstyleFrame.obj \ + .\$(OBJDIR)\nsMathMLmsqrtFrame.obj \ $(NULL) EXPORTS = \ diff --git a/mozilla/layout/mathml/base/src/nsIMathMLFrame.h b/mozilla/layout/mathml/base/src/nsIMathMLFrame.h index 095906178ca..4e6e636b546 100644 --- a/mozilla/layout/mathml/base/src/nsIMathMLFrame.h +++ b/mozilla/layout/mathml/base/src/nsIMathMLFrame.h @@ -43,10 +43,11 @@ public: * itself depending on its context */ NS_IMETHOD - Stretch(nsIPresContext& aPresContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize) = 0; + Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize) = 0; /* SUPPORT FOR SCRIPTING ELEMENTS: */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLChar.cpp b/mozilla/layout/mathml/base/src/nsMathMLChar.cpp index cea873ba455..b5a30f97aad 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLChar.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLChar.cpp @@ -17,6 +17,7 @@ * * Contributor(s): * Roger B. Sidje + * Shyjan Mahamud */ #include "nsCOMPtr.h" @@ -43,69 +44,691 @@ // nsMathMLChar implementation // +// Table of extensible chars in a suitable format for algorithmic purpose +// XXX Error-prone stuff. See how it can be automated. -// aDesiredStretchSize is an IN/OUT parameter. +/* Structure of the table gMathMLCharGlyph[]: + The table is divided into sections, each corresponding to a + stretchy symbol. Each section itself is divided into two blocks + that are separated with the special null code 0x0000. + The first block consists of *any number* of different glyphs + of *increasing* size. The second block consists of exactly + *4* glyphs that can be used to build a larger size. + + Another separate table, gMathMLCharIndex[], is used to store + pointers to the beginning of each section. + + 3 steps are needed to extend the table: + --------------------------------------- + 1. Append your new section in gMathMLCharGlyph[]. + 2. Append your new enum in nsMathMLCharEnum, and kMathMLChar + 3. Append a new pointer in gMathMLCharIndex[], so that + gMathMLCharIndex[your_enum] points to the begining of + your new section in gMathMLCharGlyph[]. That is, + your_section = gMathMLCharGlyph[gMathMLCharIndex[your_enum]] + */ + +// XXX The current values in the table correspond to the Symbol font. +// Other fonts will need their own customized tables. + +static PRUnichar gMathMLCharGlyph[] = { + + //------------ + //index = 0 + //Section for: left parenthesis + //Block of different variants of *increasing* size... + 0x0028, // LEFT PARENTHESIS # parenleft + // more here ... + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8EB, // LEFT PAREN TOP # parenlefttp (CUS) + 0xF8EC, // LEFT PAREN EXTENDER # parenleftex (CUS) + 0xF8ED, // LEFT PAREN BOTTOM # parenleftbt (CUS) + 0xF8EC, // glue = LEFT PAREN EXTENDER # parenleftex (CUS) + + //------------ + //index = 6 + //Section for: right parenthesis + //Block of different variants of *increasing* size... + 0x0029, // RIGHT PARENTHESIS # parenright + // more here ... + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8F6, // RIGHT PAREN TOP # parenrighttp (CUS) + 0xF8F7, // MIDDLE = RIGHT PAREN EXTENDER # parenrightex (CUS) + 0xF8F8, // RIGHT PAREN BOTTOM # parenrightbt (CUS) + 0xF8F7, // glue = RIGHT PAREN EXTENDER # parenrightex (CUS) + + //------------ + //index = 12 + //Section for: integral + //Block of different variants of *increasing* size... + 0x222B, // INTEGRAL # integral + // more here ... + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0x2320, // TOP HALF INTEGRAL # integraltp + 0xF8F5, // INTEGRAL EXTENDER # integralex (CUS) + 0x2321, // BOTTOM HALF INTEGRAL # integralbt + 0xF8F5, // glue = INTEGRAL EXTENDER # integralex (CUS) + + //------------ + //index = 18 + //Section for: left square bracket + //Block of different variants of *increasing* size... + 0x005B, // LEFT SQUARE BRACKET # bracketleft + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8EE, // LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) + 0xF8EF, // LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) + 0xF8F0, // LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) + 0xF8EF, // glue = LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) + + //------------ + //index = 24 + //Section for: right square bracket + //Block of different variants of *increasing* size... + 0x005D, // RIGHT SQUARE BRACKET # bracketright + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8F9, // RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) + 0xF8FA, // RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) + 0xF8FB, // RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS)0 + 0xF8FA, // glue = RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) + + //------------ + //index = 30 + //Section for: left curly bracket + //Block of different variants of *increasing* size... + 0x007B, // LEFT CURLY BRACKET # braceleft + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8F1, // LEFT CURLY BRACKET TOP # bracelefttp (CUS) + 0xF8F2, // LEFT CURLY BRACKET MID # braceleftmid (CUS) + 0xF8F3, // LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) + 0xF8F4, // glue = CURLY BRACKET EXTENDER # braceex (CUS) + + //------------ + //index = 36 + //Section for: right square bracket + //Block of different variants of *increasing* size... + 0x007D, // RIGHT CURLY BRACKET # braceright + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8FC, // RIGHT CURLY BRACKET TOP # bracerighttp (CUS) + 0xF8FD, // RIGHT CURLY BRACKET MID # bracerightmid (CUS) + 0xF8FE, // RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) + 0xF8F4, // glue = CURLY BRACKET EXTENDER # braceex (CUS) + + //------------ + //index = 42 + //Section for: down arrow + //Block of different variants of *increasing* size... + 0x2193, // DOWNWARDS ARROW # arrowdown + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8E6, // VERTICAL ARROW EXTENDER # arrowvertex (CUS) + 0xF8E6, // VERTICAL ARROW EXTENDER # arrowvertex (CUS) + 0x2193, // DOWNWARDS ARROW # arrowdown + 0xF8E6, // glue = VERTICAL ARROW EXTENDER # arrowvertex (CUS) + + //------------ + //index = 48 + //Section for: up arrow + //Block of different variants of *increasing* size... + 0x2191, // UPWARDS ARROW # arrowup + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0x2191, // UPWARDS ARROW # arrowup + 0xF8E6, // VERTICAL ARROW EXTENDER # arrowvertex (CUS) + 0xF8E6, // VERTICAL ARROW EXTENDER # arrowvertex (CUS) + 0xF8E6, // glue = VERTICAL ARROW EXTENDER # arrowvertex (CUS) + + //------------ + //index = 54 + //Section for: left arrow + //Block of different variants of *increasing* size... + 0x2190, // LEFTWARDS ARROW # arrowleft + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0x2190, // LEFTWARDS ARROW # arrowleft + 0xF8E7, // HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + 0xF8E7, // HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + 0xF8E7, // glue = HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + + //------------ + //index = 60 + //Section for: right arrow + //Block of different variants of *increasing* size... + 0x2192, // RIGHTWARDS ARROW # arrowright + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8E7, // HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + 0xF8E7, // HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + 0x2192, // RIGHTWARDS ARROW # arrowright + 0xF8E7, // glue = HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) + + //------------ + //index = 66 + 0xF8E5, // RADICAL EXTENDER # radicalex (CUS) + + 0x0000, // That's all folks ... + //Block of partial glyphs in the order top/left, middle, bottom/right, glue + 0xF8E5, // RADICAL EXTENDER # radicalex (CUS) + 0xF8E5, // RADICAL EXTENDER # radicalex (CUS) + 0xF8E5, // RADICAL EXTENDER # radicalex (CUS) + 0xF8E5, // RADICAL EXTENDER # radicalex (CUS) + + //------------ + //index = 70 + //end of table ... + 0x0000, +}; + +// Pointers to the beginning of each section +static PRInt32 gMathMLCharIndex[] = { + 0, // eMathMLChar_LeftParenthesis + 6, // eMathMLChar_RightParenthesis + 12, // eMathMLChar_Integral + 18, // eMathMLChar_LeftSquareBracket + 24, // eMathMLChar_RightSquareBracket + 30, // eMathMLChar_LeftCurlyBracket + 36, // eMathMLChar_RightCurlyBracket + 42, // eMathMLChar_DownArrow, + 48, // eMathMLChar_UpArrow, + 54, // eMathMLChar_LeftArrow, + 60, // eMathMLChar_RightArrow, + 66, // eMathMLChar_RadicalExtender, + 72, // safeguard, *must* always point at the *end* of gMathMLCharGlyph[] +}; + +// data to enable a clean architecture and extensibility +enum nsMathMLCharEnum { + eMathMLChar_UNKNOWN = -1, + eMathMLChar_LeftParenthesis, + eMathMLChar_RightParenthesis, + eMathMLChar_Integral , + eMathMLChar_LeftSquareBracket, + eMathMLChar_RightSquareBracket, + eMathMLChar_LeftCurlyBracket, + eMathMLChar_RightCurlyBracket, + eMathMLChar_DownArrow, + eMathMLChar_UpArrow, + eMathMLChar_LeftArrow, + eMathMLChar_RightArrow, + eMathMLChar_RadicalExtender, + eMathMLChar_COUNT +}; + +static const PRInt32 kMathMLChar[] = { + eMathMLChar_LeftParenthesis , '(', + eMathMLChar_RightParenthesis , ')', + eMathMLChar_Integral , 0x222B, + eMathMLChar_LeftSquareBracket, '[', + eMathMLChar_RightSquareBracket, ']', + eMathMLChar_LeftCurlyBracket, '{', + eMathMLChar_RightCurlyBracket, '}', + eMathMLChar_DownArrow, 0x2193, + eMathMLChar_UpArrow, 0x2191, + eMathMLChar_LeftArrow, 0x2190, + eMathMLChar_RightArrow, 0x2192, + eMathMLChar_RadicalExtender, 0xF8E5, +// eMathMLChar_Radical, 0x221A, +}; + +//--------------------------------------------- + +// Helper method that detects a new enum and cache it for you. +// You do not have to call this method. SetData() will call it +// for you whenever mData changes. +void +nsMathMLChar::SetEnum() { + mEnum = eMathMLChar_UNKNOWN; + if (1 == mData.Length()) { + PRUnichar ch = mData[0]; + PRInt32 count = sizeof(kMathMLChar) / sizeof(kMathMLChar[0]); + for (PRInt32 i = 0; i < count; i += 2) { + if (ch == kMathMLChar[i+1]) { + mEnum = nsMathMLCharEnum(kMathMLChar[i]); + break; + } + } + } +} + +/* + The Stretch: + @param aContainerSize - suggested size for the stretched char + @param aDesiredStretchSize - IN/OUT parameter. On input + our current size, on output the size after stretching. + + How it works? + The Stretch() method first looks for a glyph of appropriate + size; If a glyph is found, it is cached by this object + and its size is returned in aDesiredStretchSize. The cached + glyph will then be used at the painting stage. + + If no glyph of appropriate size is found, aDesiredStretchSize + is set to aContainerSize and the char is later built by + parts, at the painting stage, to fit the size. + + * When a glyph is found, its size can actually be slighthly + larger or smaller than aContainerSize. + + * When built by parts, the char is stretched to *exactly* + fit aContainerSize. [Is this what we want? Can we leave + the leading?] + + In either case, it is the responsibility of the caller + to account for the spacing when setting aContainerSize, and + to leave the extra spacing when placing the stretched char. +*/ + +//#define SHOW_BORDERS 1 + +// NS_IMETHODIMP -nsMathMLChar::Stretch(nsIPresContext& aPresContext, - nsIStyleContext* aStyleContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize) +nsMathMLChar::Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIStyleContext* aStyleContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize) { + nsresult rv = NS_OK; + + // quick return if we know nothing about this char + if (eMathMLChar_UNKNOWN == mEnum) { + return NS_OK; + } + + // check the common situations where stretching is not actually needed + // XXX need better criteria if (aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) { - // vertical stretching... for a boundary symbol - aDesiredStretchSize.descent = aContainerSize.descent; - aDesiredStretchSize.ascent = aContainerSize.ascent; - aDesiredStretchSize.height = aDesiredStretchSize.ascent - + aDesiredStretchSize.descent; + if (aContainerSize.height <= aDesiredStretchSize.height) { + return NS_OK; + } } else if (aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { - // horizontal stretching... for an accent - aDesiredStretchSize.width = aContainerSize.width; + if (aContainerSize.width <= aDesiredStretchSize.width) { + return NS_OK; + } } + // cache the stretch direction for use later at the painting stage + mDirection = aStretchDirection; + +// printf("Container height:%d ascent:%d descent:%d\n contains height:%d ascent:%d descent:%d\n", +// aContainerSize.height, aContainerSize.ascent, aContainerSize.descent, +// aDesiredStretchSize.height, aDesiredStretchSize.ascent, +// aDesiredStretchSize.descent); + + // XXX Note: there are other symbols that just need to slightly + // increase their size, like \Sum + + nsStyleFont font; + nsStyleColor color; + aStyleContext->GetStyle(eStyleStruct_Font, font); + aStyleContext->GetStyle(eStyleStruct_Color, color); + + // Set color and font + aRenderingContext.SetColor(color.mColor); + aRenderingContext.SetFont(font.mFont); + + nsBoundingMetrics bm; + nscoord height = aDesiredStretchSize.height; + nscoord width = aDesiredStretchSize.width; + nscoord ascent = aDesiredStretchSize.ascent; + nscoord descent = aDesiredStretchSize.descent; + + PRInt32 index = gMathMLCharIndex[mEnum]; + PRInt32 limit = gMathMLCharIndex[mEnum+1]; // next char starts here... + nscoord w, h; + + // try first to see if there is a glyph of appropriate size ... + PRBool sizeOK = PR_FALSE; + PRUnichar ch = gMathMLCharGlyph[index++]; + while (ch && index <= limit) { + // printf("Checking size of:%c index:%d\n", ch & 0x00FF, index); + rv = aRenderingContext.GetBoundingMetrics(&ch, 1, bm); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); getchar(); return rv; } + h = bm.ascent - bm.descent; + w = bm.width; + + // printf("height:%d width:%d ascent:%d descent:%d\n", + // height, bm.width, bm.ascent, bm.descent); + + // XXX temp hack -- need better criteria + if ((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL && h > height) || + (aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL && w > width)) { + sizeOK = PR_TRUE; + descent = -bm.descent; // as expected by Gecko + ascent = bm.ascent; + height = bm.ascent - bm.descent; + width = bm.width; + mGlyph = ch; + break; + } + ch = gMathMLCharGlyph[index++]; + } + + if (!sizeOK) { // see if we can build by parts... + mGlyph = 0; + PRInt32 i; + nscoord a, d; + h = w = a = d = 0; + float flex[3] = {0.7f, 0.3f, 0.7f}; // XXX hack! + if (mDirection == NS_STRETCH_DIRECTION_VERTICAL) { + // default is to fill-up the area given to us + width = aDesiredStretchSize.width; + height = aContainerSize.height; + ascent = aContainerSize.ascent; + descent = aContainerSize.descent; + + for (i = 0; i < 4; i++) { + ch = gMathMLCharGlyph[index+i]; + rv = aRenderingContext.GetBoundingMetrics(&ch, 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 (h <= aContainerSize.height) { // can nicely fit in the available space... + width = w; + } else { // sum of parts doesn't fit in the space... will use a single glyph + return NS_OK; + } + } + else if (mDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { + // default is to fill-up the area given to us + width = aContainerSize.width; + height = aDesiredStretchSize.height; + ascent = aDesiredStretchSize.ascent; + descent = aDesiredStretchSize.descent; + + for (i = 0; i < 4; i++) { + ch = gMathMLCharGlyph[index+i]; + rv = aRenderingContext.GetBoundingMetrics(&ch, 1, bm); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); /*getchar();*/ return rv; } + 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 (w <= aContainerSize.width) { // can nicely fit in the available space... +// ascent = a; +// height = a - d; + } else { // sum of parts doesn't fit in the space... will use a single glyph + return NS_OK; + } + } + } + + aDesiredStretchSize.width = width; + aDesiredStretchSize.height = height; + aDesiredStretchSize.ascent = ascent; + aDesiredStretchSize.descent = descent; + return NS_OK; } +void +nsMathMLChar::DrawChar(nsIRenderingContext& aRenderingContext, + PRUnichar aChar, + nscoord aX, + nscoord aY, + nsRect& aClipRect) +{ + PRBool clipState; + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(aClipRect, nsClipCombine_kIntersect, clipState); + aRenderingContext.DrawString(&aChar, PRUint32(1), aX, aY); + aRenderingContext.PopState(clipState); +} + NS_IMETHODIMP nsMathMLChar::Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, - const nsPoint& aOffset) + nsIStyleContext* aStyleContext) { nsresult rv = NS_OK; - const nsStyleColor* color = - (const nsStyleColor*)aStyleContext->GetStyleData(eStyleStruct_Color); - const nsStyleFont* font = - (const nsStyleFont*)aStyleContext->GetStyleData(eStyleStruct_Font); + + nsStyleFont font; + nsStyleColor color; + aStyleContext->GetStyle(eStyleStruct_Font, font); + aStyleContext->GetStyle(eStyleStruct_Color, color); // Set color and font - aRenderingContext.SetColor(color->mColor); - aRenderingContext.SetFont(font->mFont); + aRenderingContext.SetColor(color.mColor); + aRenderingContext.SetFont(font.mFont); - // Display the char - const PRUnichar* aString = mData.GetUnicode(); - aRenderingContext.DrawString(aString, PRUint32(mData.Length()), aOffset.x, aOffset.y); + nscoord dx = mRect.x; + nscoord dy = mRect.y; - return rv; -} + // quick return if we know nothing about this char + if (eMathMLChar_UNKNOWN == mEnum) { + aRenderingContext.DrawString(mData.GetUnicode(), PRUint32(mData.Length()), dx, dy); + return NS_OK; + } -#if 0 -// Each stretchy symbol can have its improved Stretch() and -// Paint() methods that override the default ones. + if (0 < mGlyph) { // wow, there is a glyph of appropriate size! + aRenderingContext.DrawString(&mGlyph, PRUint32(1), dx, dy); + } + else { // paint by parts + PRInt32 index = gMathMLCharIndex[mEnum]; + PRInt32 limit = gMathMLCharIndex[mEnum+1]; // next char starts here... -void -nsMathMLChar::StretchIntegral() -{ -} + // jump past the glyphs of various size... + PRUnichar ch = gMathMLCharGlyph[index++]; + while (ch && index <= limit) { + ch = gMathMLCharGlyph[index++]; + } + // return if there are no partial glyphs (an erroneous table!) + if (!gMathMLCharGlyph[index]) + return NS_OK; -void -nsMathMLChar::PaintIntegral() -{ -} + nsRect clipRect; + nsBoundingMetrics bm; + bm.Clear(); -... + // grab some metrics to help adjusting the placements + nsCOMPtr fm; + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); + nscoord fontAscent, fontDescent; + fm->GetMaxAscent(fontAscent); + fm->GetMaxDescent(fontDescent); + + nsBoundingMetrics bmdata[4]; + nscoord stride, offset[3], start[3], end[3]; + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + + // get metrics data to be re-used later + PRInt32 i; + for (i = 0; i < 4; i++) { + ch = gMathMLCharGlyph[index+i]; + rv = aRenderingContext.GetBoundingMetrics(&ch, 1, bm); + if (NS_FAILED(rv)) { printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); /*getchar();*/ return rv; } + bmdata[i] = bm; +// printf("bm for i:%d ch:%04X ascent:%d descent:%d lbearing:%d rbearing:%d width:%d fontAscent:%d fontDescent:%d\n", +// i, ch, bm.ascent, bm.descent, bm.leftBearing, bm.rightBearing, bm.width, fontAscent, fontDescent); + } + + // draw top (or left), middle, bottom (or right) + for (i = 0; i < 3; i++) { + ch = gMathMLCharGlyph[index+i]; + bm = bmdata[i]; +//printf("Drawing i=%d ch=%04X", i, ch); getchar(); + if (mDirection == NS_STRETCH_DIRECTION_VERTICAL) { + if (0 == i) { // top + //coord with line-spacing (i.e., leading) + // dy = mRect.y; + + //coord for exact fit (i.e., no leading) + dy = mRect.y + bm.ascent - fontAscent; + } + else if (1 == i) { // middle + // coord with line-spacing (i.e., leading) + // dy = mRect.y + (mRect.height - fontAscent - fontDescent + // - bmdata[0].ascent - bmdata[2].descent + bm.ascent + bm.descent)/2; + + // coord for exact fit (i.e., no leading) + dy = mRect.y + (mRect.height - (bm.ascent - bm.descent))/2 + - (fontAscent - bm.ascent); + } + else if (2 == i) { // bottom + // coord with line-spacing (i.e., leading) + // dy = mRect.y + mRect.height - (fontAscent + fontDescent); + + // coord for exact fit (i.e., no leading) + dy = mRect.y + mRect.height - (fontAscent - bm.descent); + } + clipRect = nsRect(dx, dy, mRect.width, mRect.height); + // abcissa that DrawString used + offset[i] = dy; + // *exact* abcissa where the *top-most* pixel of the glyph is painted + start[i] = dy + fontAscent - bm.ascent; + // *exact* abcissa where the *bottom-most* pixel of the glyph is painted + end[i] = dy + fontAscent - bm.descent; // note: end = start + height + } + else if (mDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { + if (0 == i) { // left + // coord with intercharacter-spacing + // dx = mRect.x; + + // coord for exact fit (no intercharacter-spacing) + dx = mRect.x - bm.leftBearing; + } + else if (1 == i) { // middle + // coord with intercharacter-spacing + dx = mRect.x + (mRect.width - bm.width)/2; + } + else if (2 == i) { // right + // coord with intercharacter-spacing + // dx = mRect.x + mRect.width - bm.width; + + // coord for exact fit (no intercharacter-spacing) + dx = mRect.x + mRect.width - bm.rightBearing; + } + // abcissa that DrawString used + offset[i] = dx; + // *exact* abcissa where the *left-most* pixel of the glyph is painted + start[i] = dx + bm.leftBearing; + // *exact* abcissa where the *right-most* pixel of the glyph is painted + end[i] = dx + bm.rightBearing; // note: end = start + width + } + } + + for (i = 0; i < 3; i++) { + ch = gMathMLCharGlyph[index+i]; + if (mDirection == NS_STRETCH_DIRECTION_VERTICAL) { +#ifdef SHOW_BORDERS + aRenderingContext.SetColor(NS_RGB(0,0,0)); + aRenderingContext.DrawRect(nsRect(dx,start[i],mRect.width+30*(i+1),end[i]-start[i])); #endif + dy = offset[i]; + if (i==0) clipRect = nsRect(dx, dy, mRect.width, mRect.height); + else if (i==1) clipRect = nsRect(dx, end[0], mRect.width, start[2]-end[0]); + else if (i==2) clipRect = nsRect(dx, start[2], mRect.width, end[2]-start[2]); + } + else if (mDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { +#ifdef SHOW_BORDERS + aRenderingContext.SetColor(NS_RGB(0,0,0)); + aRenderingContext.DrawRect(nsRect(start[i],dy,end[i]-start[i],mRect.height+30*(i+1))); +#endif + dx = offset[i]; + nscoord top = PR_MIN(dy, dy + fontAscent - bm.ascent); + if (i==0) clipRect = nsRect(dx, top, mRect.width, mRect.height); + else if (i==1) clipRect = nsRect(end[0], top, start[2]-end[0], mRect.height); + else if (i==2) clipRect = nsRect(start[2], top, end[2]-start[2], mRect.height); + } +// printf("Drawing i:%d ch:%04X ascent:%d descent:%d lbearing:%d rbearing:%d width:%d at position dx:%d dy:%d\n", +// i, ch, bm.ascent, bm.descent, bm.leftBearing, bm.rightBearing, bm.width, dx, dy); +// getchar(); + + if (!clipRect.IsEmpty()) { + clipRect.Inflate(onePixel, onePixel); + DrawChar(aRenderingContext, ch, dx, dy, clipRect); + } + } + + // fill the gap between top and middle, and between middle and bottom. + ch = gMathMLCharGlyph[index+3]; // glue + for (i = 0; i < 2; i++) { + PRInt32 count = 0; + if (mDirection == NS_STRETCH_DIRECTION_VERTICAL) { + dy = offset[i]; + clipRect = nsRect(dx, end[i], mRect.width, start[i+1]-end[i]); + clipRect.Inflate(onePixel, onePixel); +#ifdef SHOW_BORDERS + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(clipRect); +#endif + bm = bmdata[i]; + while (dy + fontAscent - bm.descent < start[i+1]) { + if (2 > count) { + stride = -bm.descent; + bm = bmdata[3]; // glue + stride += bm.ascent; + } + count++; + dy += stride; + DrawChar(aRenderingContext, ch, dx, dy, clipRect); +// NS_ASSERTION(5000 == count, "Error - gMathMLCharGlyph is incorrectly set"); + if (1000 == count) return NS_ERROR_UNEXPECTED; + } +#ifdef SHOW_BORDERS + // last glyph that may cross past its boundary and collide with the next + nscoord height = bm.ascent - bm.descent; + aRenderingContext.SetColor(NS_RGB(0,255,0)); + aRenderingContext.DrawRect(nsRect(dx,dy+fontAscent-bm.ascent,mRect.width,height)); +#endif + } + else if (mDirection == NS_STRETCH_DIRECTION_HORIZONTAL) { + dx = offset[i]; + nscoord top = PR_MIN(dy, dy + fontAscent - bm.ascent); + clipRect = nsRect(end[i], top, start[i+1]-end[i], mRect.height); + clipRect.Inflate(onePixel, onePixel); +#ifdef SHOW_BORDERS + // rectangles in-between that are to be filled + aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawRect(clipRect); +#endif + bm = bmdata[i]; + while (dx + bm.rightBearing < start[i+1]) { + if (2 > count) { + stride = bm.rightBearing; + bm = bmdata[3]; // glue + stride -= bm.leftBearing; + } + count++; + dx += stride; + DrawChar(aRenderingContext, ch, dx, dy, clipRect); +// NS_ASSERTION(5000 == count, "Error - gMathMLCharGlyph is incorrectly set"); + if (1000 == count) return NS_ERROR_UNEXPECTED; +// printf("Drawing %04X ascent:%d descent:%d at position dx:%d dy:%d\n", +// ch, bm.ascent, bm.descent, dx, dy); + } +#ifdef SHOW_BORDERS + // last glyph that may cross past its boundary and collide with the next + nscoord width = bm.rightBearing - bm.leftBearing; + aRenderingContext.SetColor(NS_RGB(0,255,0)); + aRenderingContext.DrawRect(nsRect(dx+bm.leftBearing,dy,width,mRect.height)); +#endif + } + } + } + + return NS_OK; +} + diff --git a/mozilla/layout/mathml/base/src/nsMathMLChar.h b/mozilla/layout/mathml/base/src/nsMathMLChar.h index 03107ce6469..04895ad812d 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLChar.h +++ b/mozilla/layout/mathml/base/src/nsMathMLChar.h @@ -25,6 +25,7 @@ #include "nsMathMLOperators.h" typedef PRUint32 nsStretchDirection; +enum nsMathMLCharEnum; #define NS_STRETCH_DIRECTION_HORIZONTAL 0 #define NS_STRETCH_DIRECTION_VERTICAL 1 @@ -35,12 +36,12 @@ struct nsCharMetrics { nscoord descent, ascent; nscoord width, height; - nsCharMetrics(nscoord Descent=0, nscoord Ascent=0, - nscoord Width=0, nscoord Height=0) { - width = Width; - height = Height; - ascent = Ascent; - descent = Descent; + nsCharMetrics(nscoord aDescent=0, nscoord aAscent=0, + nscoord aWidth=0, nscoord aHeight=0) { + width = aWidth; + height = aHeight; + ascent = aAscent; + descent = aDescent; } nsCharMetrics(const nsCharMetrics& aCharMetrics) { @@ -78,41 +79,75 @@ struct nsCharMetrics { class nsMathMLChar { public: + // constructor and destructor + nsMathMLChar() + { + } + +/* + nsMathMLChar() : mData(), + mGlyph(0) + { + nsStr::Initialize(mData, eTwoByte); // with MathML, we are two-byte by default + } +*/ + + virtual ~nsMathMLChar() + { + } + NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, - const nsPoint& aOffset); + nsIStyleContext* aStyleContext); // This is the method called to ask the char to stretch itself. // aDesiredStretchSize is an IN/OUT parameter. // On input - it contains our current size. // On output - the same size or the new size that we want. - NS_IMETHOD Stretch(nsIPresContext& aPresContext, - nsIStyleContext* aStyleContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize); + NS_IMETHOD Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsIStyleContext* aStyleContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize); void SetData(nsString& aData) { mData = aData; + SetEnum(); } void GetData(nsString& aData) { aData = mData; } - // constructor and destructor - nsMathMLChar() - { + void + GetRect(nsRect& aRect) { + aRect = mRect; } - virtual ~nsMathMLChar() - { + void + SetRect(const nsRect& aRect) { + mRect = aRect; } -protected: - nsString mData; +private: + nsString mData; + PRUnichar mGlyph; + nsRect mRect; + PRInt32 mDirection; + nsMathMLCharEnum mEnum; + + // helper methods + void + SetEnum(); + + static void + DrawChar(nsIRenderingContext& aRenderingContext, + PRUnichar aChar, + nscoord aX, + nscoord aY, + nsRect& aClipRect); }; #endif /* nsMathMLChar_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp index 63f60cc6b04..8297565d9af 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -151,10 +151,11 @@ nsMathMLContainerFrame::ReflowEmptyChild(nsIPresContext& aPresContext, */ NS_IMETHODIMP -nsMathMLContainerFrame::Stretch(nsIPresContext& aPresContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize) +nsMathMLContainerFrame::Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize) { return NS_OK; // the Stretch() is only implemented by and its nsMathMLChar } @@ -253,7 +254,7 @@ nsMathMLContainerFrame::InsertScriptLevelStyleContext(nsIPresContext& aPresConte if (newStyleContext && newStyleContext.get() != lastStyleContext) { // create a new frame and append it as sole child of the last created frame nsIFrame* newFrame = nsnull; - NS_NewMathMLContainerFrame(&newFrame); + NS_NewMathMLWrapperFrame(&newFrame); NS_ASSERTION(newFrame, "Failed to create new frame"); newFrame->Init(aPresContext, childContent, lastFrame, newStyleContext, nsnull); @@ -455,7 +456,9 @@ nsMathMLContainerFrame::Reflow(nsIPresContext& aPresContext, nsIMathMLFrame* aMathMLFrame; rv = childFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && nsnull != aMathMLFrame) { - aMathMLFrame->Stretch(aPresContext, stretchDir, parentSize, childSize); + nsIRenderingContext& renderingContext = *aReflowState.rendContext; + aMathMLFrame->Stretch(aPresContext, renderingContext, + stretchDir, parentSize, childSize); // store the updated metrics childFrame->SetRect(&aPresContext, nsRect(childSize.descent, childSize.ascent, @@ -496,3 +499,67 @@ nsMathMLContainerFrame::Reflow(nsIPresContext& aPresContext, aStatus = NS_FRAME_COMPLETE; return NS_OK; } + +//========================== + +nsresult +NS_NewMathMLWrapperFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsMathMLWrapperFrame* it = new nsMathMLWrapperFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsMathMLWrapperFrame::nsMathMLWrapperFrame() +{ +} + +nsMathMLWrapperFrame::~nsMathMLWrapperFrame() +{ +} + +NS_IMETHODIMP +nsMathMLWrapperFrame::Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize) +{ + nsIFrame* childFrame = mFrames.FirstChild(); + nsIMathMLFrame* aMathMLFrame; + nsresult rv = childFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + aMathMLFrame->Stretch(aPresContext, aRenderingContext, aStretchDirection, + aContainerSize, aDesiredStretchSize); + childFrame->SetRect(&aPresContext, nsRect(0,0,aDesiredStretchSize.width,aDesiredStretchSize.height)); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLWrapperFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + nsresult rv = NS_OK; + + nsReflowStatus childStatus; + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); + nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); + + nsIFrame* childFrame = mFrames.FirstChild(); + nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); + rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); + childFrame->SetRect(&aPresContext, nsRect(0,0,childDesiredSize.width,childDesiredSize.height)); + aDesiredSize = childDesiredSize; + aStatus = childStatus; + return rv; +} diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h index f5e366898fd..ed90c5d9a7c 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -67,10 +67,11 @@ public: NS_IMETHOD_(nsrefcnt) AddRef(void); NS_IMETHOD_(nsrefcnt) Release(void); - NS_IMETHOD Stretch(nsIPresContext& aPresContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize); + NS_IMETHOD Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize); NS_IMETHOD GetPresentationData(PRInt32* aScriptLevel, PRBool* aDisplayStyle); @@ -105,6 +106,8 @@ public: nsReflowStatus& aStatus); // helper method for altering the style contexts of subscript/superscript elements + // XXX this is pretty much a hack until the content model caters for MathML and + // the style system has some provisions for MathML NS_IMETHOD InsertScriptLevelStyleContext(nsIPresContext& aPresContext); @@ -129,4 +132,29 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } }; +// XXX hack until the content model caters for MathML and the style system +// has some provisions for MathML +class nsMathMLWrapperFrame : public nsMathMLContainerFrame { +public: + friend nsresult NS_NewMathMLWrapperFrame(nsIFrame** aNewFrame); + + NS_IMETHOD Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize); + + NS_IMETHOD + Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + +protected: + nsMathMLWrapperFrame(); + virtual ~nsMathMLWrapperFrame(); + + virtual PRIntn GetSkipSides() const { return 0; } +}; + #endif /* nsMathMLContainerFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLParts.h b/mozilla/layout/mathml/base/src/nsMathMLParts.h index e7d797d2f22..9f70a88836e 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLParts.h +++ b/mozilla/layout/mathml/base/src/nsMathMLParts.h @@ -42,6 +42,7 @@ extern nsresult NS_NewMathMLmunderoverFrame ( nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmmultiscriptsFrame ( nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmstyleFrame ( nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmtdFrame ( nsIFrame** aNewFrame ); +extern nsresult NS_NewMathMLmsqrtFrame( nsIFrame** aNewFrame ); inline nsresult NS_NewMathMLContainerFrame( nsIFrame** aNewFrame ) { return NS_NewMathMLmrowFrame(aNewFrame); diff --git a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp index e76aa90fc1b..0f920ea943a 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmiFrame.cpp @@ -100,7 +100,7 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext& aPresContext, // Get the length of the text content that we enclose // our content can include comment-nodes, attribute-nodes, text-nodes... - // we use to DOM to make sure that we are only looking at 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); @@ -137,7 +137,7 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext& aPresContext, if (newStyleContext && newStyleContext.get() != mStyleContext) { nsIFrame* newFrame = nsnull; - NS_NewMathMLContainerFrame(&newFrame); + NS_NewMathMLWrapperFrame(&newFrame); NS_ASSERTION(newFrame, "Failed to create new frame"); newFrame->Init(aPresContext, mContent, this, newStyleContext, nsnull); diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp index 177921fe152..a82cad661b1 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.cpp @@ -83,7 +83,6 @@ // the baseline) are identifiers displayed in a non-slanted font (i.e., under // the suggested rules, when both operands are multi-character identifiers). - nsresult NS_NewMathMLmoFrame(nsIFrame** aNewFrame) { @@ -119,8 +118,7 @@ nsMathMLmoFrame::Paint(nsIPresContext& aPresContext, NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { rv = mMathMLChar.Paint(aPresContext, aRenderingContext, - mStyleContext, - mCharOffset); + mStyleContext); } else { // let the base class worry about the painting rv = nsMathMLContainerFrame::Paint(aPresContext, @@ -145,8 +143,6 @@ nsMathMLmoFrame::Init(nsIPresContext& aPresContext, mFlags = 0; mLeftSpace = 0.0f; // .27777f; mRightSpace = 0.0f; // .27777f; - mCharOffset.x = 0; - mCharOffset.y = 0; return rv; } @@ -159,7 +155,7 @@ nsMathMLmoFrame::InitData() nsAutoString aData; // PRInt32 aLength = 0; // kids can be comment-nodes, attribute-nodes, text-nodes... - // we use to DOM to ensure that we only look at text-nodes... + // we use the DOM to ensure that we only look at text-nodes... PRInt32 numKids; mContent->ChildCount(numKids); for (PRInt32 kid=0; kid 0) { -// mLeftSpace = mRightSpace = 0; -// } - + if (mScriptLevel > 0) { + mLeftSpace /= 2.0f; + mRightSpace /= 2.0f; + } // XXX Factor all this in nsMathMLAttributes.cpp @@ -305,10 +301,11 @@ nsMathMLmoFrame::InitData() // On input - it contains our current size // On output - the same size or the new size that we want NS_IMETHODIMP -nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize) +nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize) { if (0 == mFlags) { // first time... InitData(); @@ -319,51 +316,50 @@ nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext, (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); nscoord em = NSToCoordRound(float(aFont->mFont.size)); - mCharOffset.x = nscoord( mLeftSpace * em ); - mCharOffset.y = 0; - - // check if it makes sense to stretch - if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags) && - ((NS_MATHML_OPERATOR_IS_FENCE(mFlags) && - NS_STRETCH_DIRECTION_VERTICAL == aStretchDirection) || - (NS_MATHML_OPERATOR_IS_ACCENT(mFlags) && - NS_STRETCH_DIRECTION_HORIZONTAL == aStretchDirection))) { - - mCharOffset.y = aContainerSize.ascent - - aDesiredStretchSize.ascent; // XXX temp hack + nscoord dx = nscoord( mLeftSpace * em ); + nscoord dy = 0; + // see if it is okay to stretch + if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { nsCharMetrics old(aDesiredStretchSize); - // let the MathMLChar stretch itself... - mMathMLChar.Stretch(aPresContext, mStyleContext, aStretchDirection, + mMathMLChar.Stretch(aPresContext, aRenderingContext, + mStyleContext, aStretchDirection, aContainerSize, aDesiredStretchSize); if (old == aDesiredStretchSize) { // hasn't changed ! mFlags &= ~NS_MATHML_OPERATOR_MUTABLE; - mCharOffset.y = 0; + } + else { + nscoord gap; + if (aDesiredStretchSize == NS_STRETCH_DIRECTION_VERTICAL) { + gap = aContainerSize.ascent - aDesiredStretchSize.ascent; + if (0 < gap) dy += gap; + } else if (aDesiredStretchSize == NS_STRETCH_DIRECTION_HORIZONTAL) { + gap = (aContainerSize.width - aDesiredStretchSize.width)/2; + if (0 < gap) dx += gap; + } + mMathMLChar.SetRect(nsRect(dx, dy, aDesiredStretchSize.width, + aDesiredStretchSize.height)); } } - else { - mFlags &= ~NS_MATHML_OPERATOR_MUTABLE; - } - // account the spacing - aDesiredStretchSize.width += nscoord( (mLeftSpace + mRightSpace) * em ); - - // adjust the offsets of our children to leave the spacing - if (0 < mCharOffset.x || 0 < mCharOffset.y) { + // adjust our children's offsets to leave the spacing + if (0 < dx || 0 < dy) { nsRect rect; - nscoord dx = mCharOffset.x; nsIFrame* childFrame = mFrames.FirstChild(); while (nsnull != childFrame) { if (!IsOnlyWhitespace(childFrame)) { childFrame->GetRect(rect); - childFrame->MoveTo(&aPresContext, dx, rect.y + mCharOffset.y); + childFrame->MoveTo(&aPresContext, rect.x + dx, rect.y + dy); dx += rect.width; } childFrame->GetNextSibling(&childFrame); } } + // account the spacing + aDesiredStretchSize.width += nscoord( (mLeftSpace + mRightSpace) * em ); + return NS_OK; } diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h index 35a04b2e119..bd6b55f9814 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLmoFrame.h @@ -50,10 +50,11 @@ public: // This method is called by the parent frame to ask // to stretch itself. NS_IMETHOD - Stretch(nsIPresContext& aPresContext, - nsStretchDirection aStretchDirection, - nsCharMetrics& aContainerSize, - nsCharMetrics& aDesiredStretchSize); + Stretch(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + nsStretchDirection aStretchDirection, + nsCharMetrics& aContainerSize, + nsCharMetrics& aDesiredStretchSize); // helper method to lookup the operator dictionary and initialize our member data void InitData(); @@ -68,7 +69,6 @@ protected: nsOperatorFlags mFlags; float mLeftSpace; float mRightSpace; - nsPoint mCharOffset; }; #endif /* nsMathMLmoFrame_h___ */ diff --git a/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp index f4d110015d2..3b6a6b1ad87 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmoverFrame.cpp @@ -115,6 +115,29 @@ nsMathMLmoverFrame::Reflow(nsIPresContext& aPresContext, rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } + aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); + + ///////////// + // Ask stretchy children to stretch themselves + + nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; + nsCharMetrics parentSize(aDesiredSize); + for (PRInt32 i = 0; i < count; i++) { + ////////// + // Stretch ... + // Only directed at frames that implement the nsIMathMLFrame interface + nsIMathMLFrame* aMathMLFrame = nsnull; + rv = child[i]->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + nsCharMetrics childSize(rect[i].x, rect[i].y, rect[i].width, rect[i].height); + nsIRenderingContext& renderingContext = *aReflowState.rendContext; + aMathMLFrame->Stretch(aPresContext, renderingContext, + stretchDir, parentSize, childSize); + // store the updated metrics + rect[i] = nsRect(childSize.descent, childSize.ascent, + childSize.width, childSize.height); + } + } ////////////////// // Place Children diff --git a/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp index 6700f14bbf2..aafe8941c37 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmunderFrame.cpp @@ -116,6 +116,29 @@ nsMathMLmunderFrame::Reflow(nsIPresContext& aPresContext, rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } + aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); + + ///////////// + // Ask stretchy children to stretch themselves + + nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; + nsCharMetrics parentSize(aDesiredSize); + for (PRInt32 i = 0; i < count; i++) { + ////////// + // Stretch ... + // Only directed at frames that implement the nsIMathMLFrame interface + nsIMathMLFrame* aMathMLFrame = nsnull; + rv = child[i]->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + nsCharMetrics childSize(rect[i].x, rect[i].y, rect[i].width, rect[i].height); + nsIRenderingContext& renderingContext = *aReflowState.rendContext; + aMathMLFrame->Stretch(aPresContext, renderingContext, + stretchDir, parentSize, childSize); + // store the updated metrics + rect[i] = nsRect(childSize.descent, childSize.ascent, + childSize.width, childSize.height); + } + } ////////////////// // Place Children diff --git a/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp index c75e8d9694b..debce57bc5d 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp @@ -123,6 +123,28 @@ nsMathMLmunderoverFrame::Reflow(nsIPresContext& aPresContext, NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } + ///////////// + // Ask stretchy children to stretch themselves + + nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; + nsCharMetrics parentSize(aDesiredSize); + for (PRInt32 i = 0; i < count; i++) { + ////////// + // Stretch ... + // Only directed at frames that implement the nsIMathMLFrame interface + nsIMathMLFrame* aMathMLFrame = nsnull; + rv = child[i]->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + nsCharMetrics childSize(rect[i].x, rect[i].y, rect[i].width, rect[i].height); + nsIRenderingContext& renderingContext = *aReflowState.rendContext; + aMathMLFrame->Stretch(aPresContext, renderingContext, + stretchDir, parentSize, childSize); + // store the updated metrics + rect[i] = nsRect(childSize.descent, childSize.ascent, + childSize.width, childSize.height); + } + } + ////////////////// // Place Children