diff --git a/layout/mathml/base/src/Makefile.in b/layout/mathml/base/src/Makefile.in index a7908cc3bd97..c3cfdc6866f1 100644 --- a/layout/mathml/base/src/Makefile.in +++ b/layout/mathml/base/src/Makefile.in @@ -50,8 +50,8 @@ CPPSRCS = nsMathMLChar.cpp \ nsMathMLmsubsupFrame.cpp \ nsMathMLmmultiscriptsFrame.cpp \ nsMathMLmiFrame.cpp \ - nsMathMLmnFrame.cpp \ - nsMathMLmtdFrame.cpp \ + nsMathMLmtextFrame.cpp \ + nsMathMLmtableFrame.cpp \ nsMathMLmoFrame.cpp \ nsMathMLmunderFrame.cpp \ nsMathMLmoverFrame.cpp \ diff --git a/layout/mathml/base/src/makefile.win b/layout/mathml/base/src/makefile.win index f7ed9551e49a..4be051032284 100644 --- a/layout/mathml/base/src/makefile.win +++ b/layout/mathml/base/src/makefile.win @@ -36,11 +36,11 @@ CPPSRCS= nsMathMLChar.cpp \ nsMathMLmfracFrame.cpp \ nsMathMLmsubFrame.cpp \ nsMathMLmiFrame.cpp \ - nsMathMLmnFrame.cpp \ + nsMathMLmtextFrame.cpp \ nsMathMLmsubsupFrame.cpp \ nsMathMLmmultiscriptsFrame.cpp \ nsMathMLmsupFrame.cpp \ - nsMathMLmtdFrame.cpp \ + nsMathMLmtableFrame.cpp \ nsMathMLmoFrame.cpp \ nsMathMLmunderFrame.cpp \ nsMathMLmoverFrame.cpp \ @@ -62,11 +62,11 @@ CPP_OBJS= .\$(OBJDIR)\nsMathMLChar.obj \ .\$(OBJDIR)\nsMathMLmfracFrame.obj \ .\$(OBJDIR)\nsMathMLmsubFrame.obj \ .\$(OBJDIR)\nsMathMLmiFrame.obj \ - .\$(OBJDIR)\nsMathMLmnFrame.obj \ + .\$(OBJDIR)\nsMathMLmtextFrame.obj \ .\$(OBJDIR)\nsMathMLmsubsupFrame.obj \ .\$(OBJDIR)\nsMathMLmmultiscriptsFrame.obj \ .\$(OBJDIR)\nsMathMLmsupFrame.obj \ - .\$(OBJDIR)\nsMathMLmtdFrame.obj \ + .\$(OBJDIR)\nsMathMLmtableFrame.obj \ .\$(OBJDIR)\nsMathMLmoFrame.obj \ .\$(OBJDIR)\nsMathMLmunderFrame.obj \ .\$(OBJDIR)\nsMathMLmoverFrame.obj \ diff --git a/layout/mathml/base/src/nsIMathMLFrame.h b/layout/mathml/base/src/nsIMathMLFrame.h index 27b64a3813cc..b687e5b455de 100644 --- a/layout/mathml/base/src/nsIMathMLFrame.h +++ b/layout/mathml/base/src/nsIMathMLFrame.h @@ -18,7 +18,7 @@ * Contributor(s): * Roger B. Sidje */ - +#define SHOW_BOUNDING_BOX 1 #ifndef nsIMathMLFrame_h___ #define nsIMathMLFrame_h___ @@ -81,14 +81,14 @@ public: * the stretched frame. Only member data of the struct that are * relevant to the direction are used (the rest is ignored). * @param aDesiredStretchSize [in/out] On input the current size - * size of the frame, on output the size after stretching. + * of the frame, on output the size after stretching. */ NS_IMETHOD Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize) = 0; + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredStretchSize) = 0; #if 0 NS_IMETHOD @@ -187,20 +187,23 @@ public: SetPresentationData(const nsPresentationData& aPresentationData) = 0; /* UpdatePresentationData : - * Increments the scriptlevel of the frame, and set its displaystyle. + * Increments the scriptlevel of the frame, and + * sets its displaystyle and compression flags. * Note that is the only tag which allows to set * * to reset or increment the scriptlevel in a manual way. - * Therefore has its peculiar version of this method. + * Therefore has its own peculiar version of this method. */ NS_IMETHOD UpdatePresentationData(PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) = 0; + PRBool aDisplayStyle, + PRBool aCompressed) = 0; /* UpdatePresentationDataFromChildAt : - * Increments the scriplevel and set the display level on the whole tree. - * For child frames at: aIndex, aIndex+1, aIndex+2, etc, this method set - * their mDisplayStyle to aDisplayStyle and increment their mScriptLevel + * Increments the scriplevel and + * sets the displaystyle and compression flags on the whole tree. + * For child frames at: aIndex, aIndex+1, aIndex+2, etc, this method sets + * their displaystyle and compressed flags, 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 @@ -210,57 +213,8 @@ public: NS_IMETHOD UpdatePresentationDataFromChildAt(PRInt32 aIndex, PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) = 0; -}; - -/* Structure used for stretching a frame. */ -struct nsStretchMetrics { -// nscoord leading; - nscoord descent, ascent; - nscoord width, height; - float leftSpace, rightSpace; - - nsStretchMetrics(nscoord aDescent = 0, - nscoord aAscent = 0, - nscoord aWidth = 0, - nscoord aHeight = 0, - float aLeftSpace = 0.0f, - float aRightSpace = 0.0f) { - width = aWidth; - height = aHeight; - ascent = aAscent; - descent = aDescent; - leftSpace = aLeftSpace; - rightSpace = aRightSpace; - } - - nsStretchMetrics(const nsStretchMetrics& aStretchMetrics) { - width = aStretchMetrics.width; - height = aStretchMetrics.height; - ascent = aStretchMetrics.ascent; - descent = aStretchMetrics.descent; - leftSpace = aStretchMetrics.leftSpace; - rightSpace = aStretchMetrics.rightSpace; - } - - nsStretchMetrics(const nsHTMLReflowMetrics& aReflowMetrics) { - width = aReflowMetrics.width; - height = aReflowMetrics.height; - ascent = aReflowMetrics.ascent; - descent = aReflowMetrics.descent; - leftSpace = 0.0f; - rightSpace = 0.0f; - } - - PRBool - operator == (const nsStretchMetrics& aStretchMetrics) { - return (width == aStretchMetrics.width && - height == aStretchMetrics.height && - ascent == aStretchMetrics.ascent && - descent == aStretchMetrics.descent && - leftSpace == aStretchMetrics.leftSpace && - rightSpace == aStretchMetrics.rightSpace); - } + PRBool aDisplayStyle, + PRBool aCompressed) = 0; }; // struct used by a frame to modulate its presentation @@ -283,7 +237,7 @@ struct nsEmbellishData { 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; + float leftSpace, rightSpace; nsEmbellishData() { @@ -291,7 +245,7 @@ struct nsEmbellishData { firstChild = nsnull; core = nsnull; direction = NS_STRETCH_DIRECTION_UNSUPPORTED; - leftSpace = rightSpace = 0; + leftSpace = rightSpace = 0.0f; } }; @@ -328,16 +282,21 @@ struct nsEmbellishData { // an accentunder frame #define NS_MATHML_ACCENTUNDER 0x00000020 -// This bit is set if the frame is , or +// This bit is set if the frame is an , or // whose base frame is a frame (or an embellished container with // a core ) for which the movablelimits attribute is set to true #define NS_MATHML_MOVABLELIMITS 0x00000040 +// This bit is set when the frame cannot be formatted due to an +// error (e.g., invalid markup such as a without an overscript). +// When set, a visual feedback will be provided to the user. +#define NS_MATHML_ERROR 0x80000000 + // This bit is used for visual debug. When set, the bounding box -// of your frame is painted. You should therefore ensure that you -// have properly filled your mReference and mBoundingMetrics in +// of your frame is painted. This visual debug enable to ensure that +// you have properly filled your mReference and mBoundingMetrics in // Place(). -#define NS_MATHML_SHOW_BOUNDING_METRICS 0x80000000 +#define NS_MATHML_SHOW_BOUNDING_METRICS 0x40000000 // Macros that retrieve those bits #define NS_MATHML_IS_DISPLAYSTYLE(_flags) \ @@ -361,6 +320,9 @@ struct nsEmbellishData { #define NS_MATHML_IS_MOVABLELIMITS(_flags) \ (NS_MATHML_MOVABLELIMITS == ((_flags) & NS_MATHML_MOVABLELIMITS)) +#define NS_MATHML_HAS_ERROR(_flags) \ + (NS_MATHML_ERROR == ((_flags) & NS_MATHML_ERROR)) + #define NS_MATHML_PAINT_BOUNDING_METRICS(_flags) \ (NS_MATHML_SHOW_BOUNDING_METRICS == ((_flags) & NS_MATHML_SHOW_BOUNDING_METRICS)) @@ -369,28 +331,30 @@ struct nsEmbellishData { // in their relevant situation as they become available // This bit is set if the frame is an embellished operator. -#define NS_MATHML_EMBELLISH_OPERATOR 0x00000001 +#define NS_MATHML_EMBELLISH_OPERATOR 0x00000001 -// This bit is set if the frame is an embellished container that -// will fire a stretch command on its first (non-empty) child. -#define NS_MATHML_STRETCH_FIRST_CHILD NS_MATHML_EMBELLISH_OPERATOR +// This bit is set if the frame will fire a vertical stretch +// command on all its (non-empty) children. +// Tags like (or an inferred mrow), mpadded, etc, will fire a +// vertical stretch command on all their non-empty children +#define NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY 0x00000002 -// This bit is set if the frame will fire a stretch command on all -// its (non-empty) children. -// Tags like (or an inferred mrow), munderover, etc, -// will fire a stretch command on all their non-empty children -#define NS_MATHML_STRETCH_ALL_CHILDREN 0x00000002 +// This bit is set if the frame will fire a horizontal stretch +// command on all its (non-empty) children. +// Tags like munder, mover, munderover, will fire a +// horizontal stretch command on all their non-empty children +#define NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY 0x00000004 // This bit is set if the frame is an frame that should behave -// like an accent -#define NS_MATHML_EMBELLISH_ACCENT 0x00000004 +// like an accent XXX since it is specific, use NS_MATHML_EMBELLISH_MO_ACCENT instead? +#define NS_MATHML_EMBELLISH_ACCENT 0x00000008 // This bit is set if the frame is an frame with the movablelimits -// attribute set to true -#define NS_MATHML_EMBELLISH_MOVABLELIMITS 0x00000008 +// attribute set to true XXX since it is specific, use NS_MATHML_EMBELLISH_MO_MOVABLELIMITS instead? +#define NS_MATHML_EMBELLISH_MOVABLELIMITS 0x00000010 // a bit used for debug -#define NS_MATHML_STRETCH_DONE 0x80000000 +#define NS_MATHML_STRETCH_DONE 0x80000000 // Macros that retrieve those bits @@ -398,11 +362,11 @@ struct nsEmbellishData { #define NS_MATHML_IS_EMBELLISH_OPERATOR(_flags) \ (NS_MATHML_EMBELLISH_OPERATOR == ((_flags) & NS_MATHML_EMBELLISH_OPERATOR)) -#define NS_MATHML_WILL_STRETCH_FIRST_CHILD(_flags) \ - (NS_MATHML_STRETCH_FIRST_CHILD == ((_flags) & NS_MATHML_STRETCH_FIRST_CHILD)) +#define NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(_flags) \ + (NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY == ((_flags) & NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY)) -#define NS_MATHML_WILL_STRETCH_ALL_CHILDREN(_flags) \ - (NS_MATHML_STRETCH_ALL_CHILDREN == ((_flags) & NS_MATHML_STRETCH_ALL_CHILDREN)) +#define NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(_flags) \ + (NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY == ((_flags) & NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY)) #define NS_MATHML_STRETCH_WAS_DONE(_flags) \ (NS_MATHML_STRETCH_DONE == ((_flags) & NS_MATHML_STRETCH_DONE)) diff --git a/layout/mathml/base/src/nsMathMLChar.cpp b/layout/mathml/base/src/nsMathMLChar.cpp index 57b7726a8ddd..b12820be6165 100644 --- a/layout/mathml/base/src/nsMathMLChar.cpp +++ b/layout/mathml/base/src/nsMathMLChar.cpp @@ -3,19 +3,19 @@ * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ - * + * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. - * + * * The Original Code is Mozilla MathML Project. - * - * The Initial Developer of the Original Code is The University Of + * + * The Initial Developer of the Original Code is The University Of * Queensland. Portions created by The University Of Queensland are * Copyright (C) 1999 The University Of Queensland. All Rights Reserved. - * - * Contributor(s): + * + * Contributor(s): * Roger B. Sidje * Shyjan Mahamud */ @@ -37,699 +37,1158 @@ #include "nsIFontMetrics.h" #include "nsStyleUtil.h" +#include "nsIDeviceContext.h" +#include "nsCSSRendering.h" +#include "nsQuickSort.h" + #include "nsMathMLOperators.h" #include "nsMathMLChar.h" +// List of all stretchy MathML chars with their attributes -------------- +// ---------------------------------------------------------------------- + +struct nsCharInfo { + PRUnichar mUnicode; + PRInt32 mDirection; + nsGlyphTable* mGlyphTable; // placeholder to cache the table with the smallest glue +}; + +nsCharInfo gCharInfo[] = { +#define WANT_CHAR_INFO + #include "nsMathMLCharList.h" +#undef WANT_CHAR_INFO +}; + +// ---------------------------------------------------------------------- +// nsGlyphTable is a class that provides an interface for accessing glyphs +// of stretchy chars. It acts like a table that stores the variants of bigger +// sizes (if any) and the partial glyphs needed to build extensible symbols. +// An instance of nsGlyphTable is associated to one font. // -// nsMathMLChar implementation -// +// A char for which nsGlyphTable::Has(aChar) is true means that the table +// contains some glyphs (bigger and/or partial) that can be used to render +// the char. Bigger sizes (if any) of the char can then be retrieved with +// BigOf(aSize). Partial glyphs can be retrieved with TopOf(), GlueOf(), etc. +// ---------------------------------------------------------------------- -// Table of extensible chars in a suitable format for algorithmic purpose -// XXX Error-prone stuff. See how it can be automated. +// A table consists of "nsGlyphCode"s which are viewed either as Unicode +// points or as direct glyph indices, depending on the type of the table. +// XXX The latter is not yet supported. -/* 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. +// XXX There are many assertions in the code to ensure that callers +// write correct/efficient/speedy code. As a rule of thumb, you should +// ckeck for Has(aChar) prior to using a char within a glyphtable. - Another separate table, gMathMLCharIndex[], is used to store - pointers to the beginning of each section. +#define NS_TABLE_TYPE_UNICODE 0 +#define NS_TABLE_TYPE_GLYPH_INDEX 1 - Three steps are needed to extend the table: - ---------------------------------------=--- - 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, - 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. - -// XXX The Stretching doesn't align the glyphs in italic style. Need to -// force the style to normal before starting to stretch. - -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 - //Section for: square-root bar - 0x00AF, // RADICAL EXTENDER # radicalex (CUS) -- formerly 0xF8E5 - - 0x0000, // That's all folks ... - //Block of partial glyphs in the order top/left, middle, bottom/right, glue - 0x00AF, // RADICAL EXTENDER # radicalex (CUS) - 0x00AF, // RADICAL EXTENDER # radicalex (CUS) - 0x00AF, // RADICAL EXTENDER # radicalex (CUS) - 0x00AF, // RADICAL EXTENDER # radicalex (CUS) - - //------------ - //index = 72 - //Section for: vertical bar (0x2223) - '|', - - 0x0000, // That's all folks ... - //Block of partial glyphs in the order top/left, middle, bottom/right, glue - '|', - '|', - '|', - '|', - - //------------ - //index = 78 - //end of table ... - 0x0000, +struct nsCharData { + nsMathMLCharEnum mEnum; + PRInt32 mIndex; }; -// 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_OverBar, - 72, // eMathMLChar_VerticalBar, - 78, // eMathMLChar_Sqrt, -- placeholder for now - 78, // safeguard, *must* always point at the *end* of gMathMLCharGlyph[] +class nsGlyphTable { +public: + nsGlyphTable(PRInt32 aType, + nsString& aFontName, + nsCharData* aCharArray, + PRInt32 aCharCount, + nsGlyphCode* aGlyphArray, + PRInt32 aGlyphCount) + { + mType = aType; + mFontName = aFontName; + mCharArray = aCharArray; + mCharCount = aCharCount; + mGlyphArray = aGlyphArray; + mGlyphCount = aGlyphCount; + mNextTable = nsnull; + mIsSorted = PR_FALSE; + mCache = mCharArray; + } + + ~nsGlyphTable() // not a virtual destructor: this class is not intended to be subclassed + { + } + + void GetFontName(nsString& aFontName) + { + aFontName = mFontName; + } + + nsGlyphTable* GetNextTable(void) + { + return mNextTable; + } + + void SetNextTable(nsGlyphTable* aNextTable) + { + mNextTable = aNextTable; + } + + PRBool Has(nsMathMLCharEnum aEnum) + { + return PRBool(IndexOf(aEnum) < mGlyphCount); + } + +#ifdef NS_DEBUG + // a linear search function for debug mode only + PRBool Has(nsGlyphCode aGlyphCode) + { + NS_ASSERTION(aGlyphCode, "bad usage of a glyph table"); + for (PRInt32 i = 0; i < mGlyphCount; i++) + if (mGlyphArray[i] == aGlyphCode) return PR_TRUE; + return PR_FALSE; + } +#endif + + nsGlyphCode TopOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(Has(aEnum), "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum)]; + } + + nsGlyphCode MiddleOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(IndexOf(aEnum) + 1 < mGlyphCount, "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum) + 1]; + } + + nsGlyphCode BottomOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(IndexOf(aEnum) + 2 < mGlyphCount, "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum) + 2]; + } + + nsGlyphCode GlueOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(IndexOf(aEnum) + 3 < mGlyphCount, "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum) + 3]; + } + + nsGlyphCode BigOf(nsMathMLCharEnum aEnum, PRInt32 aSize) + { + NS_ASSERTION(aSize>=0 && IndexOf(aEnum) + 4 + aSize < mGlyphCount, "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum) + 4 + aSize]; + } + + nsGlyphCode LeftOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(Has(aEnum), "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum)]; + } + + nsGlyphCode RightOf(nsMathMLCharEnum aEnum) + { + NS_ASSERTION(IndexOf(aEnum) + 2 < mGlyphCount, "bad usage of a glyph table"); + return mGlyphArray[IndexOf(aEnum) + 2]; + } + + // use these to measure/render a glyph that comes from this table + nsresult GetBoundingMetrics(nsIRenderingContext& aRenderingContext, + nsGlyphCode aGlyphCode, + nsBoundingMetrics& aBoundingMetrics) + { +#ifdef NS_DEBUG + NS_ASSERTION(Has(aGlyphCode), "bad usage of a glyph table"); +#endif + if (mType == NS_TABLE_TYPE_UNICODE) + return aRenderingContext.GetBoundingMetrics((PRUnichar*)&aGlyphCode, PRUint32(1), aBoundingMetrics); + // else mType == NS_TABLE_TYPE_GLYPH_INDEX + return NS_ERROR_NOT_IMPLEMENTED; + // return aRenderingContext.GetBoundingMetricsI((PRUint16*)&aGlyphCode, PRUint32(1), aBoundingMetrics); + } + + void + DrawGlyph(nsIRenderingContext& aRenderingContext, + nsGlyphCode aGlyphCode, + nscoord aX, + nscoord aY, + nsRect* aClipRect = nsnull); + +private: + PRInt32 mType; // NS_TABLE_TYPE_UNICODE + // NS_TABLE_TYPE_GLYPH_INDEX + + nsString mFontName; // The name of the font associated to this table. + + PRInt32 mCharCount; + nsCharData* mCharArray; // All the stretchy chars supported by the font associated to + // this table. + + PRInt32 mGlyphCount; + nsGlyphCode* mGlyphArray; // For each stretchy char in this font, this array contains + // the unicode points (or glyph-indices) of the partial glyphs + // needed to build extensible symbols, and of the readily-available + // variants of bigger sizes (if any) that the font already contains. + + nsGlyphTable* mNextTable; // Pointer to another table --to enable walking/trying several fonts. + + PRBool mIsSorted; // mCharArray is kept sorted so that we can speedily lookup + // the index of a char using binary search. + + nsCharData* mCache; // For speedy re-use, always cache the last char used in IndexOf() ... + + // --------------------------- + // helper functions + + // compare function for doing a quick sort of our chars in ascending order + static int compare( const void *a, const void *b , void *unused) + { + return (PRInt32)(((nsCharData*)a)->mEnum) - (PRInt32)(((nsCharData*)b)->mEnum); + } + + // we use this a lot... to lookup the starting index (in mGlyphArray) of the + // list of glyphs corresponding to a char. This list consists of the 4 partial + // glyphs: top (or left), middle, bottom (or right), glue, followed by the + // bigger sizes (if any): size0, ..., size{N-1}, *and* the null separator. + // (Note: retrieval with BigOf(aSize) is 0-based, BigOf(0) gives the first + // glyph size which is the normal size.) + PRInt32 IndexOf(nsMathMLCharEnum aEnum); }; -static const PRInt32 kMathMLChar[] = { -#define MATHML_CHAR(_name, _value, _direction) eMathMLChar_##_name, _value, _direction, -#include "nsMathMLCharList.h" -#undef MATHML_CHAR +PRInt32 +nsGlyphTable::IndexOf(nsMathMLCharEnum aEnum) +{ + // quick return if it is identical with our cache ... + if (mCache->mEnum == aEnum) return mCache->mIndex; + // quick sort if this is the first call ... + if (!mIsSorted) { + NS_QuickSort(mCharArray, mCharCount, sizeof(nsCharData), compare, nsnull); + mIsSorted = PR_TRUE; + } + // binary search ... + PRInt32 low = 0; + PRInt32 high = mCharCount-1; + while (low <= high) { + PRInt32 middle = (low + high) >> 1; + PRInt32 result = (PRInt32)aEnum - (PRInt32)mCharArray[middle].mEnum; + if (result == 0) { + mCache = &mCharArray[middle]; // update our cache ... + return mCache->mIndex; + } + if (result > 0) + low = middle + 1; + else + high = middle - 1; + } + return mGlyphCount; +} + +// draw a glyph in a clipped area so that we don't have hairy chars pending outside +void +nsGlyphTable::DrawGlyph(nsIRenderingContext& aRenderingContext, + nsGlyphCode aGlyphCode, + nscoord aX, + nscoord aY, + nsRect* aClipRect) +{ +#ifdef NS_DEBUG + NS_ASSERTION(Has(aGlyphCode), "bad usage of a glyph table"); +#endif + PRBool clipState; + if (aClipRect) { + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(*aClipRect, nsClipCombine_kIntersect, clipState); + } + + if (mType == NS_TABLE_TYPE_UNICODE) + aRenderingContext.DrawString((PRUnichar*)&aGlyphCode, PRUint32(1), aX, aY); + else + NS_ASSERTION(0, "Error *** Not yet implemented"); + //aRenderingContext.DrawStringI((PRUint16*)&aGlyphCode, PRUint32(1), aX, aY); + + if (aClipRect) { + aRenderingContext.PopState(clipState); + } +} + +// Structure used to walk/try all the the glyph tables that we have. +// Glyph tables are singly linked together through their next-table pointer. +// ----------------------------------------------------------------------------------- + +struct nsGlyphTableList { + + nsGlyphTableList(void) + { + mFirstTable = nsnull; + mIsInitialized = PR_FALSE; + } + + PRBool IsInitialized(void) + { + return mIsInitialized; + } + + nsGlyphTable* + FirstTable(void) + { + return mFirstTable; + } + + // Create a list of glyph tables. The list will only select glyph tables that + // are associated to fonts currently installed on the system... + void Init(nsIPresContext* aPresContext, + nsGlyphTable** aGlyphTables); + + // Find a glyph table that has a glyph for a char. + nsGlyphTable* + FindTableFor(nsMathMLCharEnum aCharEnum); + + // ---- + nsGlyphTable* mFirstTable; + PRBool mIsInitialized; }; +void +nsGlyphTableList::Init(nsIPresContext* aPresContext, + nsGlyphTable** aGlyphTables) +{ + NS_ASSERTION(!mIsInitialized, "glyph table list is already initialized"); + mIsInitialized = PR_TRUE; -//--------------------------------------------- + nsCOMPtr deviceContext; + aPresContext->GetDeviceContext(getter_AddRefs(deviceContext)); + + PRBool aliased; + nsAutoString fontName, localName; + nsGlyphTable* lastTable; + nsGlyphTable** glyphTable = aGlyphTables; + + while (*glyphTable) { + // check for existence of the font + (*glyphTable)->GetFontName(fontName); + deviceContext->GetLocalFontName(fontName, localName, aliased); + if (aliased || (NS_OK == deviceContext->CheckFontExistence(localName))) + { + if (mFirstTable == nsnull) { + mFirstTable = lastTable = *glyphTable; + } + else { + lastTable->SetNextTable(*glyphTable); + lastTable = *glyphTable; + } + } + else { // the font is not installed +#ifdef NS_DEBUG + char str[50]; + localName.ToCString(str, sizeof(str)); + printf("WARNING *** Missing the %s font to stretch MathML symbols!\n", str); + printf(" Why don't you install the %s font on your system for a better MathML experience!\n", str); +#endif + } + glyphTable++; + } +} + +nsGlyphTable* +nsGlyphTableList::FindTableFor(nsMathMLCharEnum aCharEnum) +{ + NS_ASSERTION(mIsInitialized, "glyph table list must be initialized first"); + nsGlyphTable* glyphTable = mFirstTable; + while (glyphTable) { + if (glyphTable->Has(aCharEnum)) { + return glyphTable; + } + glyphTable = glyphTable->GetNextTable(); + } + return nsnull; +} + +// ----------------------------------------------------------------------------------- +// Here is the global list of glyph tables that we will be using ... +nsGlyphTableList gGlyphTableList; + +// And this is a dummy glyph table that we will use as a flag for gCharInfo[].mGlyphTable +nsGlyphTable gGlyphTableUNDEFINED(NS_TABLE_TYPE_UNICODE, nsAutoString("UNDEFINED"), + nsnull, 0, nsnull, 0); + + +// Data sets that we have ... + +// ----------------------------------------------------------------------------------- +// Data for strecthy chars that are supported by the Symbol font --------------------- + +static nsCharData gCharDataSymbol[] = { +#define WANT_SYMBOL_DATA +#define WANT_CHAR_DATA + #include "nsMathMLCharList.h" +#undef WANT_CHAR_DATA +#undef WANT_SYMBOL_DATA +}; + +static nsGlyphCode gGlyphCodeSymbol[] = { +#define WANT_SYMBOL_DATA +#define WANT_GLYPH_DATA + #include "nsMathMLCharList.h" +#undef WANT_GLYPH_DATA +#undef WANT_SYMBOL_DATA +}; + +nsGlyphTable gGlyphTableSymbol(NS_TABLE_TYPE_UNICODE, nsAutoString("Symbol"), + gCharDataSymbol, sizeof(gCharDataSymbol) / sizeof(gCharDataSymbol[0]), + gGlyphCodeSymbol, sizeof(gGlyphCodeSymbol) / sizeof(gGlyphCodeSymbol[0])); + +// ----------------------------------------------------------------------------------- +// Data for strecthy chars that are supported by the MT Extra font ------------------- + +static nsCharData gCharDataMTExtra[] = { +#define WANT_MTEXTRA_DATA +#define WANT_CHAR_DATA + #include "nsMathMLCharList.h" +#undef WANT_CHAR_DATA +#undef WANT_MTEXTRA_DATA +}; + +static nsGlyphCode gGlyphCodeMTExtra[] = { +#define WANT_MTEXTRA_DATA +#define WANT_GLYPH_DATA + #include "nsMathMLCharList.h" +#undef WANT_GLYPH_DATA +#undef WANT_MTEXTRA_DATA +}; + +nsGlyphTable gGlyphTableMTExtra(NS_TABLE_TYPE_UNICODE, nsAutoString("MT Extra"), + gCharDataMTExtra, sizeof(gCharDataMTExtra) / sizeof(gCharDataMTExtra[0]), + gGlyphCodeMTExtra, sizeof(gGlyphCodeMTExtra) / sizeof(gGlyphCodeMTExtra[0])); + +// ----------------------------------------------------------------------------------- +// Data for strecthy chars that are supported by TeX's CMEX font --------------------- + +static nsCharData gCharDataCMEX[] = { +#define WANT_CMEX_DATA +#define WANT_CHAR_DATA + #include "nsMathMLCharList.h" +#undef WANT_CHAR_DATA +#undef WANT_CMEX_DATA +}; + +static nsGlyphCode gGlyphCodeCMEX[] = { +#define WANT_CMEX_DATA +#define WANT_GLYPH_DATA + #include "nsMathMLCharList.h" +#undef WANT_GLYPH_DATA +#undef WANT_CMEX_DATA +}; + +nsGlyphTable gGlyphTableCMEX(NS_TABLE_TYPE_UNICODE, nsAutoString("CMEX10"), + gCharDataCMEX, sizeof(gCharDataCMEX) / sizeof(gCharDataCMEX[0]), + gGlyphCodeCMEX, sizeof(gGlyphCodeCMEX) / sizeof(gGlyphCodeCMEX[0])); + +// ----------------------------------------------------------------------------------- +// Data for strecthy chars that are supported by TeX's CMSY font --------------------- + +static nsCharData gCharDataCMSY[] = { +#define WANT_CMSY_DATA +#define WANT_CHAR_DATA + #include "nsMathMLCharList.h" +#undef WANT_CHAR_DATA +#undef WANT_CMSY_DATA +}; + +static nsGlyphCode gGlyphCodeCMSY[] = { +#define WANT_CMSY_DATA +#define WANT_GLYPH_DATA + #include "nsMathMLCharList.h" +#undef WANT_GLYPH_DATA +#undef WANT_CMSY_DATA +}; + +nsGlyphTable gGlyphTableCMSY(NS_TABLE_TYPE_UNICODE, nsAutoString("CMSY10"), + gCharDataCMSY, sizeof(gCharDataCMSY) / sizeof(gCharDataCMSY[0]), + gGlyphCodeCMSY, sizeof(gGlyphCodeCMSY) / sizeof(gGlyphCodeCMSY[0])); + +// ----------------------------------------------------------------------------------- + +// All the glyph tables in order of preference ... +nsGlyphTable* gAllGlyphTables[] = { + &gGlyphTableCMSY, + &gGlyphTableCMEX, + &gGlyphTableMTExtra, + &gGlyphTableSymbol, + + nsnull +}; + +// ----------------------------------------------------------------------------------- +// And now the implementation of nsMathMLChar + +nsresult +nsMathMLChar::GetStyleContext(nsIStyleContext** aStyleContext) const +{ + NS_PRECONDITION(aStyleContext, "null OUT ptr"); + NS_ASSERTION(mStyleContext, "chars shoud always have style context"); + NS_IF_ADDREF(mStyleContext); + *aStyleContext = mStyleContext; + return NS_OK; +} + +nsresult +nsMathMLChar::SetStyleContext(nsIStyleContext* aStyleContext) +{ + NS_PRECONDITION(aStyleContext, "null ptr"); + if (aStyleContext != mStyleContext) { + NS_IF_RELEASE(mStyleContext); + if (aStyleContext) { + mStyleContext = aStyleContext; + NS_ADDREF(aStyleContext); + } + } + return NS_OK; +} // If you call SetData(), it will lookup the enum // of the char and set it for you. void -nsMathMLChar::SetData(nsString& aData) { +nsMathMLChar::SetData(nsIPresContext* aPresContext, + nsString& aData) +{ + if (!gGlyphTableList.IsInitialized()) { + gGlyphTableList.Init(aPresContext, gAllGlyphTables); + for (PRInt32 i = 0; i < eMathMLChar_COUNT; i++) + gCharInfo[i].mGlyphTable = &gGlyphTableUNDEFINED; + } mData = aData; // some assumptions until proven otherwise! + // note that mGlyph is not initialized mEnum = eMathMLChar_DONT_STRETCH; mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; mBoundingMetrics.Clear(); + mGlyphTable = nsnull; // lookup the enum ... if (1 == mData.Length()) { PRUnichar ch = mData[0]; - PRInt32 count = sizeof(kMathMLChar) / sizeof(kMathMLChar[0]); - for (PRInt32 i = 0; i < count; i += 3) { - if (ch == kMathMLChar[i+1]) { - mEnum = nsMathMLCharEnum(kMathMLChar[i]); - mDirection = kMathMLChar[i+2]; - break; + for (PRInt32 i = 0; i < eMathMLChar_COUNT; i++) { + if (ch == gCharInfo[i].mUnicode) { + // found ... + mEnum = nsMathMLCharEnum(i); + mDirection = gCharInfo[i].mDirection; + if (mDirection != NS_STRETCH_DIRECTION_UNSUPPORTED) { + // ... now see if there is a glyph table for us + mGlyphTable = gGlyphTableList.FindTableFor(mEnum); + // don't bother with the streching if there is no glyph table for us... + if (!mGlyphTable) { + gCharInfo[i].mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; // update to never try again + mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; + mEnum = eMathMLChar_DONT_STRETCH; + } +#ifdef NS_DEBUG + else NS_ASSERTION(mGlyphTable->Has(nsGlyphCode(mData[0])), "Something is wrong somewhere"); +#endif + } + return; } } } } -// If you call SetEnum(), it will lookup the actual value +// If you call SetEnum(), it will lookup the actual value // of the char and set it for you. void -nsMathMLChar::SetEnum(nsMathMLCharEnum aEnum) { +nsMathMLChar::SetEnum(nsIPresContext* aPresContext, + nsMathMLCharEnum aEnum) +{ + NS_ASSERTION(aEnum < eMathMLChar_COUNT, "Something is wrong somewhere"); + if (!gGlyphTableList.IsInitialized()) { + gGlyphTableList.Init(aPresContext, gAllGlyphTables); + for (PRInt32 i = 0; i < eMathMLChar_COUNT; i++) + gCharInfo[i].mGlyphTable = &gGlyphTableUNDEFINED; + } mEnum = aEnum; // some assumptions until proven otherwise! + // note that mGlyph is not initialized mData = ""; mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; mBoundingMetrics.Clear(); - // lookup the data ... + mGlyphTable = nsnull; if (mEnum != eMathMLChar_DONT_STRETCH) { - PRInt32 count = sizeof(kMathMLChar) / sizeof(kMathMLChar[0]); - for (PRInt32 i = 0; i < count; i += 3) { - if (mEnum == kMathMLChar[i]) { - mData = PRUnichar(kMathMLChar[i+1]); - mDirection = kMathMLChar[i+2]; - break; + mData = gCharInfo[mEnum].mUnicode; + mDirection = gCharInfo[mEnum].mDirection; + if (mDirection != NS_STRETCH_DIRECTION_UNSUPPORTED) { + // ... now see if there is a glyph table for us + mGlyphTable = gGlyphTableList.FindTableFor(mEnum); + // don't bother with the streching if there is no glyph table for us... + if (!mGlyphTable) { + gCharInfo[mEnum].mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; // update to never try again + mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED; + mEnum = eMathMLChar_DONT_STRETCH; } +#ifdef NS_DEBUG + else NS_ASSERTION(mGlyphTable->Has(nsGlyphCode(mData[0])), "Something is wrong somewhere"); +#endif } + NS_ASSERTION(mData.Length(), "Something is wrong somewhere"); } - NS_ASSERTION(mData.Length(), "Something is wrong somewhere"); } /* 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. + our current size or zero if current size is unknown, on output + the size after stretching. If not stretching is done, and the + input was zero, the output will simply give the default size. 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 + 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 + 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?] + * When built by parts, the char is stretched to *exactly* + fit aContainerSize. 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 +#define SHOW_BORDERS 1 +//#define NOISY_SEARCH 1 -// -NS_IMETHODIMP +// ********************************************************************** +// ********************************************************************** +// ********************************************************************** + +#undef PR_ABS +#define PR_ABS(x) ((x) < 0 ? -(x) : (x)) + +static PRBool +IsSizeOK(nscoord a, nscoord b, PRInt32 aHint) +{ + if (aHint == NS_STRETCH_NORMAL) + return PRBool(float(PR_ABS(a - b)) < 0.15f * float(b)); + else if (aHint == NS_STRETCH_SMALLER) + return PRBool((0.85f * float(b) <= float(a)) && (a <= b)); + else if (aHint == NS_STRETCH_LARGER) + return PRBool(a >= b); + else + return PR_FALSE; +} + +static PRBool +IsSizeBetter(nscoord a, nscoord olda, nscoord b, PRInt32 aHint) +{ + if (0 == olda) + return PR_TRUE; + else if (PR_ABS(a - b) < PR_ABS(olda - b)) + { + if (aHint == NS_STRETCH_NORMAL) + return PR_TRUE; + else if (aHint == NS_STRETCH_SMALLER) + return PRBool(a <= b); + else if (aHint == NS_STRETCH_LARGER) + return PRBool(a >= b); + } + return PR_FALSE; +} + +nsresult nsMathMLChar::Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize) + nsBoundingMetrics& aContainerSize, + nsBoundingMetrics& aDesiredStretchSize, + PRInt32 aStretchHint) { nsresult rv = NS_OK; nsStretchDirection aDirection = aStretchDirection; + //////////////// + // if no specified direction, attempt to stretch in our preferred direction if (aDirection == NS_STRETCH_DIRECTION_DEFAULT) { aDirection = mDirection; } + /////////////// // Set font nsStyleFont font; - aStyleContext->GetStyle(eStyleStruct_Font, font); + mStyleContext->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; } + ////////////// + // set the default bounding metrics + rv = aRenderingContext.GetBoundingMetrics(mData.GetUnicode(), + PRUint32(mData.Length()), + mBoundingMetrics); + if (NS_FAILED(rv)) { + printf ("GetBoundingMetrics failed\n"); + return rv; + } + + ////////////// + // set the default desired metrics for special cases where + // the caller doesn't know the default size + if ((0 == aDesiredStretchSize.width) || + (0 == aDesiredStretchSize.ascent && 0 == aDesiredStretchSize.descent)) + { + aDesiredStretchSize = mBoundingMetrics; + } + + /////////////// + // quickly return if there is nothing special about this char + if (!mGlyphTable || + eMathMLChar_DONT_STRETCH == mEnum || + aDirection != mDirection) { + // ensure that the char later behaves like a normal char + mEnum = eMathMLChar_DONT_STRETCH; // XXX need to reset in dynamic updates return NS_OK; } + // hitting these assertions? + // make sure to clobber-build the MathML directory if nsMathMLCharList.h has changed + NS_ASSERTION(gCharInfo[mEnum].mUnicode == mData[0], "Mystery!"); + NS_ASSERTION(gCharInfo[mEnum].mDirection == mDirection, "Mystery!"); + NS_ASSERTION(gCharInfo[mEnum].mDirection != NS_STRETCH_DIRECTION_UNSUPPORTED, "Mystery!"); + + //////////////// // check the common situations where stretching is not actually needed - // XXX need better criteria 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; } + if (IsSizeOK(aDesiredStretchSize.ascent + aDesiredStretchSize.descent, + aContainerSize.ascent + aContainerSize.descent, + aStretchHint)) { + // ensure that the char later behaves like a normal char + mEnum = eMathMLChar_DONT_STRETCH; // XXX need to reset in dynamic updates 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; } + if (IsSizeOK(aDesiredStretchSize.width, + aContainerSize.width, + aStretchHint)) { + // ensure that the char later behaves like a normal char + mEnum = eMathMLChar_DONT_STRETCH; // XXX need to reset in dynamic updates return NS_OK; } } - -// printf("Container height:%d width:%d ascent:%d descent:%d\n contains height:%d width:%d ascent:%d descent:%d\n", -// aContainerSize.height, aContainerSize.width, aContainerSize.ascent, aContainerSize.descent, -// aDesiredStretchSize.height, aDesiredStretchSize.width, aDesiredStretchSize.ascent, -// aDesiredStretchSize.descent); - - // XXX Note: there are other symbols that just need to slightly - // increase their size, like \Sum - - 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++]; - 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; - - // printf("height:%d width:%d ascent:%d descent:%d\n", - // height, bm.width, bm.ascent, bm.descent); - - // XXX temp hack -- need better criteria - if ((aDirection == NS_STRETCH_DIRECTION_VERTICAL && h > height) || - (aDirection == NS_STRETCH_DIRECTION_HORIZONTAL && w > width)) { - sizeOK = PR_TRUE; - descent = bm.descent; - 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++]; + else { + NS_ASSERTION(0, "What are you doing here?"); + return NS_OK; } - if (!sizeOK) { // see if we can build by parts... - mGlyph = 0; + ////////////////// + // try first to search if there is a glyph of appropriate size ... + + PRInt32 size; + PRBool sizeOK = PR_FALSE; + nsBoundingMetrics bm; + nsGlyphCode ch; + + // this will be the best glyph that we encounter during the search... + nsGlyphCode bestGlyph = mData[0]; // XXX need to also take care of the glyph index case + nsGlyphTable* bestGlyphTable = mGlyphTable; + nsBoundingMetrics bestbm = mBoundingMetrics; + +#ifdef NOISY_SEARCH + printf("Searching a font with a glyph of appropriate size for: 0x%04X:%c\n", + mData[0], mData[0]&0x00FF); +#endif + nsGlyphTable* glyphTable = gGlyphTableList.FirstTable(); + while (glyphTable && !sizeOK) { + if (glyphTable->Has(mEnum) && glyphTable->BigOf(mEnum, 1)) { + // see if this table has a glyph that matches the size +#ifdef NOISY_SEARCH + nsAutoString fontName; + glyphTable->GetFontName(fontName); + char str[50]; + fontName.ToCString(str, sizeof(str)); + printf(" searching in %s ...\n", str); +#endif + size = 1; // size=0 is the char at its normal size + ch = glyphTable->BigOf(mEnum, size++); + while (ch) { + NS_ASSERTION(ch != mData[0], "glyph table incorrectly set -- duplicate found"); + rv = glyphTable->GetBoundingMetrics(aRenderingContext, ch, bm); + if (NS_SUCCEEDED(rv)) { + nscoord h = bm.ascent + bm.descent; + nscoord w = bm.rightBearing - bm.leftBearing; + if ((aDirection == NS_STRETCH_DIRECTION_VERTICAL && + IsSizeOK(h, aContainerSize.ascent + aContainerSize.descent, aStretchHint)) || + (aDirection == NS_STRETCH_DIRECTION_HORIZONTAL && + IsSizeOK(w, aContainerSize.width, aStretchHint))) + { +#ifdef NOISY_SEARCH + printf(" size:%d OK!\n", size-1); +#endif + bestbm = bm; + bestGlyphTable = glyphTable; + bestGlyph = ch; + + sizeOK = PR_TRUE; + break; // get out... + } + if ((aDirection == NS_STRETCH_DIRECTION_VERTICAL && + IsSizeBetter(h, bestbm.ascent + bestbm.descent, + aContainerSize.ascent + aContainerSize.descent, aStretchHint)) || + (aDirection == NS_STRETCH_DIRECTION_HORIZONTAL && + IsSizeBetter(w, bestbm.rightBearing - bestbm.leftBearing, + aContainerSize.width, aStretchHint))) + { +#ifdef NOISY_SEARCH + printf(" size:%d Current best\n", size-1); +#endif + bestGlyphTable = glyphTable; + bestGlyph = ch; + bestbm = bm; + } +#ifdef NOISY_SEARCH + else { + printf(" size:%d Rejected!\n", size-1); + } +#endif + } + ch = glyphTable->BigOf(mEnum, size++); + } + } + glyphTable = glyphTable->GetNextTable(); + } + + ////////////////// + // if no glyph of appropriate size, see if we can build by parts... + // search for the table with the smallest glue + + if (!sizeOK) { +#ifdef NOISY_SEARCH + printf(" searching for the font with the smallest glue\n"); +#endif + if (gCharInfo[mEnum].mGlyphTable == &gGlyphTableUNDEFINED) { // first time + // gCharInfo[mEnum].mGlyphTable is not yet initialized, scan the global list + nscoord sizeGlue = 0; + gCharInfo[mEnum].mGlyphTable = nsnull; // clear the first time flag + glyphTable = gGlyphTableList.FirstTable(); + while (glyphTable) { + if (glyphTable->Has(mEnum) && glyphTable->GlueOf(mEnum)) { + ch = glyphTable->GlueOf(mEnum); + rv = glyphTable->GetBoundingMetrics(aRenderingContext, ch, bm); + if (NS_SUCCEEDED(rv)) { + nscoord size = (aDirection == NS_STRETCH_DIRECTION_VERTICAL) + ? bm.ascent + bm.descent + : bm.rightBearing - bm.leftBearing; + NS_ASSERTION(size, "glue should never be zero *** Erroneous glue in glyph table!"); + if (IsSizeBetter(size, sizeGlue, 0, NS_STRETCH_SMALLER)) { + // current glyph table is the one with the smallest glue, update the cache... + gCharInfo[mEnum].mGlyphTable = glyphTable; + sizeGlue = size; + } + } + } + glyphTable = glyphTable->GetNextTable(); + } +#ifdef NOISY_SEARCH + if (gCharInfo[mEnum].mGlyphTable) { + nsAutoString fontName; + gCharInfo[mEnum].mGlyphTable->GetFontName(fontName); + char str[50]; + fontName.ToCString(str, sizeof(str)); + printf(" Found %s font in the global list\n", str); + } +#endif + } +#ifdef NOISY_SEARCH + if (gCharInfo[mEnum].mGlyphTable) { + nsAutoString fontName; + gCharInfo[mEnum].mGlyphTable->GetFontName(fontName); + char str[50]; + fontName.ToCString(str, sizeof(str)); + printf(" Found %s font in the cache\n", str); + } + else { + printf(" no font found\n"); + } +#endif + } + + if (sizeOK || !gCharInfo[mEnum].mGlyphTable) { + // if we enter here, it means either that the best glyph encountered + // is of appropriate size, or that it is not possible to build by + // parts (i.e., a font with a glue wasn't found). + // so return the best glyph that we have + } + else { + // we are going to build by parts... + // using the glyph table with the smallest glue + glyphTable = gCharInfo[mEnum].mGlyphTable; + PRInt32 i; - nscoord a, d; - h = w = a = d = 0; - float flex[3] = {0.7f, 0.3f, 0.7f}; // XXX hack! + + // XXX hack! should vary when some parts are not there + // XXX another possibility is also to base the acceptance criteria on the + // amount of overlap between the bounding boxes that SHOW_BORDER presents + float flex[3] = {0.7f, 0.3f, 0.7f}; - // get metrics data to be re-used later nsBoundingMetrics bmdata[4]; for (i = 0; i < 4; i++) { - 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; + switch (i) { + case 0: ch = glyphTable->TopOf(mEnum); break; + case 1: ch = glyphTable->MiddleOf(mEnum); break; + case 2: ch = glyphTable->BottomOf(mEnum); break; + case 3: ch = glyphTable->GlueOf(mEnum); break; + } + if (!ch) ch = glyphTable->GlueOf(mEnum); // empty slots are filled with the glue + rv = glyphTable->GetBoundingMetrics(aRenderingContext, ch, bm); + if (NS_FAILED(rv)) { + printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); + return rv; } bmdata[i] = bm; } if (aDirection == 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; - + nscoord lbearing = bmdata[0].leftBearing; + nscoord rbearing = bmdata[0].rightBearing; + nscoord h = 0; + nscoord w = bmdata[0].width; for (i = 0; i < 4; i++) { bm = bmdata[i]; if (w < bm.width) w = bm.width; if (i < 3) { - h += nscoord(flex[i]*(bm.ascent+bm.descent)); // sum heights of the parts... + 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 (lbearing > bm.leftBearing) lbearing = bm.leftBearing; + if (rbearing < bm.rightBearing) rbearing = 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; + if (h <= aContainerSize.ascent + aContainerSize.descent) { + // can nicely fit in the available space... + bestbm.width = w; + bestbm.ascent = aContainerSize.ascent; + bestbm.descent = aContainerSize.descent; + bestbm.leftBearing = lbearing; + bestbm.rightBearing = rbearing; + // reset + bestGlyph = 0; // this will tell paint to build by parts + bestGlyphTable = glyphTable; + } + else { + // sum of parts doesn't fit in the space... will use a single glyph + // will use the best glyph encountered earlier } } else if (aDirection == 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; - + nscoord a = bmdata[0].ascent; + nscoord d = bmdata[0].descent; + nscoord w = 0; for (i = 0; i < 4; i++) { - bm = bmdata[i]; - if (0 == i) bm0 = bm; + bm = bmdata[i]; 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... - // compute and cache our bounding metrics (horizontal stacking) - if (0 == i) - mBoundingMetrics = bm; - else - mBoundingMetrics += bm; + w += nscoord(flex[i]*(bm.rightBearing - bm.leftBearing)); // sum widths of the parts... } } - 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; - mBoundingMetrics.leftBearing = 0; - mBoundingMetrics.rightBearing = 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; + if (w <= aContainerSize.width) { + // can nicely fit in the available space... + bestbm.width = aContainerSize.width; + bestbm.ascent = a; + bestbm.descent = d; + bestbm.leftBearing = 0; + bestbm.rightBearing = aContainerSize.width; + // reset + bestGlyph = 0; // this will tell paint to build by parts + bestGlyphTable = glyphTable; + } + else { + // sum of parts doesn't fit in the space... will use a single glyph + // will use the best glyph encountered earlier } } } - aDesiredStretchSize.width = width; - aDesiredStretchSize.height = height; - aDesiredStretchSize.ascent = ascent; - aDesiredStretchSize.descent = descent; - + if (bestGlyph == mData[0]) { // nothing happened + // ensure that the char behaves like a normal char + mEnum = eMathMLChar_DONT_STRETCH; // XXX need to reset in dynamic updates + } + else { + // will stretch + mGlyph = bestGlyph; // note that this can be 0 in order to tell paint to build by parts + mGlyphTable = bestGlyphTable; + mBoundingMetrics = bestbm; + aDesiredStretchSize = bestbm; + } return NS_OK; } -NS_IMETHODIMP +nsresult nsMathMLChar::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext) + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nsIFrame* aForFrame) { - nsresult rv = NS_OK; - - nsStyleFont font; + nsStyleDisplay display; nsStyleColor color; - aStyleContext->GetStyle(eStyleStruct_Font, font); - aStyleContext->GetStyle(eStyleStruct_Color, color); + mStyleContext->GetStyle(eStyleStruct_Display, display); + mStyleContext->GetStyle(eStyleStruct_Color, color); - // Set color and font ... - aRenderingContext.SetColor(color.mColor); - aRenderingContext.SetFont(font.mFont); + if (display.IsVisible() && NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) + { + if (mRect.width && mRect.height) { + // Paint our background and border + PRIntn skipSides = 0; //aForFrame->GetSkipSides(); + nsStyleSpacing spacing; + mStyleContext->GetStyle(eStyleStruct_Spacing, spacing); - if (eMathMLChar_DONT_STRETCH == mEnum || NS_STRETCH_DIRECTION_UNSUPPORTED == mDirection) { - // normal drawing if there is nothing special about this char ... - aRenderingContext.DrawString(mData.GetUnicode(), PRUint32(mData.Length()), mRect.x, mRect.y); -//printf("Painting %04X like a normal char\n", mData[0]); + nsRect rect(mRect); //0, 0, mRect.width, mRect.height); + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, aForFrame, + aDirtyRect, rect, color, spacing, 0, 0); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, aForFrame, + aDirtyRect, rect, spacing, mStyleContext, skipSides); + nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, aForFrame, + aDirtyRect, rect, spacing, mStyleContext, 0); + } } - else if (0 < mGlyph) { // wow, there is a glyph of appropriate size! -//printf("Painting %04X with a glyph of appropriate size\n", mData[0]); - aRenderingContext.DrawString(&mGlyph, PRUint32(1), mRect.x, mRect.y); - } - else { // paint by parts + + if (display.IsVisible() && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) + { + // Set color and font ... + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + aRenderingContext.SetColor(color.mColor); + aRenderingContext.SetFont(font.mFont); + // grab some metrics that will help to adjust the placements ... - nscoord fontAscent, fontDescent; + nscoord fontAscent; nsCOMPtr fm; aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); fm->GetMaxAscent(fontAscent); - fm->GetMaxDescent(fontDescent); - // do the painting ... - if (NS_STRETCH_DIRECTION_VERTICAL == mDirection) - return PaintVertically(aPresContext, aRenderingContext, aStyleContext, - fontAscent, fontDescent, mEnum, mRect); - else if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection) - return PaintHorizontally(aPresContext, aRenderingContext, aStyleContext, - fontAscent, fontDescent, mEnum, mRect); + + if (eMathMLChar_DONT_STRETCH == mEnum || NS_STRETCH_DIRECTION_UNSUPPORTED == mDirection) { + // normal drawing if there is nothing special about this char ... + //printf("Painting %04X like a normal char\n", mData[0]); +aRenderingContext.SetColor(NS_RGB(255,0,0)); + aRenderingContext.DrawString(mData.GetUnicode(), PRUint32(mData.Length()), + mRect.x, + mRect.y - (fontAscent - mBoundingMetrics.ascent)); + } + else if (0 < mGlyph) { // wow, there is a glyph of appropriate size! + //printf("Painting %04X with a glyph of appropriate size\n", mData[0]); +aRenderingContext.SetColor(NS_RGB(0,0,255)); + mGlyphTable->DrawGlyph(aRenderingContext, mGlyph, + mRect.x, + mRect.y - (fontAscent - mBoundingMetrics.ascent)); + } + else { // paint by parts +aRenderingContext.SetColor(NS_RGB(0,255,0)); + if (NS_STRETCH_DIRECTION_VERTICAL == mDirection) + return PaintVertically(aPresContext, aRenderingContext, fontAscent, + mStyleContext, mGlyphTable, mEnum, mRect); + else if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection) + return PaintHorizontally(aPresContext, aRenderingContext, fontAscent, + mStyleContext, mGlyphTable, mEnum, mRect); + } } return NS_OK; } -/* ================================================================================= +/* ================================================================================= And now the helper routines that actually do the job of painting the char by parts */ -// draw a glyph in a clipped area so that we don't have hairy chars pending outside -void -nsMathMLChar::DrawGlyph(nsIRenderingContext& aRenderingContext, - PRUnichar aGlyph, - nscoord aX, - nscoord aY, - nsRect& aClipRect) -{ - PRBool clipState; - aRenderingContext.PushState(); - aRenderingContext.SetClipRect(aClipRect, nsClipCombine_kIntersect, clipState); - aRenderingContext.DrawString(&aGlyph, PRUint32(1), aX, aY); - aRenderingContext.PopState(clipState); -} - // paint a stretchy char by assembling glyphs vertically nsresult nsMathMLChar::PaintVertically(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, + nscoord aFontAscent, nsIStyleContext* aStyleContext, - nscoord fontAscent, - nscoord fontDescent, + nsGlyphTable* aGlyphTable, nsMathMLCharEnum aCharEnum, nsRect aRect) { nsresult rv = NS_OK; - PRInt32 index = gMathMLCharIndex[aCharEnum]; - PRInt32 limit = gMathMLCharIndex[aCharEnum+1]; // next char starts here... - // 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]) { printf("Erroneous gMathMLCharGlyph table!\n"); return NS_OK; } - nscoord dx = aRect.x; nscoord dy = aRect.y; nsRect clipRect; float p2t; aPresContext->GetScaledPixelsToTwips(&p2t); - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); // get metrics data to be re-used later PRInt32 i; + nsGlyphCode ch, chdata[4]; nsBoundingMetrics bm, bmdata[4]; nscoord stride, offset[3], start[3], end[3]; for (i = 0; i < 4; i++) { - 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; } + switch (i) { + case 0: ch = aGlyphTable->TopOf(aCharEnum); break; + case 1: ch = aGlyphTable->MiddleOf(aCharEnum); break; + case 2: ch = aGlyphTable->BottomOf(aCharEnum); break; + case 3: ch = aGlyphTable->GlueOf(aCharEnum); break; + } + if (!ch) ch = aGlyphTable->GlueOf(aCharEnum); + rv = aGlyphTable->GetBoundingMetrics(aRenderingContext, ch, bm); + if (NS_FAILED(rv)) { + printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); + return rv; + } + chdata[i] = ch; 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); } for (i = 0; i < 3; i++) { - ch = gMathMLCharGlyph[index+i]; + ch = chdata[i]; bm = bmdata[i]; -//printf("Drawing i=%d ch=%04X", i, ch); getchar(); if (0 == i) { // top - //coord with line-spacing (i.e., leading) - // dy = aRect.y; - - //coord for exact fit (i.e., no leading) - dy = aRect.y + bm.ascent - fontAscent; + dy = aRect.y - aFontAscent + bm.ascent; } else if (1 == i) { // middle - // coord with line-spacing (i.e., leading) - // dy = aRect.y + (aRect.height - fontAscent - fontDescent - // - bmdata[0].ascent - bmdata[2].descent + bm.ascent + bm.descent)/2; - - // coord for exact fit (i.e., no leading) - dy = aRect.y + (aRect.height - (bm.ascent + bm.descent))/2 - - (fontAscent - bm.ascent); + dy = aRect.y - aFontAscent + bm.ascent + + (aRect.height - (bm.ascent + bm.descent))/2; } else if (2 == i) { // bottom - // coord with line-spacing (i.e., leading) - // dy = aRect.y + aRect.height - (fontAscent + fontDescent); - - // coord for exact fit (i.e., no leading) - dy = aRect.y + aRect.height - (fontAscent + bm.descent); + dy = aRect.y - aFontAscent + aRect.height - bm.descent; } - clipRect = nsRect(dx, dy, aRect.width, aRect.height); - // abcissa that DrawString used + // abcissa passed to DrawString offset[i] = dy; // *exact* abcissa where the *top-most* pixel of the glyph is painted - start[i] = dy + fontAscent - bm.ascent; + start[i] = dy + aFontAscent - bm.ascent; // *exact* abcissa where the *bottom-most* pixel of the glyph is painted - end[i] = dy + fontAscent + bm.descent; // note: end = start + height + end[i] = dy + aFontAscent + bm.descent; // end = start + height } ///////////////////////////////////// // draw top, middle, bottom for (i = 0; i < 3; i++) { - ch = gMathMLCharGlyph[index+i]; + ch = chdata[i]; #ifdef SHOW_BORDERS + // bounding box of the part aRenderingContext.SetColor(NS_RGB(0,0,0)); aRenderingContext.DrawRect(nsRect(dx,start[i],aRect.width+30*(i+1),end[i]-start[i])); #endif dy = offset[i]; - if (i==0) clipRect = nsRect(dx, dy, aRect.width, aRect.height); + if (i==0) clipRect = nsRect(dx, aRect.y, aRect.width, aRect.height); else if (i==1) clipRect = nsRect(dx, end[0], aRect.width, start[2]-end[0]); else if (i==2) clipRect = nsRect(dx, start[2], aRect.width, end[2]-start[2]); -// 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); - DrawGlyph(aRenderingContext, ch, dx, dy, clipRect); + aGlyphTable->DrawGlyph(aRenderingContext, ch, dx, dy, &clipRect); } } /////////////// // fill the gap between top and middle, and between middle and bottom. - ch = gMathMLCharGlyph[index+3]; // glue + ch = aGlyphTable->GlueOf(aCharEnum); for (i = 0; i < 2; i++) { PRInt32 count = 0; - dy = offset[i]; + dy = offset[i]; clipRect = nsRect(dx, end[i], aRect.width, start[i+1]-end[i]); clipRect.Inflate(onePixel, onePixel); #ifdef SHOW_BORDERS + // exact area to fill aRenderingContext.SetColor(NS_RGB(255,0,0)); aRenderingContext.DrawRect(clipRect); #endif bm = bmdata[i]; - while (dy + fontAscent + bm.descent < start[i+1]) { + while (dy + aFontAscent + bm.descent < start[i+1]) { if (2 > count) { stride = bm.descent; bm = bmdata[3]; // glue @@ -737,87 +1196,82 @@ nsMathMLChar::PaintVertically(nsIPresContext* aPresContext, } count++; dy += stride; - DrawGlyph(aRenderingContext, ch, dx, dy, clipRect); -// NS_ASSERTION(5000 == count, "Error - gMathMLCharGlyph is incorrectly set"); + aGlyphTable->DrawGlyph(aRenderingContext, ch, dx, dy, &clipRect); +// NS_ASSERTION(5000 == count, "Error - glyph table 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; + nscoord height = bm.ascent + bm.descent; aRenderingContext.SetColor(NS_RGB(0,255,0)); - aRenderingContext.DrawRect(nsRect(dx, dy+fontAscent-bm.ascent, aRect.width, height)); + aRenderingContext.DrawRect(nsRect(dx, dy+aFontAscent-bm.ascent, aRect.width, height)); #endif } - return NS_OK; + return NS_OK; } // paint a stretchy char by assembling glyphs horizontally nsresult nsMathMLChar::PaintHorizontally(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, + nscoord aFontAscent, nsIStyleContext* aStyleContext, - nscoord fontAscent, - nscoord fontDescent, + nsGlyphTable* aGlyphTable, nsMathMLCharEnum aCharEnum, nsRect aRect) { nsresult rv = NS_OK; - PRInt32 index = gMathMLCharIndex[aCharEnum]; - PRInt32 limit = gMathMLCharIndex[aCharEnum+1]; // next char starts here... - // 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]) { printf("Erroneous gMathMLCharGlyph table!\n"); return NS_OK; } + nsRect clipRect; nscoord dx = aRect.x; nscoord dy = aRect.y; - nsRect clipRect; + // place the parts such that the operator as a whole is centered +// nscoord dx = aRect.x + (aRect.width - mBoundingMetrics.width)/2; +// nscoord dy = aRect.y - (aFontAscent - mBoundingMetrics.ascent); float p2t; aPresContext->GetScaledPixelsToTwips(&p2t); - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); // get metrics data to be re-used later PRInt32 i; + nsGlyphCode ch, chdata[4]; nsBoundingMetrics bm, bmdata[4]; - nscoord stride, offset[3], start[3], end[3]; + nscoord ascent, stride, offset[3], start[3], end[3]; for (i = 0; i < 4; i++) { - 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; } + switch (i) { + case 0: ch = aGlyphTable->LeftOf(aCharEnum); break; + case 1: ch = aGlyphTable->MiddleOf(aCharEnum); break; + case 2: ch = aGlyphTable->RightOf(aCharEnum); break; + case 3: ch = aGlyphTable->GlueOf(aCharEnum); break; + } + if (!ch) ch = aGlyphTable->GlueOf(aCharEnum); + rv = aGlyphTable->GetBoundingMetrics(aRenderingContext, ch, bm); + if (NS_FAILED(rv)) { + printf("GetBoundingMetrics failed for %04X:%c\n", ch, ch&0x00FF); + return rv; + } + chdata[i] = ch; 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); + if (0 == i || ascent < bm.ascent) ascent = bm.ascent; } + dy = aRect.y - aFontAscent + ascent; for (i = 0; i < 3; i++) { - ch = gMathMLCharGlyph[index+i]; + ch = chdata[i]; bm = bmdata[i]; -//printf("Drawing i=%d ch=%04X", i, ch); getchar(); - if (0 == i) { // left - // coord with intercharacter-spacing - // dx = aRect.x; - - // coord for exact fit (no intercharacter-spacing) + if (0 == i) { // left dx = aRect.x - bm.leftBearing; } else if (1 == i) { // middle - // coord with intercharacter-spacing dx = aRect.x + (aRect.width - bm.width)/2; } else if (2 == i) { // right - // coord with intercharacter-spacing - // dx = aRect.x + aRect.width - bm.width; - - // coord for exact fit (no intercharacter-spacing) dx = aRect.x + aRect.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; + 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 } @@ -825,33 +1279,32 @@ nsMathMLChar::PaintHorizontally(nsIPresContext* aPresContext, /////////////////////////// // draw left, middle, right for (i = 0; i < 3; i++) { - ch = gMathMLCharGlyph[index+i]; + ch = chdata[i]; #ifdef SHOW_BORDERS aRenderingContext.SetColor(NS_RGB(0,0,0)); - aRenderingContext.DrawRect(nsRect(start[i], dy, end[i]-start[i], aRect.height+30*(i+1))); + aRenderingContext.DrawRect(nsRect(start[i], aRect.y, end[i]-start[i], aRect.height+30*(i+1))); #endif dx = offset[i]; - nscoord top = PR_MIN(dy, dy + fontAscent - bm.ascent); +// nscoord top = aRect.y; /*PR_MIN(dy, dy + aFontAscent - bm.ascent);*/ + nscoord top = aRect.y; if (i==0) clipRect = nsRect(dx, top, aRect.width, aRect.height); else if (i==1) clipRect = nsRect(end[0], top, start[2]-end[0], aRect.height); else if (i==2) clipRect = nsRect(start[2], top, end[2]-start[2], aRect.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); - DrawGlyph(aRenderingContext, ch, dx, dy, clipRect); + aGlyphTable->DrawGlyph(aRenderingContext, ch, dx, dy, &clipRect); } } //////////////// // fill the gap between left and middle, and between middle and right. - ch = gMathMLCharGlyph[index+3]; // glue + ch = aGlyphTable->GlueOf(aCharEnum); for (i = 0; i < 2; i++) { PRInt32 count = 0; - dx = offset[i]; - nscoord top = PR_MIN(dy, dy + fontAscent - bm.ascent); + dx = offset[i]; + nscoord top = aRect.y; +// nscoord top = PR_MIN(dy, dy + aFontAscent - bm.ascent); clipRect = nsRect(end[i], top, start[i+1]-end[i], aRect.height); clipRect.Inflate(onePixel, onePixel); #ifdef SHOW_BORDERS @@ -868,19 +1321,16 @@ nsMathMLChar::PaintHorizontally(nsIPresContext* aPresContext, } count++; dx += stride; - DrawGlyph(aRenderingContext, ch, dx, dy, clipRect); -// NS_ASSERTION(5000 == count, "Error - gMathMLCharGlyph is incorrectly set"); + aGlyphTable->DrawGlyph(aRenderingContext, ch, dx, dy, &clipRect); +// NS_ASSERTION(5000 == count, "Error - glyph table 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, aRect.height)); + aRenderingContext.DrawRect(nsRect(dx + bm.leftBearing, aRect.y, width, aRect.height)); #endif } - return NS_OK; + return NS_OK; } - diff --git a/layout/mathml/base/src/nsMathMLChar.h b/layout/mathml/base/src/nsMathMLChar.h index c657797dfb9a..f2dad91eb9bb 100644 --- a/layout/mathml/base/src/nsMathMLChar.h +++ b/layout/mathml/base/src/nsMathMLChar.h @@ -17,6 +17,7 @@ * * Contributor(s): * Roger B. Sidje + * Shyjan Mahamud */ #ifndef nsMathMLChar_h___ @@ -25,52 +26,63 @@ #include "nsMathMLOperators.h" #include "nsIMathMLFrame.h" -// enum of chars that we know something about +typedef PRUnichar nsGlyphCode; +class nsGlyphTable; + +// List of enums of all known chars enum nsMathMLCharEnum { eMathMLChar_DONT_STRETCH = -1, -#define MATHML_CHAR(_name, _value, _direction) eMathMLChar_##_name, -#include "nsMathMLCharList.h" -#undef MATHML_CHAR +#define WANT_CHAR_ENUM + #include "nsMathMLCharList.h" +#undef WANT_CHAR_ENUM eMathMLChar_COUNT }; +// Hints for Stretch() to indicate criteria for stretching +#define NS_STRETCH_SMALLER -1 // don't stretch more than requested size +#define NS_STRETCH_NORMAL 0 // try to stretch to requested size - DEFAULT +#define NS_STRETCH_LARGER 1 // try to stretch more than requested size -// class used to handle stretchy symbols (accent and boundary symbol) +// class used to handle stretchy symbols (accent, delimiter and boundary symbols) class nsMathMLChar { public: // constructor and destructor nsMathMLChar() { + mStyleContext = nsnull; } - virtual ~nsMathMLChar() + ~nsMathMLChar() // not a virtual destructor: this class is not intended to be subclassed { } - NS_IMETHOD + nsresult Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext); + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nsIFrame* aForFrame); // 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 input - it contains our current size, or zero if current size is unknown // On output - the same size or the new size that the char wants. - NS_IMETHOD + nsresult Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize); + nsBoundingMetrics& aContainerSize, + nsBoundingMetrics& aDesiredStretchSize, + PRInt32 aStretchHint = NS_STRETCH_NORMAL); // If you call SetData(), it will lookup the enum of the data // and set mEnum for you. If the data is an arbitrary string for // which no enum is defined, mEnum is set to eMathMLChar_DONT_STRETCH // and the data is interpreted as a normal string. void - SetData(nsString& aData); + SetData(nsIPresContext* aPresContext, + nsString& aData); void GetData(nsString& aData) { @@ -80,10 +92,11 @@ public: // If you call SetEnum(), it will lookup the actual value of the data and // set it for you. All the enums listed above have their corresponding data. void - SetEnum(nsMathMLCharEnum aEnum); + SetEnum(nsIPresContext* aPresContext, + nsMathMLCharEnum aEnum); nsMathMLCharEnum - Enum() { + GetEnum() { return mEnum; } @@ -114,43 +127,52 @@ public: mRect = aRect; } + // Metrics that _exactly_ enclose the char. The char *must* have *already* + // being stretched before you can call the GetBoundingMetrics() method. + // IMPORTANT: since chars have their own style contexts, and may be rendered + // with glyphs that are not in the parent font, just calling the default + // aRenderingContext.GetBoundingMetrics(aChar) can give incorrect results. void GetBoundingMetrics(nsBoundingMetrics& aBoundingMetrics) { aBoundingMetrics = mBoundingMetrics; } + // Hooks to access the extra leaf style contexts given to the MathMLChars. + // They provide an interface to make them acessible to the Style System via + // the Get/Set AdditionalStyleContext() APIs. Owners of MathMLChars + // should honor these APIs. + nsresult + GetStyleContext(nsIStyleContext** aStyleContext) const; + + nsresult + SetStyleContext(nsIStyleContext* aStyleContext); + private: nsString mData; - PRUnichar mGlyph; - nsRect mRect; - nsStretchDirection mDirection; nsMathMLCharEnum mEnum; + nsStretchDirection mDirection; + nsRect mRect; nsBoundingMetrics mBoundingMetrics; + nsIStyleContext* mStyleContext; + nsGlyphTable* mGlyphTable; + nsGlyphCode mGlyph; // helper methods - - static void - DrawGlyph(nsIRenderingContext& aRenderingContext, - PRUnichar aChar, - nscoord aX, - nscoord aY, - nsRect& aClipRect); - static nsresult PaintVertically(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, + nscoord aFontAscent, nsIStyleContext* aStyleContext, - nscoord fontAscent, - nscoord fontDescent, + nsGlyphTable* aGlyphTable, nsMathMLCharEnum aCharEnum, nsRect aRect); static nsresult PaintHorizontally(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, + nscoord aFontAscent, nsIStyleContext* aStyleContext, - nscoord fontAscent, - nscoord fontDescent, + nsGlyphTable* aGlyphTable, nsMathMLCharEnum aCharEnum, nsRect aRect); }; diff --git a/layout/mathml/base/src/nsMathMLCharList.h b/layout/mathml/base/src/nsMathMLCharList.h index 67ab462f7340..2a1892c62770 100644 --- a/layout/mathml/base/src/nsMathMLCharList.h +++ b/layout/mathml/base/src/nsMathMLCharList.h @@ -17,6 +17,7 @@ * * Contributor(s): * Roger B. Sidje + * Shyjan Mahamud */ /****** @@ -29,153 +30,307 @@ All entries must be enclosed in the macro MATHML_CHAR which will have cruel and unusual things done to them. - To add support for a particular stretchy char, you should move its - MATHML_CHAR entry out of the #ifdef list and append it in the active list. + How it works + ============ + + * Stretchy chars that come from the same font are grouped together. + For example, stretchy chars that can be build with the Symbol font are enclosed in: + #if defined(WANT_SYMBOL_DATA) + ... + #endif + + * To add support for a new stretchy char within a font, you should + add its MATHML_CHAR entry in the appropriate list. Each relevant row looks like: - The first argument of MATHML_CHAR will be converted in an enum of - the form, e.g., eMathMLChar_LeftParenthesis, which will be used in - the code. Therefore the ORDER OF THE ACTIVE LIST IS SIGNIFICANT. - (The order in which chars are gradually appended in the active list is - not-significant, but once added in the active list, they should remain - in their positions. If you want to shuffle the active list, you should - also make sure to adjust the related data structures in nsMathMLChar.cpp) + MATHML_CHAR(index, enum, top _ middle _ bottom _ glue, size0 _ ... _ size{N-1}) + + o The second argument of MATHML_CHAR will be converted in an 'enum' of the form, + e.g., eMathMLChar_LeftParenthesis, which will be used in the code. + + o The first argument 'index' represents the previous index augmented with: + 1 + number of glyphs listed in the previous row. In general therefore, + the k+1st index after the k-th index must satisfy the relationship: + + index[k+1] = index[k] + 5 + N. + + where: + 5 represents the 4 partial glyphs: top (or left), middle, bottom (or right), glue, + *plus* the null separator that is inserted after the list of glyphs! + N represents the total number of bigger sizes: size0, ..., size{N-1}. + + * To add support for a new font, you should create the list of stretchy chars + that can be rendered with that font, and then declare an instance of nsGlyphTable + associated to that font in nsMathMLChar.cpp. Then update the font-family list + of :-moz-math-font-style-stretchy in mathml.css to instruct the Style System to + pass your font in your preferred order. + + * There can be two types of data: either with Unicode points, or with direct + glyph indices within the fonts. XXX The second variant is not yet supported. ******/ +#if defined(WANT_CHAR_ENUM) + #define MATHML_CHAR(_enum, _unicode, _direction) eMathMLChar_##_enum, + +#elif defined(WANT_CHAR_INFO) + #define MATHML_CHAR(_enum, _unicode, _direction) {_unicode, _direction, nsnull}, + +#elif defined(WANT_CHAR_DATA) + #define MATHML_CHAR(_index, _enum, _parts, _sizes) {eMathMLChar_##_enum, _index}, + +#elif defined(WANT_GLYPH_DATA) + #define MATHML_CHAR(_index, _enum, _parts, _sizes) _parts, _sizes, 0x0000, + +#endif + + +#if defined(WANT_CHAR_ENUM) || defined(WANT_CHAR_INFO) + // short names for a short while... #define STRETCH_UNSUPPORTED NS_STRETCH_DIRECTION_UNSUPPORTED #define STRETCH_HORIZONTAL NS_STRETCH_DIRECTION_HORIZONTAL #define STRETCH_VERTICAL NS_STRETCH_DIRECTION_VERTICAL -/* active list - these are chars that we know something about */ +// List of all strecthy chars from the MathML's Operator Dictionary ------------------ +// ----------------------------------------------------------------------------------- + MATHML_CHAR(LeftParenthesis, '(' , STRETCH_VERTICAL) MATHML_CHAR(RightParenthesis, ')' , STRETCH_VERTICAL) -MATHML_CHAR(Integral, 0x222B, STRETCH_VERTICAL) MATHML_CHAR(LeftSquareBracket, '[' , STRETCH_VERTICAL) MATHML_CHAR(RightSquareBracket, ']' , STRETCH_VERTICAL) MATHML_CHAR(LeftCurlyBracket, '{' , STRETCH_VERTICAL) MATHML_CHAR(RightCurlyBracket, '}' , STRETCH_VERTICAL) +MATHML_CHAR(VerticalBar, 0x007C, STRETCH_VERTICAL) // '|' +MATHML_CHAR(Integral, 0x222B, STRETCH_VERTICAL) MATHML_CHAR(DownArrow, 0x2193, STRETCH_VERTICAL) MATHML_CHAR(UpArrow, 0x2191, STRETCH_VERTICAL) MATHML_CHAR(LeftArrow, 0x2190, STRETCH_HORIZONTAL) MATHML_CHAR(RightArrow, 0x2192, STRETCH_HORIZONTAL) MATHML_CHAR(OverBar, 0x00AF, STRETCH_HORIZONTAL) -MATHML_CHAR(VerticalBar, '|' , STRETCH_VERTICAL) -MATHML_CHAR(Sqrt, 0x221A, STRETCH_UNSUPPORTED) +MATHML_CHAR(Sqrt, 0x221A, STRETCH_VERTICAL) +MATHML_CHAR(LeftAngleBracket, 0x3008, STRETCH_VERTICAL) +MATHML_CHAR(LeftBracketingBar, 0xF603, STRETCH_VERTICAL) +MATHML_CHAR(LeftCeiling, 0x2308, STRETCH_VERTICAL) +MATHML_CHAR(LeftDoubleBracket, 0x301A, STRETCH_VERTICAL) +MATHML_CHAR(LeftDoubleBracketingBar, 0xF605, STRETCH_VERTICAL) +MATHML_CHAR(LeftFloor, 0x230A, STRETCH_VERTICAL) +MATHML_CHAR(RightAngleBracket, 0x3009, STRETCH_VERTICAL) +MATHML_CHAR(RightBracketingBar, 0xF604, STRETCH_VERTICAL) +MATHML_CHAR(RightCeiling, 0x2309, STRETCH_VERTICAL) +MATHML_CHAR(RightDoubleBracket, 0x301B, STRETCH_VERTICAL) +MATHML_CHAR(RightDoubleBracketingBar, 0xF606, STRETCH_VERTICAL) +MATHML_CHAR(RightFloor, 0x230B, STRETCH_VERTICAL) +MATHML_CHAR(HorizontalLine, 0xE859, STRETCH_HORIZONTAL) +MATHML_CHAR(VerticalLine, 0xE85A, STRETCH_VERTICAL) +MATHML_CHAR(VerticalSeparator, 0xE85C, STRETCH_VERTICAL) +MATHML_CHAR(Implies, 0x21D2, STRETCH_HORIZONTAL) +MATHML_CHAR(And, 0x2227, STRETCH_HORIZONTAL) +MATHML_CHAR(Or, 0x2228, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleLeftArrow, 0x21D0, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleLeftRightArrow, 0x21D4, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleRightArrow, 0x21D2, STRETCH_HORIZONTAL) +MATHML_CHAR(DownLeftRightVector, 0xF50B, STRETCH_VERTICAL) +MATHML_CHAR(DownLeftTeeVector, 0xF50E, STRETCH_VERTICAL) +MATHML_CHAR(DownLeftVector, 0x21BD, STRETCH_VERTICAL) +MATHML_CHAR(DownLeftVectorBar, 0xF50C, STRETCH_VERTICAL) +MATHML_CHAR(DownRightTeeVector, 0xF50F, STRETCH_VERTICAL) +MATHML_CHAR(DownRightVector, 0x21C1, STRETCH_VERTICAL) +MATHML_CHAR(DownRightVectorBar, 0xF50D, STRETCH_VERTICAL) +MATHML_CHAR(LeftArrowBar, 0x21E4, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftArrowRightArrow, 0x21C6, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftRightArrow, 0x2194, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftRightVector, 0xF505, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftTeeArrow, 0x21A4, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftTeeVector, 0xF509, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftVector, 0x21BC, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftVectorBar, 0xF507, STRETCH_HORIZONTAL) +MATHML_CHAR(LowerLeftArrow, 0x2199, STRETCH_HORIZONTAL) +MATHML_CHAR(LowerRightArrow, 0x2198, STRETCH_HORIZONTAL) +MATHML_CHAR(RightArrowBar, 0x21E5, STRETCH_HORIZONTAL) +MATHML_CHAR(RightArrowLeftArrow, 0x21C4, STRETCH_HORIZONTAL) +MATHML_CHAR(RightTeeArrow, 0x21A6, STRETCH_HORIZONTAL) +MATHML_CHAR(RightTeeVector, 0xF50A, STRETCH_HORIZONTAL) +MATHML_CHAR(RightVector, 0x21C0, STRETCH_HORIZONTAL) +MATHML_CHAR(RightVectorBar, 0xF508, STRETCH_HORIZONTAL) +MATHML_CHAR(UpperLeftArrow, 0x2196, STRETCH_VERTICAL) +MATHML_CHAR(UpperRightArrow, 0x2197, STRETCH_VERTICAL) +MATHML_CHAR(Equilibrium, 0x21CC, STRETCH_HORIZONTAL) +MATHML_CHAR(ReverseEquilibrium, 0x21CB, STRETCH_HORIZONTAL) +MATHML_CHAR(SquareUnion, 0x2294, STRETCH_VERTICAL) +MATHML_CHAR(Union, 0x22C3, STRETCH_VERTICAL) +MATHML_CHAR(UnionPlus, 0x228E, STRETCH_VERTICAL) +MATHML_CHAR(Intersection, 0x22C2, STRETCH_VERTICAL) +MATHML_CHAR(SquareIntersection, 0x2293, STRETCH_VERTICAL) +MATHML_CHAR(Vee, 0x22C1, STRETCH_VERTICAL) +MATHML_CHAR(Sum, 0x2211, STRETCH_VERTICAL) +MATHML_CHAR(ClockwiseContourIntegral, 0x2232, STRETCH_VERTICAL) +MATHML_CHAR(ContourIntegral, 0x222E, STRETCH_VERTICAL) +MATHML_CHAR(CounterClockwiseContourIntegral, 0x2233, STRETCH_VERTICAL) +MATHML_CHAR(DoubleContourIntegral, 0x222F, STRETCH_VERTICAL) +MATHML_CHAR(Wedge, 0x22C0, STRETCH_VERTICAL) +MATHML_CHAR(Coproduct, 0x2210, STRETCH_VERTICAL) +MATHML_CHAR(Product, 0x220F, STRETCH_VERTICAL) +MATHML_CHAR(Backslash, 0x2216, STRETCH_VERTICAL) +MATHML_CHAR(Slash, '/' , STRETCH_VERTICAL) +MATHML_CHAR(DoubleDownArrow, 0x21D3, STRETCH_VERTICAL) +MATHML_CHAR(DoubleLongLeftArrow, 0xE200, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleLongLeftRightArrow, 0xE202, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleLongRightArrow, 0xE204, STRETCH_HORIZONTAL) +MATHML_CHAR(DoubleUpArrow, 0x21D1, STRETCH_VERTICAL) +MATHML_CHAR(DoubleUpDownArrow, 0x21D5, STRETCH_VERTICAL) +MATHML_CHAR(DownArrowBar, 0xF504, STRETCH_VERTICAL) +MATHML_CHAR(DownArrowUpArrow, 0xE216, STRETCH_VERTICAL) +MATHML_CHAR(DownTeeArrow, 0x21A7, STRETCH_VERTICAL) +MATHML_CHAR(LeftDownTeeVector, 0xF519, STRETCH_VERTICAL) +MATHML_CHAR(LeftDownVector, 0x21C3, STRETCH_VERTICAL) +MATHML_CHAR(LeftDownVectorBar, 0xF517, STRETCH_VERTICAL) +MATHML_CHAR(LeftUpDownVector, 0xF515, STRETCH_VERTICAL) +MATHML_CHAR(LeftUpTeeVector, 0xF518, STRETCH_VERTICAL) +MATHML_CHAR(LeftUpVector, 0x21BF, STRETCH_VERTICAL) +MATHML_CHAR(LeftUpVectorBar, 0xF516, STRETCH_VERTICAL) +MATHML_CHAR(LongLeftArrow, 0xE201, STRETCH_HORIZONTAL) +MATHML_CHAR(LongLeftRightArrow, 0xE203, STRETCH_HORIZONTAL) +MATHML_CHAR(LongRightArrow, 0xE205, STRETCH_HORIZONTAL) +MATHML_CHAR(ReverseUpEquilibrium, 0xE217, STRETCH_VERTICAL) +MATHML_CHAR(RightDownTeeVector, 0xF514, STRETCH_VERTICAL) +MATHML_CHAR(RightDownVector, 0x21C2, STRETCH_VERTICAL) +MATHML_CHAR(RightDownVectorBar, 0xF512, STRETCH_VERTICAL) +MATHML_CHAR(RightUpDownVector, 0xF510, STRETCH_VERTICAL) +MATHML_CHAR(RightUpTeeVector, 0xF513, STRETCH_VERTICAL) +MATHML_CHAR(RightUpVector, 0x21BE, STRETCH_VERTICAL) +MATHML_CHAR(RightUpVectorBar, 0xF511, STRETCH_VERTICAL) +MATHML_CHAR(UpArrowBar, 0xF503, STRETCH_VERTICAL) +MATHML_CHAR(UpArrowDownArrow, 0x21C5, STRETCH_VERTICAL) +MATHML_CHAR(UpDownArrow, 0x2195, STRETCH_VERTICAL) +MATHML_CHAR(UpEquilibrium, 0xE218, STRETCH_VERTICAL) +MATHML_CHAR(UpTeeArrow, 0x21A5, STRETCH_VERTICAL) +MATHML_CHAR(DiacriticalTilde, 0x02DC, STRETCH_HORIZONTAL) +MATHML_CHAR(Hacek, 0x02C7, STRETCH_HORIZONTAL) +MATHML_CHAR(Hat, 0x0302, STRETCH_HORIZONTAL) +MATHML_CHAR(OverCurlyBracket, 0xF612, STRETCH_HORIZONTAL) +MATHML_CHAR(OverBracket, 0xF614, STRETCH_HORIZONTAL) +MATHML_CHAR(OverParenthesis, 0xF610, STRETCH_HORIZONTAL) +MATHML_CHAR(UnderBar, 0x0332, STRETCH_HORIZONTAL) +MATHML_CHAR(UnderCurlyBracket, 0xF613, STRETCH_HORIZONTAL) +MATHML_CHAR(UnderBracket, 0xF615, STRETCH_HORIZONTAL) +MATHML_CHAR(UnderParenthesis, 0xF611, STRETCH_HORIZONTAL) +MATHML_CHAR(CircleDot, 0x2299, STRETCH_VERTICAL) +MATHML_CHAR(CirclePlus, 0x2295, STRETCH_VERTICAL) +MATHML_CHAR(CircleMultiply, 0x2297, STRETCH_VERTICAL) +MATHML_CHAR(Tilde, 0x223C, STRETCH_HORIZONTAL) + +//UnionMultiply (UnionPlus?), 0x228E, STRETCH_VERTICAL, + +// Oversight? \parallel (&DoubleVerticalBar, 0x2225) is not stretchy in +// the REC operator dictionary... + + +// Extra stretchy operators that are not in the MathML REC Operator Dictionary +// ----------------------------------------------------------------------------------- +// XXX For these extra to work, they must also be added in nsMathMLOperators +MATHML_CHAR(RightArrowAccent, 0x20D7, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftArrowAccent, 0x20D6, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftRightArrowAccent, 0x20E1, STRETCH_HORIZONTAL) +MATHML_CHAR(RightHarpoonAccent, 0x20D1, STRETCH_HORIZONTAL) +MATHML_CHAR(LeftHarpoonAccent, 0x20D0, STRETCH_HORIZONTAL) + -#if 0 -MATHML_CHAR(LeftAngleBracket, 0x3008, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftBracketingBar, 0xF603, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftCeiling, 0x2308, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftDoubleBracket, 0x301A, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftDoubleBracketingBar, 0xF605, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftFloor, 0x230A, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightAngleBracket, 0x3009, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightBracketingBar, 0xF604, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightCeiling, 0x2309, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightDoubleBracket, 0x301B, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightDoubleBracketingBar, 0xF606, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightFloor, 0x230B, STRETCH_UNSUPPORTED) -MATHML_CHAR(HorizontalLine, 0xE859, STRETCH_UNSUPPORTED) -MATHML_CHAR(VerticalLine, 0xE85A, STRETCH_UNSUPPORTED) -MATHML_CHAR(VerticalSeparator, 0xE85C, STRETCH_UNSUPPORTED) -MATHML_CHAR(Implies, 0x21D2, STRETCH_UNSUPPORTED) -MATHML_CHAR(Or, 0xE375, STRETCH_UNSUPPORTED) -MATHML_CHAR(And, 0xE374, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleLeftArrow, 0x21D0, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleLeftRightArrow, 0x21D4, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleRightArrow, 0x21D2, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownLeftRightVector, 0xF50B, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownLeftTeeVector, 0xF50E, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownLeftVector, 0x21BD, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownLeftVectorBar, 0xF50C, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownRightTeeVector, 0xF50F, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownRightVector, 0x21C1, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownRightVectorBar, 0xF50D, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftArrowBar, 0x21E4, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftArrowRightArrow, 0x21C6, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftRightArrow, 0x2194, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftRightVector, 0xF505, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftTeeArrow, 0x21A4, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftTeeVector, 0xF509, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftVector, 0x21BC, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftVectorBar, 0xF507, STRETCH_UNSUPPORTED) -MATHML_CHAR(LowerLeftArrow, 0x2199, STRETCH_UNSUPPORTED) -MATHML_CHAR(LowerRightArrow, 0x2198, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightArrowBar, 0x21E5, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightArrowLeftArrow, 0x21C4, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightTeeArrow, 0x21A6, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightTeeVector, 0xF50A, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightVector, 0x21C0, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightVectorBar, 0xF508, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpperLeftArrow, 0x2196, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpperRightArrow, 0x2197, STRETCH_UNSUPPORTED) -MATHML_CHAR(Equilibrium, 0x21CC, STRETCH_UNSUPPORTED) -MATHML_CHAR(ReverseEquilibrium, 0x21CB, STRETCH_UNSUPPORTED) -MATHML_CHAR(SquareUnion, 0x2294, STRETCH_UNSUPPORTED) -MATHML_CHAR(Union, 0x22C3, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnionPlus, 0x228E, STRETCH_UNSUPPORTED) -MATHML_CHAR(Intersection, 0x22C2, STRETCH_UNSUPPORTED) -MATHML_CHAR(SquareIntersection, 0x2293, STRETCH_UNSUPPORTED) -MATHML_CHAR(Vee, 0x22C1, STRETCH_UNSUPPORTED) -MATHML_CHAR(Sum, 0x2211, STRETCH_UNSUPPORTED) -MATHML_CHAR(Union, 0x22C3, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnionPlus, 0x228E, STRETCH_UNSUPPORTED) -MATHML_CHAR(ClockwiseContourIntegral, 0x2232, STRETCH_UNSUPPORTED) -MATHML_CHAR(ContourIntegral, 0x222E, STRETCH_UNSUPPORTED) -MATHML_CHAR(CounterClockwiseContourIntegral, 0x2233, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleContourIntegral, 0x222F, STRETCH_UNSUPPORTED) -MATHML_CHAR(Wedge, 0x22C0, STRETCH_UNSUPPORTED) -MATHML_CHAR(Coproduct, 0x2210, STRETCH_UNSUPPORTED) -MATHML_CHAR(Product, 0x220F, STRETCH_UNSUPPORTED) -MATHML_CHAR(Intersection, 0x22C2, STRETCH_UNSUPPORTED) -MATHML_CHAR(Backslash, 0x2216, STRETCH_UNSUPPORTED) -MATHML_CHAR(Divide, '/' , STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleDownArrow, 0x21D3, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleLongLeftArrow, 0xE200, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleLongLeftRightArrow, 0xE202, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleLongRightArrow, 0xE204, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleUpArrow, 0x21D1, STRETCH_UNSUPPORTED) -MATHML_CHAR(DoubleUpDownArrow, 0x21D5, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownArrowBar, 0xF504, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownArrowUpArrow, 0xE216, STRETCH_UNSUPPORTED) -MATHML_CHAR(DownTeeArrow, 0x21A7, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftDownTeeVector, 0xF519, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftDownVector, 0x21C3, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftDownVectorBar, 0xF517, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftUpDownVector, 0xF515, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftUpTeeVector, 0xF518, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftUpVector, 0x21BF, STRETCH_UNSUPPORTED) -MATHML_CHAR(LeftUpVectorBar, 0xF516, STRETCH_UNSUPPORTED) -MATHML_CHAR(LongLeftArrow, 0xE201, STRETCH_UNSUPPORTED) -MATHML_CHAR(LongLeftRightArrow, 0xE203, STRETCH_UNSUPPORTED) -MATHML_CHAR(LongRightArrow, 0xE205, STRETCH_UNSUPPORTED) -MATHML_CHAR(ReverseUpEquilibrium, 0xE217, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightDownTeeVector, 0xF514, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightDownVector, 0x21C2, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightDownVectorBar, 0xF512, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightUpDownVector, 0xF510, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightUpTeeVector, 0xF513, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightUpVector, 0x21BE, STRETCH_UNSUPPORTED) -MATHML_CHAR(RightUpVectorBar, 0xF511, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpArrowBar, 0xF503, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpArrowDownArrow, 0x21C5, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpDownArrow, 0x2195, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpEquilibrium, 0xE218, STRETCH_UNSUPPORTED) -MATHML_CHAR(UpTeeArrow, 0x21A5, STRETCH_UNSUPPORTED) -MATHML_CHAR(DiacriticalTilde, 0x02DC, STRETCH_UNSUPPORTED) -MATHML_CHAR(Hacek, 0x02C7, STRETCH_UNSUPPORTED) -MATHML_CHAR(Hat, 0x0302, STRETCH_UNSUPPORTED) -MATHML_CHAR(OverBrace, 0xF612, STRETCH_UNSUPPORTED) -MATHML_CHAR(OverBracket, 0xF614, STRETCH_UNSUPPORTED) -MATHML_CHAR(OverParenthesis, 0xF610, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnderBar, 0x0332, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnderBrace, 0xF613, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnderBracket, 0xF615, STRETCH_UNSUPPORTED) -MATHML_CHAR(UnderParenthesis, 0xF611, STRETCH_UNSUPPORTED) -#endif #undef STRETCH_UNSUPPORTED #undef STRETCH_HORIZONTAL #undef STRETCH_VERTICAL + +#elif defined(WANT_CHAR_DATA) || defined(WANT_GLYPH_DATA) +#define _ , // dirty trick to make the macro handle a variable number of glyphs... + +// Data for strecthy chars that are supported by the Symbol font --------------------- +// ----------------------------------------------------------------------------------- + #if defined(WANT_SYMBOL_DATA)//[top/left][middle][bot/right][glue] [size0 ... size{N-1}] +MATHML_CHAR( 0, LeftParenthesis, 0xF8EB _ 0x0000 _ 0xF8ED _ 0xF8EC, 0x0028) +MATHML_CHAR( 6, RightParenthesis, 0xF8F6 _ 0x0000 _ 0xF8F8 _ 0xF8F7, 0x0029) +MATHML_CHAR(12, Integral, 0x2320 _ 0x0000 _ 0x2321 _ 0xF8F5, 0x222B) +MATHML_CHAR(18, LeftSquareBracket, 0xF8EE _ 0xF8EF _ 0xF8F0 _ 0xF8EF, 0x005B) +MATHML_CHAR(24, RightSquareBracket, 0xF8F9 _ 0xF8FA _ 0xF8FB _ 0xF8FA, 0x005D) +MATHML_CHAR(30, LeftCurlyBracket, 0xF8F1 _ 0xF8F2 _ 0xF8F3 _ 0xF8F4, 0x007B) +MATHML_CHAR(36, RightCurlyBracket, 0xF8FC _ 0xF8FD _ 0xF8FE _ 0xF8F4, 0x007D) +MATHML_CHAR(42, UpArrow, 0x2191 _ 0x0000 _ 0x0000 _ 0xF8E6, 0x2191) +MATHML_CHAR(48, DownArrow, 0x0000 _ 0x0000 _ 0x2193 _ 0xF8E6, 0x2193) +MATHML_CHAR(54, UpDownArrow, 0x2191 _ 0x0000 _ 0x2193 _ 0xF8E6, 0x2195) +MATHML_CHAR(60, LeftArrow, 0x2190 _ 0x0000 _ 0x0000 _ 0xF8E7, 0x2190) +MATHML_CHAR(66, RightArrow, 0x0000 _ 0x0000 _ 0x2192 _ 0xF8E7, 0x2192) +MATHML_CHAR(72, LeftRightArrow, 0x2190 _ 0x0000 _ 0x2192 _ 0xF8E7, 0x2194) +MATHML_CHAR(78, OverBar, 0x0000 _ 0x0000 _ 0x0000 _ 0x00AF, 0x00AF) +MATHML_CHAR(84, VerticalBar, 0x0000 _ 0x0000 _ 0x0000 _ 0x007C, 0x007C) + #endif // defined(WANT_SYMBOL_DATA) + +// Data for strecthy chars that are supported by the MT Extra font ------------------- +// ----------------------------------------------------------------------------------- + #if defined(WANT_MTEXTRA_DATA)//[top/left][middle][bot/right][glue] [size0 ... size{N-1}] +MATHML_CHAR( 0, UnderCurlyBracket, 0xEC00 _ 0xEC01 _ 0xEC02 _ 0xEC03, 0xF613) +MATHML_CHAR( 6, OverCurlyBracket, 0xEC04 _ 0xEC05 _ 0xEC06 _ 0xEC03, 0xF612) +MATHML_CHAR(12, LeftArrowAccent, 0x20D6 _ 0x0000 _ 0x0000 _ 0xEB00, 0x20D6) +MATHML_CHAR(18, RightArrowAccent, 0x0000 _ 0x0000 _ 0x20D7 _ 0xEB00, 0x20D7) +MATHML_CHAR(24, LeftRightArrowAccent,0x20D6 _ 0x0000 _ 0x20D7 _ 0xEB00, 0x20E1) +MATHML_CHAR(30, LeftHarpoonAccent, 0x20D0 _ 0x0000 _ 0x0000 _ 0xEB00, 0x20D0) +MATHML_CHAR(36, RightHarpoonAccent, 0x0000 _ 0x0000 _ 0x20D1 _ 0xEB00, 0x20D1) + #endif // defined(WANT_MTEXTRA_DATA) + +// Data for strecthy chars that are supported by TeX's CMSY font --------------------- +// ----------------------------------------------------------------------------------- + + #if defined(WANT_CMSY_DATA) //[top/left][middle][bot/right][glue] [size0 ... size{N-1}] +MATHML_CHAR( 0, DoubleLeftArrow, 0x21D0 _ 0x0000 _ 0x0000 _ '=', 0x21D0) +MATHML_CHAR( 6, DoubleRightArrow, 0x0000 _ 0x0000 _ 0x21D2 _ '=', 0x21D2) +MATHML_CHAR(12, DoubleLeftRightArrow,0x21D0 _ 0x0000 _ 0x21D2 _ '=', 0x21D4) +MATHML_CHAR(18, DoubleLongLeftArrow, 0x21D0 _ 0x0000 _ 0x0000 _ '=', 0xE200) +MATHML_CHAR(24, DoubleLongRightArrow,0x0000 _ 0x0000 _ 0x21D2 _ '=', 0xE204) +MATHML_CHAR(30, DoubleLongLeftRightArrow, 0x21D0 _ 0x0000 _ 0x21D2 _ '=', 0xE202) + #endif // defined(WANT_CMSY_DATA) + +// Data for strecthy chars that are supported by TeX's CMEX font --------------------- +// ----------------------------------------------------------------------------------- + #if defined(WANT_CMEX_DATA) // [top/left][middle][bot/right][glue] [size0 ... size{N-1}] +MATHML_CHAR( 0, LeftParenthesis, 0xE030 _ 0x0000 _ 0xE040 _ 0xE042, 0x0028 _ 0xE072 _ 0xE089 _ 0xE08B _ 0xE099) +MATHML_CHAR( 10, RightParenthesis, 0xE031 _ 0x0000 _ 0xE041 _ 0xE043, 0x0029 _ 0xE073 _ 0xE08A _ 0xE08C _ 0xE021) +MATHML_CHAR( 20, LeftSquareBracket, 0xE032 _ 0x0000 _ 0xE034 _ 0xE036, 0x005B _ 0xE074 _ 0xE08D _ 0xE05B _ 0xE022) +MATHML_CHAR( 30, RightSquareBracket, 0xE033 _ 0x0000 _ 0xE035 _ 0xE037, 0x005D _ 0xE075 _ 0xE08E _ 0xE05C _ 0xE023) +MATHML_CHAR( 40, LeftFloor, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x230A _ 0xE076 _ 0xE08F _ 0xE05D _ 0xE024) +MATHML_CHAR( 50, RightFloor, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x230B _ 0xE077 _ 0xE090 _ 0xE05E _ 0xE025) +MATHML_CHAR( 60, LeftCeiling, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2308 _ 0xE078 _ 0xE091 _ 0xE05F _ 0xE026) +MATHML_CHAR( 70, RightCeiling, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2309 _ 0xE079 _ 0xE092 _ 0xE060 _ 0xE027) +MATHML_CHAR( 80, LeftCurlyBracket, 0xE038 _ 0xE03C _ 0xE03A _ 0xE03E, 0x007B _ 0xE07A _ 0xE093 _ 0xE061 _ 0xE028) +MATHML_CHAR( 90, RightCurlyBracket, 0xE039 _ 0xE03D _ 0xE03B _ 0xE03E, 0x007D _ 0xE07B _ 0xE094 _ 0xE062 _ 0xE029) +MATHML_CHAR(100, LeftAngleBracket, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x3008 _ 0xE07C _ 0xE095 _ 0xE044 _ 0xE02A) +MATHML_CHAR(110, RightAngleBracket, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x3009 _ 0xE07D _ 0xE096 _ 0xE045 _ 0xE02B) +MATHML_CHAR(120, SquareUnion, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2294 _ 0xE046) +MATHML_CHAR(127, ContourIntegral, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x222E _ 0xE047) +MATHML_CHAR(134, CircleDot, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2299 _ 0xE048) +MATHML_CHAR(141, CirclePlus, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2249 _ 0xE04A) +MATHML_CHAR(148, CircleMultiply, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2297 _ 0xE04B) +MATHML_CHAR(155, Sum, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2211 _ 0xE04C) +MATHML_CHAR(162, Product, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x220F _ 0xE04D) +MATHML_CHAR(169, Slash, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, '/' _ 0xE02E _ 0xE097 _ 0xE080 _ 0xE02C) +MATHML_CHAR(179, Integral, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x222B _ 0xE04E) +MATHML_CHAR(186, Union, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x22C3 _ 0xE04F) +MATHML_CHAR(193, Intersection, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x22C2 _ 0xE050) +MATHML_CHAR(200, UnionPlus, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x228E _ 0xE051) +MATHML_CHAR(207, And, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2227 _ 0xE052) +MATHML_CHAR(214, Or, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2228 _ 0xE053) +MATHML_CHAR(221, Coproduct, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x2210 _ 0xE054) +MATHML_CHAR(228, Hat, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x0302 _ 0xE055 _ 0xE056 _ 0xE057) +MATHML_CHAR(237, Tilde, 0x0000 _ 0x0000 _ 0x0000 _ 0x0000, 0x223C _ 0xE058 _ 0xE059 _ 0xE05A) +MATHML_CHAR(246, Sqrt, 0xE069 _ 0x0000 _ 0xE067 _ 0xE068, 0x221A _ 0xE063 _ 0xE064 _ 0xE065 _ 0xE066) +MATHML_CHAR(256, UpArrow, 0xE06B _ 0x0000 _ 0x0000 _ 0xE03F, 0x2191) +MATHML_CHAR(262, DownArrow, 0x0000 _ 0x0000 _ 0xE06C _ 0xE03F, 0x2193) +MATHML_CHAR(268, UpDownArrow, 0xE06B _ 0x0000 _ 0xE06C _ 0xE03F, 0x2195) +MATHML_CHAR(274, DoubleUpArrow, 0xE071 _ 0x0000 _ 0x0000 _ 0xE06A, 0x21D1) +MATHML_CHAR(280, DoubleDownArrow, 0x0000 _ 0x0000 _ 0xE09A _ 0xE06A, 0x21D3) +MATHML_CHAR(286, DoubleUpDownArrow, 0xE071 _ 0x0000 _ 0xE09A _ 0xE06A, 0x21D5) + #endif // defined(WANT_CMEX_DATA) + +#undef _ +#endif // defined(WANT_CHAR_DATA) || defined(WANT_GLYPH_DATA) + + +#undef MATHML_CHAR diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/layout/mathml/base/src/nsMathMLContainerFrame.cpp index b4aa979c5597..b16aa34b4774 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -70,20 +70,13 @@ // nsISupports // ============================================================================= -NS_IMETHODIMP -nsMathMLContainerFrame::QueryInterface(REFNSIID aIID, void** aInstancePtr) -{ - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - *aInstancePtr = nsnull; - if (aIID.Equals(kIMathMLFrameIID)) { - *aInstancePtr = (void*)(nsIMathMLFrame*)this; - NS_ADDREF_THIS(); // not effectual, frames are not Refcounted - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} +NS_INTERFACE_MAP_BEGIN(nsMathMLContainerFrame) + NS_INTERFACE_MAP_ENTRY(nsIMathMLFrame) +#ifdef NS_DEBUG + NS_INTERFACE_MAP_ENTRY(nsIFrameDebug) +#endif + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMathMLFrame) +NS_INTERFACE_MAP_END_INHERITING(nsHTMLContainerFrame) NS_IMETHODIMP_(nsrefcnt) nsMathMLContainerFrame::AddRef(void) @@ -108,9 +101,15 @@ PRBool nsMathMLContainerFrame::IsOnlyWhitespace(nsIFrame* aFrame) { NS_PRECONDITION(aFrame, "null arg"); - PRBool rv = PR_FALSE; + + // quick return if we have encountered this frame before + nsFrameState state; + aFrame->GetFrameState(&state); + if (NS_FRAME_IS_UNFLOWABLE & state) + return PR_TRUE; // by empty frame we mean a leaf frame whose text content is empty... + PRBool rv = PR_FALSE; nsCOMPtr aContent; aFrame->GetContent(getter_AddRefs(aContent)); if (!aContent) return PR_TRUE; @@ -120,6 +119,10 @@ nsMathMLContainerFrame::IsOnlyWhitespace(nsIFrame* aFrame) nsCOMPtr tc(do_QueryInterface(aContent)); if (tc.get()) tc->IsOnlyWhitespace(&rv); } + if (rv) { + // mark the frame as unflowable + aFrame->SetFrameState(NS_FRAME_IS_UNFLOWABLE | state); + } return rv; } @@ -130,19 +133,57 @@ nsMathMLContainerFrame::GetAttribute(nsIContent* aContent, nsIAtom* aAttributeAtom, nsString& aValue) { + nsresult rv = NS_CONTENT_ATTR_NOT_THERE; + // see if we can get the attribute from the content if (aContent) { - return aContent->GetAttribute(kNameSpaceID_None, aAttributeAtom, aValue); + rv = aContent->GetAttribute(kNameSpaceID_None, aAttributeAtom, aValue); } - // see if we can get the attribute from the mstyle frame - if (aMathMLmstyleFrame) { - nsCOMPtr mstyleContent; - aMathMLmstyleFrame->GetContent(getter_AddRefs(mstyleContent)); - return mstyleContent->GetAttribute(kNameSpaceID_None, aAttributeAtom, aValue); + if (NS_CONTENT_ATTR_NOT_THERE == rv) { + // see if we can get the attribute from the mstyle frame + if (aMathMLmstyleFrame) { + nsCOMPtr mstyleContent; + aMathMLmstyleFrame->GetContent(getter_AddRefs(mstyleContent)); + rv = mstyleContent->GetAttribute(kNameSpaceID_None, aAttributeAtom, aValue); + } } + return rv; +} - return NS_CONTENT_ATTR_NOT_THERE; +void +nsMathMLContainerFrame::GetRuleThickness(nsIRenderingContext& aRenderingContext, + nsIFontMetrics* aFontMetrics, + nscoord& aRuleThickness) +{ + // get the bounding metrics of the overbar char, the rendering context + // is assumed to have been set with the font of the current style context + nsBoundingMetrics bm; + PRUnichar overBar = 0x00AF; + nsresult rv = aRenderingContext.GetBoundingMetrics(&overBar, PRUint32(1), bm); + if (NS_SUCCEEDED(rv)) { + aRuleThickness = bm.ascent + bm.descent; + } + else { + printf("GetBoundingMetrics() failed in GetRuleThickness()\n"); + // fall-back to the other version + GetRuleThickness(aFontMetrics, aRuleThickness); + } + +#if 0 + nscoord xHeight; + aRuleThickness->GetXHeight(xHeight); + + nscoord oldRuleThickness; + GetRuleThickness(aFontMetrics, oldRuleThickness); + + PRUnichar sqrt = 0xE063; // a sqrt glyph from TeX's CMEX font + rv = aRenderingContext.GetBoundingMetrics(&sqrt, PRUint32(1), bm); + nscoord sqrtrule = bm.ascent; // according to TeX, the ascent should be the rule + + printf("xheight:%4d rule:%4d oldrule:%4d sqrtrule:%4d\n", + xHeight, aRuleThickness, oldRuleThickness, sqrtrule); +#endif } // ================ @@ -201,7 +242,7 @@ nsMathMLContainerFrame::ParseNumericValue(nsString& aString, aString.Right(unit, stringLength - i); break; } - number.Append(PRUnichar(c)); + number.Append(c); } #if 0 @@ -221,19 +262,19 @@ printf("String:%s, Number:%s, Unit:%s\n", s1, s2, s3); if (0 == unit.Length()) { cssUnit = eCSSUnit_Number; // no explicit unit, this is a number that will act as a multiplier } - else if (unit == "%") { + else if (unit.Equals("%")) { floatValue = floatValue / 100.0f; aCSSValue.SetPercentValue(floatValue); return PR_TRUE; } - else if (unit == "em") cssUnit = eCSSUnit_EM; - else if (unit == "ex") cssUnit = eCSSUnit_XHeight; - else if (unit == "px") cssUnit = eCSSUnit_Pixel; - else if (unit == "in") cssUnit = eCSSUnit_Inch; - else if (unit == "cm") cssUnit = eCSSUnit_Centimeter; - else if (unit == "mm") cssUnit = eCSSUnit_Millimeter; - else if (unit == "pt") cssUnit = eCSSUnit_Point; - else if (unit == "pc") cssUnit = eCSSUnit_Pica; + else if (unit.Equals("em")) cssUnit = eCSSUnit_EM; + else if (unit.Equals("ex")) cssUnit = eCSSUnit_XHeight; + else if (unit.Equals("px")) cssUnit = eCSSUnit_Pixel; + else if (unit.Equals("in")) cssUnit = eCSSUnit_Inch; + else if (unit.Equals("cm")) cssUnit = eCSSUnit_Centimeter; + else if (unit.Equals("mm")) cssUnit = eCSSUnit_Millimeter; + else if (unit.Equals("pt")) cssUnit = eCSSUnit_Point; + else if (unit.Equals("pc")) cssUnit = eCSSUnit_Pica; else // unexpected unit return PR_FALSE; @@ -278,6 +319,83 @@ nsMathMLContainerFrame::CalcLength(nsIPresContext* aPresContext, return 0; } +// ------------------------- +// error handlers +// by default show the Unicode REPLACEMENT CHARACTER U+FFFD +// when a frame with bad markup can not be rendered +nsresult +nsMathMLContainerFrame::ReflowError(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize) +{ + nsresult rv; + + // clear all other flags and record that there is an error with this frame + mEmbellishData.flags = 0; + mPresentationData.flags = NS_MATHML_ERROR; + + /////////////// + // Set font + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + aRenderingContext.SetFont(font.mFont); + + // bounding metrics + nsAutoString errorMsg = PRUnichar(0xFFFD); + rv = aRenderingContext.GetBoundingMetrics(errorMsg.GetUnicode(), + PRUint32(errorMsg.Length()), + mBoundingMetrics); + if (NS_FAILED(rv)) { + printf("GetBoundingMetrics failed\n"); + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + return NS_OK; + } + + // reflow metrics + nsCOMPtr fm; + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); + fm->GetMaxAscent(aDesiredSize.ascent); + fm->GetMaxDescent(aDesiredSize.descent); + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; + + if (nsnull != aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = aDesiredSize.width; + aDesiredSize.maxElementSize->height = aDesiredSize.height; + } + // Also return our bounding metrics + aDesiredSize.mBoundingMetrics = mBoundingMetrics; + + return NS_OK; +} + +nsresult +nsMathMLContainerFrame::PaintError(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) + { + NS_ASSERTION(NS_MATHML_HAS_ERROR(mPresentationData.flags), + "There is nothing wrong with this frame!"); + // Set color and font ... + nsStyleFont font; + nsStyleColor color; + mStyleContext->GetStyle(eStyleStruct_Font, font); + mStyleContext->GetStyle(eStyleStruct_Color, color); + aRenderingContext.SetColor(color.mColor); + aRenderingContext.SetFont(font.mFont); + + nsAutoString errorMsg = PRUnichar(0xFFFD); + aRenderingContext.DrawString(errorMsg.GetUnicode(), + PRUint32(errorMsg.Length()), + mRect.x, mRect.y); + } + return NS_OK; +} + // ------------------------- void @@ -368,7 +486,7 @@ nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFra aBoundingMetrics.descent = aReflowMetrics.descent; aBoundingMetrics.ascent = aReflowMetrics.ascent; aBoundingMetrics.width = aReflowMetrics.width; -#if 0 +#if 1 printf("GetBoundingMetrics() failed for: "); /* getchar(); */ nsFrame::ListTag(stdout, aFrame); printf("\n"); @@ -385,8 +503,8 @@ NS_IMETHODIMP nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize) + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredStretchSize) { nsresult rv = NS_OK; if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) { @@ -398,6 +516,10 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, } mEmbellishData.flags |= NS_MATHML_STRETCH_DONE; + if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { + printf("WARNING *** it is wrong to fire stretch on a erroneous frame...\n"); + return NS_OK; + } // Pass the stretch to the first non-empty child ... @@ -409,37 +531,39 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Something is wrong somewhere"); if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsHTMLReflowMetrics aReflowMetrics(nsnull); + // And the trick is that the child's rect.x is still holding the descent, + // and rect.y is still holding the ascent ... 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 != mEmbellishData.direction) { + nsHTMLReflowMetrics childSize(aDesiredStretchSize); + aMathMLFrame->GetBoundingMetrics(childSize.mBoundingMetrics); + childSize.descent = rect.x; + childSize.ascent = rect.y; + childSize.height = rect.height; + childSize.width = rect.width; + + nsBoundingMetrics containerSize = aContainerSize; + + 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); + // XXX tune this + containerSize = mBoundingMetrics; } + // do the stretching... aMathMLFrame->Stretch(aPresContext, aRenderingContext, - mEmbellishData.direction, container, childSize); + mEmbellishData.direction, containerSize, childSize); + + // store the updated metrics childFrame->SetRect(aPresContext, nsRect(childSize.descent, childSize.ascent, childSize.width, childSize.height)); // We now have one child that may have changed, re-position all our children - Place(aPresContext, aRenderingContext, PR_TRUE, aReflowMetrics); - - // Prepare the metrics to be returned - aDesiredStretchSize = nsStretchMetrics(aReflowMetrics); - aDesiredStretchSize.leftSpace = childSize.leftSpace; - aDesiredStretchSize.rightSpace = childSize.rightSpace; + Place(aPresContext, aRenderingContext, PR_TRUE, aDesiredStretchSize); // If our parent is not embellished, it means we are the outermost embellished // container and so we put the spacing, otherwise we don't include the spacing, @@ -451,14 +575,27 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, mStyleContext->GetStyle(eStyleStruct_Font, font); nscoord em = NSToCoordRound(float(font.mFont.size)); - // cache these values - mEmbellishData.leftSpace = nscoord( em * aDesiredStretchSize.leftSpace ); - mEmbellishData.rightSpace = nscoord( em * aDesiredStretchSize.rightSpace ); + nsEmbellishData coreData; + mEmbellishData.core->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); + aMathMLFrame->GetEmbellishData(coreData); - aDesiredStretchSize.width += nscoord( (aDesiredStretchSize.leftSpace + aDesiredStretchSize.rightSpace) * em ); - nscoord dx = nscoord( aDesiredStretchSize.leftSpace * em ); + // cache these values + mEmbellishData.leftSpace = coreData.leftSpace; + mEmbellishData.rightSpace = coreData.rightSpace; + + aDesiredStretchSize.width += + NSToCoordRound((coreData.leftSpace + coreData.rightSpace) * em); + +// XXX is this what to do ? + aDesiredStretchSize.mBoundingMetrics.width += + NSToCoordRound((coreData.leftSpace + coreData.rightSpace) * em); + + nscoord dx = nscoord( coreData.leftSpace * em ); if (0 == dx) return NS_OK; + aDesiredStretchSize.mBoundingMetrics.leftBearing += dx; + aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; + nsPoint origin; childFrame = mFrames.FirstChild(); while (childFrame) { @@ -473,9 +610,8 @@ nsMathMLContainerFrame::Stretch(nsIPresContext* aPresContext, return NS_OK; } -NS_IMETHODIMP -nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, - nsIPresContext* aPresContext, +nsresult +nsMathMLContainerFrame::FinalizeReflow(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) { @@ -507,9 +643,11 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, nsresult rv = mParent->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && aMathMLFrame) { aMathMLFrame->GetEmbellishData(parentData); - if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(parentData.flags) || - (NS_MATHML_WILL_STRETCH_FIRST_CHILD(parentData.flags) && - parentData.firstChild == this)) { + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(parentData.flags) || + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(parentData.flags) || + (NS_MATHML_IS_EMBELLISH_OPERATOR(parentData.flags) + && parentData.firstChild == this)) + { parentWillFireStretch = PR_TRUE; } } @@ -530,7 +668,8 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, // 2) With this code, horizontal stretching works. But vertical stretching // is done in some cases where frames could have simply been kept as is. - nsStretchMetrics curSize(aDesiredSize); +// nsStretchMetrics curSize(aDesiredSize); + nsBoundingMetrics curSize = mBoundingMetrics; // 3) With this code, we should get appropriate size when it is done !! @@ -540,14 +679,8 @@ nsMathMLContainerFrame::FinalizeReflow(PRInt32 aDirection, // With the default direction, the MathMLChar will attempt to stretch // in its preferred direction. - nsStretchMetrics newSize(curSize); Stretch(aPresContext, aRenderingContext, NS_STRETCH_DIRECTION_DEFAULT, - curSize, newSize); - - aDesiredSize.width = newSize.width; - aDesiredSize.height = newSize.height; - aDesiredSize.ascent = newSize.ascent; - aDesiredSize.descent = newSize.descent; + curSize, aDesiredSize); } } if (nsnull != aDesiredSize.maxElementSize) { @@ -644,20 +777,26 @@ nsMathMLContainerFrame::SetPresentationData(const nsPresentationData& aPresentat NS_IMETHODIMP nsMathMLContainerFrame::UpdatePresentationData(PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) + PRBool aDisplayStyle, + PRBool aCompressed) { - mPresentationData.scriptLevel += aScriptLevelIncrement; - if (aDisplayStyle) - mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE; - else - mPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE; + mPresentationData.scriptLevel += aScriptLevelIncrement; + if (aDisplayStyle) + mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE; + else + mPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE; + if (aCompressed) + mPresentationData.flags |= NS_MATHML_COMPRESSED; + else + mPresentationData.flags &= ~NS_MATHML_COMPRESSED; return NS_OK; } NS_IMETHODIMP nsMathMLContainerFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) + PRBool aDisplayStyle, + PRBool aCompressed) { nsIFrame* childFrame = mFrames.FirstChild(); while (nsnull != childFrame) { @@ -667,9 +806,9 @@ nsMathMLContainerFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, nsresult rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && nsnull != aMathMLFrame) { // update - aMathMLFrame->UpdatePresentationData(aScriptLevelIncrement, aDisplayStyle); + aMathMLFrame->UpdatePresentationData(aScriptLevelIncrement, aDisplayStyle, aCompressed); // propagate down the subtrees - aMathMLFrame->UpdatePresentationDataFromChildAt(0, aScriptLevelIncrement, aDisplayStyle); + aMathMLFrame->UpdatePresentationDataFromChildAt(0, aScriptLevelIncrement, aDisplayStyle, aCompressed); } } } @@ -686,7 +825,6 @@ nsMathMLContainerFrame::FindSmallestFontSizeFor(nsIPresContext* aPresContext, nsCOMPtr aStyleContext; aFrame->GetStyleContext(getter_AddRefs(aStyleContext)); aStyleContext->GetStyle(eStyleStruct_Font, aFont); -// PRInt32 fontSize = NSTwipsToFloorIntPoints(aFont.mFont.size); PRInt32 fontSize = aFont.mFont.size; PRInt32 childSize; @@ -702,11 +840,38 @@ nsMathMLContainerFrame::FindSmallestFontSizeFor(nsIPresContext* aPresContext, return fontSize; } +// Helper to give a style context suitable for doing the stretching of +// a MathMLChar. Frame classes that use this should ensure that the +// extra leaf style contexts given to the MathMLChars are acessible to +// the Style System via the Get/Set AdditionalStyleContext() APIs. +void +nsMathMLContainerFrame::ResolveMathMLCharStyle(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIStyleContext* aParentStyleContext, + nsMathMLChar* aMathMLChar) +{ + nsAutoString data; + aMathMLChar->GetData(data); + PRBool isStretchy = nsMathMLOperators::MatchOperator(data, NS_MATHML_OPERATOR_STRETCHY); + nsAutoString fontStyle = (isStretchy) ? ":-moz-math-font-style-stretchy" + : ":-moz-math-font-style-anonymous"; + nsCOMPtr fontAtom(getter_AddRefs(NS_NewAtom(fontStyle))); + nsCOMPtr newStyleContext; + nsresult rv = aPresContext->ResolvePseudoStyleContextFor(aContent, fontAtom, + aParentStyleContext, PR_FALSE, + getter_AddRefs(newStyleContext)); + if (NS_SUCCEEDED(rv) && newStyleContext) + aMathMLChar->SetStyleContext(newStyleContext); +} + // helper method to alter the style context // This method is used for switching the font to a subscript/superscript font in // mfrac, msub, msup, msubsup, munder, mover, munderover, mmultiscripts -NS_IMETHODIMP +// XXX change the code to ensure that the size decreases in a top-down manner. +// the coide should always insert top-scriptstyle frames, and inner frames that +// cause the size to decrease pass the smallest limit should be removed +nsresult nsMathMLContainerFrame::InsertScriptLevelStyleContext(nsIPresContext* aPresContext) { nsresult rv = NS_OK; @@ -910,10 +1075,15 @@ nsMathMLContainerFrame::Paint(nsIPresContext* aPresContext, { nsresult rv = NS_OK; - rv = nsHTMLContainerFrame::Paint(aPresContext, - aRenderingContext, - aDirtyRect, - aWhichLayer); + // report an error if something wrong was found in this frame + if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { + return PaintError(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); + } + + rv = nsHTMLContainerFrame::Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); + // for visual debug // ---------------- // if you want to see your bounding box, make sure to properly fill @@ -927,7 +1097,7 @@ nsMathMLContainerFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.SetColor(NS_RGB(0,0,255)); nscoord x = mReference.x + mBoundingMetrics.leftBearing; - nscoord y = mReference.y; + nscoord y = mReference.y - mBoundingMetrics.ascent; nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing; nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent; @@ -947,7 +1117,10 @@ nsMathMLContainerFrame::Init(nsIPresContext* aPresContext, nsresult rv; // first, let the base class do its Init() rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - + + mBoundingMetrics.Clear(); + mReference.x = mReference.y = 0; + // now, if our parent implements the nsIMathMLFrame interface, we inherit // its scriptlevel and displaystyle. If the parent later wishes to increment // with other values, it will do so in its SetInitialChildList() method. @@ -1036,73 +1209,6 @@ nsMathMLContainerFrame::SetInitialChildList(nsIPresContext* aPresContext, return rv; } -#if 0 -// helper method to compute the desired size of a frame -NS_IMETHODIMP -nsMathMLContainerFrame::GetDesiredStretchSize(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - nsHTMLReflowMetrics& aDesiredSize) -{ - nsresult rv = NS_OK; - nsRect rect; - nscoord count = 0; - nsIFrame* childFrame = mFrames.FirstChild(); - while (childFrame) { - if (!IsOnlyWhitespace(childFrame)) { - childFrame->GetRect(rect); - if (IsEmbellishOperator(childFrame)) { - // We have encountered an embellished operator... - // It is treated as if the embellishments were not there! - nsIMathMLFrame* aMathMLFrame = nsnull; - rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); - NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); - if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsEmbellishData embellishData; - aMathMLFrame->GetEmbellishData(embellishData); - embellishData.core->GetRect(rect); - } - } - if (0 == aDirection) { // for horizontal positioning of child frames like in mrow - aDesiredSize.width += rect.width; - if (aDesiredSize.ascent < rect.y) aDesiredSize.ascent = rect.y; - if (aDesiredSize.descent < rect.x) aDesiredSize.descent = rect.x; - } - else if (1 == aDirection) { // for vertical positioning of child frames like in mfrac, munder - if (0 == count) { // it is the ascent and descent of the 'base' that is returned by defaul - aDesiredSize.ascent = rect.y; - aDesiredSize.descent = rect.x; - } - if (aDesiredSize.width < rect.width) aDesiredSize.width = rect.width; - } - count++; - } - rv = childFrame->GetNextSibling(&childFrame); - NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); - } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - // 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; - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); - aPresContext->GetMetricsFor(font.mFont, getter_AddRefs(fm)); - fm->GetMaxAscent(aDesiredSize.ascent); - fm->GetMaxDescent(aDesiredSize.descent); - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - } - if (0 < count && 1 == aDirection && 0 == aDesiredSize.width) { - // Return em - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); - aDesiredSize.width = NSToCoordRound(float(font.mFont.size)); - } - return NS_OK; -} -#endif - - // helper function to reflow token elements // note that mBoundingMetrics is computed here nsresult @@ -1115,11 +1221,15 @@ nsMathMLContainerFrame::ReflowTokenFor(nsIFrame* aFrame, NS_PRECONDITION(aFrame, "null arg"); nsresult rv = NS_OK; + // initializations needed for empty markup like + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.mBoundingMetrics.Clear(); + // 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(aPresContext, nsnull, &childFrame); @@ -1143,20 +1253,21 @@ nsMathMLContainerFrame::ReflowTokenFor(nsIFrame* aFrame, childDesiredSize.width, childDesiredSize.height)); // compute and cache the bounding metrics if (0 == count) - bm = childDesiredSize.mBoundingMetrics; + aDesiredSize.mBoundingMetrics = childDesiredSize.mBoundingMetrics; else - bm += childDesiredSize.mBoundingMetrics; + aDesiredSize.mBoundingMetrics += 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 + // cache the frame's mBoundingMetrics + NS_STATIC_CAST(nsMathMLContainerFrame*, + aFrame)->SetBoundingMetrics(aDesiredSize.mBoundingMetrics); + // place and size children NS_STATIC_CAST(nsMathMLContainerFrame*, - aFrame)->FinalizeReflow(0, aPresContext, *aReflowState.rendContext, + aFrame)->FinalizeReflow(aPresContext, *aReflowState.rendContext, aDesiredSize); return NS_OK; } @@ -1172,7 +1283,8 @@ nsMathMLContainerFrame::PlaceTokenFor(nsIFrame* aFrame, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; nsRect rect; nsIFrame* childFrame; @@ -1187,20 +1299,19 @@ nsMathMLContainerFrame::PlaceTokenFor(nsIFrame* aFrame, childFrame->GetNextSibling(&childFrame); } aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - if (aPlaceOrigin) { - nscoord dy; - nscoord dx = 0; + NS_STATIC_CAST(nsMathMLContainerFrame*, + aFrame)->GetBoundingMetrics(aDesiredSize.mBoundingMetrics); + if (aPlaceOrigin) { + nscoord dy, dx = 0; aFrame->FirstChild(aPresContext, nsnull, &childFrame); while (childFrame) { childFrame->GetRect(rect); - nsHTMLReflowMetrics childSize(nsnull); childSize.width = rect.width; childSize.height = rect.height; - // Place and size the child + // place and size the child dy = aDesiredSize.ascent - rect.y; NS_STATIC_CAST(nsMathMLContainerFrame*, aFrame)->FinishReflowChild(childFrame, aPresContext, @@ -1209,35 +1320,30 @@ nsMathMLContainerFrame::PlaceTokenFor(nsIFrame* aFrame, childFrame->GetNextSibling(&childFrame); } } - nsBoundingMetrics bm; NS_STATIC_CAST(nsMathMLContainerFrame*, - aFrame)->GetBoundingMetrics(bm); - NS_STATIC_CAST(nsMathMLContainerFrame*, - aFrame)->SetReference(nsPoint(0,aDesiredSize.ascent-bm.ascent)); + aFrame)->SetReference(nsPoint(0, aDesiredSize.ascent)); return NS_OK; } -// helper function to reflow all children NS_IMETHODIMP -nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, - nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) +nsMathMLContainerFrame::Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { - NS_PRECONDITION(aDirection==0 || aDirection==1, "Unknown direction"); + nsresult rv; + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.mBoundingMetrics.Clear(); + + ///////////// + // Reflow children + // Asking each child to cache its bounding metrics - nsresult rv = NS_OK; nsReflowStatus childStatus; 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; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { ////////////// @@ -1259,141 +1365,68 @@ nsMathMLContainerFrame::ReflowChildren(PRInt32 aDirection, childFrame->SetRect(aPresContext, nsRect(childDesiredSize.descent, childDesiredSize.ascent, childDesiredSize.width, childDesiredSize.height)); - - 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! - nsIMathMLFrame* aMathMLFrame = nsnull; - rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); - NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); - if (NS_SUCCEEDED(rv) && aMathMLFrame) { - - nsEmbellishData embellishData; - aMathMLFrame->GetEmbellishData(embellishData); - nsRect rect; - embellishData.core->GetRect(rect); - childDesiredSize.descent = rect.x; - childDesiredSize.ascent = rect.y; - childDesiredSize.width = rect.width; - childDesiredSize.height = rect.height; - -#if 0 - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - nsStretchMetrics stretchSize; - aMathMLFrame->GetDesiredStretchSize(aPresContext, renderingContext, stretchSize); - childDesiredSize.descent = stretchSize.descent; - childDesiredSize.ascent = stretchSize.ascent; - childDesiredSize.width = stretchSize.width; - childDesiredSize.height = stretchSize.height; -#endif - } - } - if (0 == aDirection) { // for horizontal positioning of child frames like in mrow - aDesiredSize.width += childDesiredSize.width; - if (aDesiredSize.ascent < childDesiredSize.ascent) aDesiredSize.ascent = childDesiredSize.ascent; - if (aDesiredSize.descent < childDesiredSize.descent) aDesiredSize.descent = childDesiredSize.descent; - } - else if (1 == aDirection) { // for vertical positioning of child frames like in mfrac, munder - if (0 == count) { // it is the ascent and descent of the 'base' that is returned by defaul - aDesiredSize.ascent = childDesiredSize.ascent; - aDesiredSize.descent = childDesiredSize.descent; - } - if (aDesiredSize.width < childDesiredSize.width) aDesiredSize.width = childDesiredSize.width; - } - count++; } rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - // 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; - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); - aPresContext->GetMetricsFor(font.mFont, getter_AddRefs(fm)); - fm->GetMaxAscent(aDesiredSize.ascent); - fm->GetMaxDescent(aDesiredSize.descent); - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - } - if (0 < count && 1 == aDirection && 0 == aDesiredSize.width) { - // Return em - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); - aDesiredSize.width = NSToCoordRound(float(font.mFont.size)); - } - - return NS_OK; -} - -// helper function to stretch all children -NS_IMETHODIMP -nsMathMLContainerFrame::StretchChildren(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize) -{ - nsRect rect; - nsIFrame* childFrame = mFrames.FirstChild(); - while (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. - // Its stretch will be handled separatedly when we receive - // stretch command fired by our parent frame. - } - else { - nsIMathMLFrame* aMathMLFrame; - nsresult rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); - if (NS_SUCCEEDED(rv) && aMathMLFrame) { - // retrieve the metrics that was stored at the ReflowChildren pass - childFrame->GetRect(rect); - nsStretchMetrics childSize(rect.x, rect.y, rect.width, rect.height); - aMathMLFrame->Stretch(aPresContext, aRenderingContext, - aStretchDirection, aContainerSize, childSize); - // store the updated metrics - childFrame->SetRect(aPresContext, - nsRect(childSize.descent, childSize.ascent, - childSize.width, childSize.height)); - } - } - childFrame->GetNextSibling(&childFrame); - } - return NS_OK; -} - -NS_IMETHODIMP -nsMathMLContainerFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; - - ///////////// - // Reflow children - ReflowChildren(0, aPresContext, aDesiredSize, aReflowState, aStatus); ///////////// // If we are a container which is entitled to stretch its children, then we // ask our stretchy children to stretch themselves - nsIRenderingContext& renderingContext = *aReflowState.rendContext; + if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mEmbellishData.flags) || + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mEmbellishData.flags)) { - if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN(mEmbellishData.flags)) { - nsStretchMetrics containerSize(aDesiredSize); - nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; + // get our tentative bounding metrics using Place() + Place(aPresContext, *aReflowState.rendContext, PR_FALSE, aDesiredSize); - StretchChildren(aPresContext, renderingContext, stretchDir, containerSize); + // What size should we use to stretch our stretchy children + // XXX tune this + nsBoundingMetrics containerSize = mBoundingMetrics; + + // get the strech direction + nsStretchDirection stretchDir = + NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mEmbellishData.flags) ? + NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL; + + // fire the stretch on each child + childFrame = mFrames.FirstChild(); + while (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. + // Its stretch will be handled separatedly when we receive + // the stretch command fired by our parent frame. + } + else if (!IsOnlyWhitespace(childFrame)) { + nsIMathMLFrame* aMathMLFrame = nsnull; + rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + // retrieve the metrics that was stored at the previous pass + nsRect rect; + childFrame->GetRect(rect); + aMathMLFrame->GetBoundingMetrics(childDesiredSize.mBoundingMetrics); + childDesiredSize.descent = rect.x; + childDesiredSize.ascent = rect.y; + childDesiredSize.height = rect.height; + childDesiredSize.width = rect.width; + + aMathMLFrame->Stretch(aPresContext, *aReflowState.rendContext, + stretchDir, containerSize, childDesiredSize); + // store the updated metrics + childFrame->SetRect(aPresContext, + nsRect(childDesiredSize.descent, childDesiredSize.ascent, + childDesiredSize.width, childDesiredSize.height)); + } + } + childFrame->GetNextSibling(&childFrame); + } } ///////////// // Place children now by re-adjusting the origins to align the baselines - FinalizeReflow(0, aPresContext, renderingContext, aDesiredSize); + FinalizeReflow(aPresContext, *aReflowState.rendContext, aDesiredSize); aStatus = NS_FRAME_COMPLETE; return NS_OK; @@ -1405,7 +1438,9 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + mBoundingMetrics.Clear(); PRInt32 count = 0; nsBoundingMetrics bm; @@ -1416,8 +1451,10 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); aDesiredSize.width += childSize.width; - if (aDesiredSize.descent < childSize.descent) aDesiredSize.descent = childSize.descent; - if (aDesiredSize.ascent < childSize.ascent) aDesiredSize.ascent = childSize.ascent; + if (aDesiredSize.descent < childSize.descent) + aDesiredSize.descent = childSize.descent; + if (aDesiredSize.ascent < childSize.ascent) + aDesiredSize.ascent = childSize.ascent; // Compute and cache our bounding metrics if (0 == count) @@ -1430,16 +1467,14 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, childFrame->GetNextSibling(&childFrame); } aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.mBoundingMetrics = mBoundingMetrics; if (aPlaceOrigin) { nsRect rect; - - nscoord dy; - nscoord dx = 0; + nscoord dy, dx = 0; childFrame = mFrames.FirstChild(); while (childFrame) { childFrame->GetRect(rect); - childSize.width = rect.width; childSize.height = rect.height; @@ -1453,7 +1488,7 @@ nsMathMLContainerFrame::Place(nsIPresContext* aPresContext, } mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; return NS_OK; } @@ -1495,15 +1530,37 @@ 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) { - return ReflowTokenFor(this, aPresContext, aDesiredSize, - aReflowState, 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, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); + 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; + + mBoundingMetrics = childDesiredSize.mBoundingMetrics; + + mReference.x = 0; + mReference.y = aDesiredSize.ascent; + + FinalizeReflow(aPresContext, *aReflowState.rendContext, aDesiredSize); + } + return rv; } NS_IMETHODIMP @@ -1512,6 +1569,66 @@ nsMathMLWrapperFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - return PlaceTokenFor(this, aPresContext, aRenderingContext, - aPlaceOrigin, aDesiredSize); + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.mBoundingMetrics.Clear(); + + nsIFrame* childFrame = mFrames.FirstChild(); + if (childFrame) { + + // get a possibly updated bounding metrics if the child is + // a stretchy MathML frame that has just been stretched, otherwise + // keep the bounding metrics that was computed in Reflow() + nsIMathMLFrame* aMathMLFrame = nsnull; + nsresult rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + aMathMLFrame->GetBoundingMetrics(mBoundingMetrics); + aMathMLFrame->GetReference(mReference); // XXX doesn't set the correct value (due to lspace) fix me! + } + + nsRect rect; + childFrame->GetRect(rect); + aDesiredSize.descent = rect.x; + aDesiredSize.ascent = rect.y; + aDesiredSize.width = rect.width; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.mBoundingMetrics = mBoundingMetrics; + + if (aPlaceOrigin) { + nsHTMLReflowMetrics childSize(nsnull); + childSize.width = rect.width; + childSize.height = rect.height; + FinishReflowChild(childFrame, aPresContext, childSize, 0, 0, 0); + } + } + return NS_OK; } + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) +NS_IMETHODIMP +nsMathMLWrapperFrame::Paint(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + nsresult rv = NS_OK; + + rv = nsHTMLContainerFrame::Paint(aPresContext, + aRenderingContext, + aDirtyRect, + aWhichLayer); + + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) + { + aRenderingContext.SetColor(NS_RGB(255,0,0)); + + nscoord x = mReference.x + mBoundingMetrics.leftBearing; + nscoord y = mReference.y - mBoundingMetrics.ascent; + nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing; + nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent; + + aRenderingContext.DrawRect(x,y,w,h); + } + return rv; +} +#endif diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.h b/layout/mathml/base/src/nsMathMLContainerFrame.h index 655a589a94b9..3d46415b195e 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -68,10 +68,8 @@ class nsMathMLContainerFrame : public nsHTMLContainerFrame, public nsIMathMLFram public: // nsIMathMLFrame methods -- see documentation in nsIMathMLFrame.h - - NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); + + NS_DECL_ISUPPORTS NS_IMETHOD GetBoundingMetrics(nsBoundingMetrics& aBoundingMetrics); @@ -89,8 +87,8 @@ public: Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize); + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredStretchSize); #if 0 NS_IMETHOD GetDesiredStretchSize(nsIPresContext* aPresContext, @@ -120,12 +118,14 @@ public: NS_IMETHOD UpdatePresentationData(PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle); + PRBool aDisplayStyle, + PRBool aCompressed); NS_IMETHOD UpdatePresentationDataFromChildAt(PRInt32 aIndex, PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle); + PRBool aDisplayStyle, + PRBool aCompressed); // nsHTMLContainerFrame methods @@ -164,6 +164,20 @@ public: nsFramePaintLayer aWhichLayer); #endif + // error handlers to report than an error (typically invalid markup) + // was encountered during reflow. By default the user will see the + // Unicode REPLACEMENT CHAR U+FFFD at the spot where the error was + // encountered. + virtual nsresult + ReflowError(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsHTMLReflowMetrics& aDesiredSize); + virtual nsresult + PaintError(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + // helper function to reflow token elements static nsresult ReflowTokenFor(nsIFrame* aFrame, @@ -194,45 +208,28 @@ public: 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); } - // helper function to reflow all children before placing them. - // With MathML, we have to reflow all children and use their desired size - // information in order to figure out how to lay them. - // aDirection = 0 means children will later be laid horizontally - // aDirection = 1 means children will later be laid vertically - NS_IMETHOD - ReflowChildren(PRInt32 aDirection, - nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); - - // helper function to fire a Stretch command on all children, - // Note that if the container is embellished, the stretch is not fired - // on its embellished child. It is the responsibility of the parent - // of the embellished container to fire a stretch that is then passed - // onto the embellished child. - // If an embellished container doesn't have a parent that will fire - // a stretch, it will do it itself (see FinalizeReflow). - NS_IMETHOD - StretchChildren(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize); - // 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, - nsIPresContext* aPresContext, + virtual nsresult + FinalizeReflow(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsHTMLReflowMetrics& aDesiredSize); // helper method to alter 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 + virtual nsresult InsertScriptLevelStyleContext(nsIPresContext* aPresContext); + // helper to give a style context suitable for doing the stretching to the + // MathMLChar. Frame classes that use this should make the extra style contexts + // accessible to the Style System via Get/Set AdditionalStyleContext + static void + ResolveMathMLCharStyle(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIStyleContext* aParenStyleContext, + nsMathMLChar* aMathMLChar); + // helper to find the smallest font-size on a tree so that we don't insert // scriptlevel fonts that lead to unreadable results on deeper nodes below us. // XXX expensive recursive function, need something better, with cache @@ -245,12 +242,11 @@ public: IsEmbellishOperator(nsIFrame* aFrame); // helper methods for processing empty MathML frames (with whitespace only) - static PRBool - IsOnlyWhitespace(nsIFrame* aFrame); - static void ReflowEmptyChild(nsIPresContext* aPresContext, nsIFrame* aFrame); + static PRBool + IsOnlyWhitespace(nsIFrame* aFrame); // helper method to facilitate getting the reflow and bounding metrics // IMPORTANT: This function is only meant to be called in Place() methods @@ -263,8 +259,9 @@ public: // helper to check if a content has an attribute. If content is nsnull or if // the attribute is not there, check if the attribute is on the mstyle frame. - // @return NS_CONTENT_ATTR_HAS_VALUE --if attribute is there - // NS_CONTENT_ATTR_NOT_THERE --if attribute is not there + // @return NS_CONTENT_ATTR_HAS_VALUE --if attribute has non-empty value, attr="value" + // NS_CONTENT_ATTR_NO_VALUE --if attribute has empty value, attr="" + // NS_CONTENT_ATTR_NOT_THERE --if attribute is not there static nsresult GetAttribute(nsIContent* aContent, nsIFrame* aMathMLmstyleFrame, @@ -309,6 +306,16 @@ public: GetSupDrop (fm, aSupDrop); } + static void + GetSkewCorrectionFromChild (nsIPresContext* aPresContext, + nsIFrame* aChild, + nscoord& aSkewCorrection) + { + // default is 0 + // individual classes should over-ride this method if necessary + aSkewCorrection = 0; + } + // 2 levels of subscript shifts static void GetSubScriptShifts (nsIFontMetrics *fm, @@ -354,8 +361,8 @@ public: static void GetSubShifts (nsIFontMetrics *fm, - nscoord& aSubShift1, - nscoord& aSubShift2) + nscoord& aSubShift1, + nscoord& aSubShift2) { nscoord xHeight = 0; fm->GetXHeight (xHeight); @@ -365,9 +372,9 @@ public: static void GetSupShifts (nsIFontMetrics *fm, - nscoord& aSupShift1, - nscoord& aSupShift2, - nscoord& aSupShift3) + nscoord& aSupShift1, + nscoord& aSupShift2, + nscoord& aSupShift3) { nscoord xHeight = 0; fm->GetXHeight (xHeight); @@ -377,10 +384,10 @@ public: } static void - GetNumShifts (nsIFontMetrics *fm, - nscoord& numShift1, - nscoord& numShift2, - nscoord& numShift3) + GetNumeratorShifts (nsIFontMetrics *fm, + nscoord& numShift1, + nscoord& numShift2, + nscoord& numShift3) { nscoord xHeight = 0; fm->GetXHeight (xHeight); @@ -390,9 +397,9 @@ public: } static void - GetDenShifts (nsIFontMetrics *fm, - nscoord& denShift1, - nscoord& denShift2) + GetDenominatorShifts (nsIFontMetrics *fm, + nscoord& denShift1, + nscoord& denShift2) { nscoord xHeight = 0; fm->GetXHeight (xHeight); @@ -402,7 +409,7 @@ public: static void GetAxisHeight (nsIFontMetrics *fm, - nscoord& axisHeight) + nscoord& axisHeight) { fm->GetXHeight (axisHeight); axisHeight = NSToCoordRound (250.000f/430.556f * axisHeight); @@ -410,11 +417,11 @@ public: static void GetBigOpSpacings (nsIFontMetrics *fm, - nscoord& bigOpSpacing1, - nscoord& bigOpSpacing2, - nscoord& bigOpSpacing3, - nscoord& bigOpSpacing4, - nscoord& bigOpSpacing5) + nscoord& bigOpSpacing1, + nscoord& bigOpSpacing2, + nscoord& bigOpSpacing3, + nscoord& bigOpSpacing4, + nscoord& bigOpSpacing5) { nscoord xHeight = 0; fm->GetXHeight (xHeight); @@ -425,34 +432,23 @@ public: bigOpSpacing5 = NSToCoordRound (100.000f/430.556f * xHeight); } -#if 0 - NS_IMETHOD - GetItalicCorrection (nscoord& italicCorrection) - { - italicCorrection = mItalicCorrection; - - return NS_OK; - } - - NS_IMETHOD - SetItalicCorrection (nscoord italicCorrection) - { - mItalicCorrection = italicCorrection; - - return NS_OK; - } -#endif - - NS_IMETHOD - GetRuleThickness (nsIFontMetrics *fm, nscoord& ruleThickness) + static void + GetRuleThickness(nsIFontMetrics* fm, + nscoord& ruleThickness) { nscoord xHeight; fm->GetXHeight (xHeight); ruleThickness = NSToCoordRound (40.000f/430.556f * xHeight); - - return NS_OK; } + // the rule thickness is not accurately obtained using the x-height. + // Here is a slow GetRuleThickness() which obtains the rule + // thickness by actually measuring the overbar char U+00AF + static void + GetRuleThickness(nsIRenderingContext& aRenderingContext, + nsIFontMetrics* aFontMetrics, + nscoord& aRuleThickness); + protected: // information about the presentation policy of the frame @@ -488,6 +484,14 @@ public: PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize); +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + NS_IMETHOD + Paint(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); +#endif + protected: nsMathMLWrapperFrame(); virtual ~nsMathMLWrapperFrame(); diff --git a/layout/mathml/base/src/nsMathMLParts.h b/layout/mathml/base/src/nsMathMLParts.h index 292142f4be71..c0fb6d036ad9 100644 --- a/layout/mathml/base/src/nsMathMLParts.h +++ b/layout/mathml/base/src/nsMathMLParts.h @@ -28,7 +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_NewMathMLmtextFrame ( 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 ); @@ -44,6 +44,7 @@ extern nsresult NS_NewMathMLmoverFrame ( nsIPresShell* aPresShell, nsIFrame** aN extern nsresult NS_NewMathMLmunderoverFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmmultiscriptsFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmstyleFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); +extern nsresult NS_NewMathMLmtableOuterFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmtdFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmsqrtFrame( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); extern nsresult NS_NewMathMLmrootFrame( nsIPresShell* aPresShell, nsIFrame** aNewFrame ); diff --git a/layout/mathml/base/src/nsMathMLmactionFrame.cpp b/layout/mathml/base/src/nsMathMLmactionFrame.cpp index 1e75c41392d2..111a066b9ca6 100644 --- a/layout/mathml/base/src/nsMathMLmactionFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmactionFrame.cpp @@ -233,7 +233,7 @@ nsMathMLmactionFrame::GetSelectedFrame() mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; if (mSelectedFrame) { nsIMathMLFrame* aMathMLFrame = nsnull; - rv = mSelectedFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + rv = mSelectedFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); if (NS_SUCCEEDED(rv) && aMathMLFrame) { nsEmbellishData embellishData; aMathMLFrame->GetEmbellishData(embellishData); @@ -270,10 +270,10 @@ nsMathMLmactionFrame::SetInitialChildList(nsIPresContext* aPresContext, // Return the selected frame ... NS_IMETHODIMP -nsMathMLmactionFrame::GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, +nsMathMLmactionFrame::GetFrameForPoint(nsIPresContext* aPresContext, + const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame) + nsIFrame** aFrame) { nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) @@ -292,7 +292,7 @@ nsMathMLmactionFrame::Paint(nsIPresContext* aPresContext, const nsStyleDisplay* disp = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display); if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - if (disp->mVisible && mRect.width && mRect.height) { + if (disp->IsVisible() && mRect.width && mRect.height) { // Paint our background and border PRIntn skipSides = GetSkipSides(); const nsStyleColor* color = (const nsStyleColor*) @@ -317,42 +317,6 @@ nsMathMLmactionFrame::Paint(nsIPresContext* aPresContext, return NS_OK; } -// Only reflow the selected child ... -NS_IMETHODIMP -nsMathMLmactionFrame::ReflowChildren(PRInt32 aDirection, - nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; - aStatus = NS_FRAME_COMPLETE; - nsIFrame* childFrame = GetSelectedFrame(); - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; - if (childFrame) { - // ask the child to compute its bounding metrics - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, - aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); - nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); - nsHTMLReflowState childReflowState(aPresContext, aReflowState, - childFrame, availSize); - rv = 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)); - - aDesiredSize.width = childDesiredSize.width; - aDesiredSize.ascent = childDesiredSize.ascent; - aDesiredSize.descent = childDesiredSize.descent; - aDesiredSize.height = childDesiredSize.height; - } - return NS_OK; -} - // Only place the selected child ... NS_IMETHODIMP nsMathMLmactionFrame::Place(nsIPresContext* aPresContext, @@ -360,7 +324,9 @@ nsMathMLmactionFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + mBoundingMetrics.Clear(); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { GetReflowAndBoundingMetricsFor(childFrame, aDesiredSize, mBoundingMetrics); @@ -368,8 +334,9 @@ nsMathMLmactionFrame::Place(nsIPresContext* aPresContext, FinishReflowChild(childFrame, aPresContext, aDesiredSize, 0, 0, 0); } mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; } + aDesiredSize.mBoundingMetrics = mBoundingMetrics; return NS_OK; } diff --git a/layout/mathml/base/src/nsMathMLmactionFrame.h b/layout/mathml/base/src/nsMathMLmactionFrame.h index 37eb1caa7bdc..7e56b01956df 100644 --- a/layout/mathml/base/src/nsMathMLmactionFrame.h +++ b/layout/mathml/base/src/nsMathMLmactionFrame.h @@ -57,10 +57,10 @@ public: nsIFrame* aChildList); NS_IMETHOD - GetFrameForPoint(nsIPresContext* aPresContext, - const nsPoint& aPoint, + GetFrameForPoint(nsIPresContext* aPresContext, + const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, - nsIFrame** aFrame); + nsIFrame** aFrame); NS_IMETHOD Paint(nsIPresContext* aPresContext, @@ -68,13 +68,6 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); - NS_IMETHOD - ReflowChildren(PRInt32 aDirection, - nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); - NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/mathml/base/src/nsMathMLmfencedFrame.cpp b/layout/mathml/base/src/nsMathMLmfencedFrame.cpp index ca048d7297b5..521fce9cc91a 100644 --- a/layout/mathml/base/src/nsMathMLmfencedFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmfencedFrame.cpp @@ -77,11 +77,16 @@ nsMathMLmfencedFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; + mOpenChar = nsnull; mCloseChar = nsnull; mSeparatorsChar = nsnull; mSeparatorsCount = 0; +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -97,7 +102,7 @@ nsMathMLmfencedFrame::SetInitialChildList(nsIPresContext* aPresContext, rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); if (NS_FAILED(rv)) return rv; - rv = ReCreateFencesAndSeparators(); + rv = ReCreateFencesAndSeparators(aPresContext); return rv; } @@ -116,7 +121,7 @@ nsMathMLmfencedFrame::RemoveFencesAndSeparators() } nsresult -nsMathMLmfencedFrame::ReCreateFencesAndSeparators() +nsMathMLmfencedFrame::ReCreateFencesAndSeparators(nsIPresContext* aPresContext) { nsresult rv; @@ -126,42 +131,56 @@ nsMathMLmfencedFrame::ReCreateFencesAndSeparators() ////////////// // see if the opening fence is there ... - if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, - nsMathMLAtoms::open_, value)) { + rv = GetAttribute(mContent, mPresentationData.mstyle, + nsMathMLAtoms::open_, value); + if (NS_CONTENT_ATTR_HAS_VALUE == rv) { value.Trim(" "); data = value; } - else data = '('; // default as per the MathML REC + else if (NS_CONTENT_ATTR_NOT_THERE == rv) + data = '('; // default as per the MathML REC + else + data = ""; if (0 < data.Length()) { mOpenChar = new nsMathMLChar; if (!mOpenChar) return NS_ERROR_OUT_OF_MEMORY; - mOpenChar->SetData(data); + mOpenChar->SetData(aPresContext, data); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar); } ////////////// // see if the closing fence is there ... - if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, - nsMathMLAtoms::close_, value)) { + rv = GetAttribute(mContent, mPresentationData.mstyle, + nsMathMLAtoms::close_, value); + if (NS_CONTENT_ATTR_HAS_VALUE == rv) { value.Trim(" "); data = value; } - else data = ')'; // default as per the MathML REC + else if (NS_CONTENT_ATTR_NOT_THERE == rv) + data = ')'; // default as per the MathML REC + else + data = ""; if (0 < data.Length()) { mCloseChar = new nsMathMLChar; if (!mCloseChar) return NS_ERROR_OUT_OF_MEMORY; - mCloseChar->SetData(data); + mCloseChar->SetData(aPresContext, data); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar); } ////////////// // see if separators are there ... - if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, - nsMathMLAtoms::separators_, value)) { + rv = GetAttribute(mContent, mPresentationData.mstyle, + nsMathMLAtoms::separators_, value); + if (NS_CONTENT_ATTR_HAS_VALUE == rv) { value.Trim(" "); data = value; } - else data = ','; // default as per the MathML REC + else if (NS_CONTENT_ATTR_NOT_THERE == rv) + data = ','; // default as per the MathML REC + else + data = ""; mSeparatorsCount = data.Length(); if (0 < mSeparatorsCount) { @@ -180,7 +199,8 @@ nsMathMLmfencedFrame::ReCreateFencesAndSeparators() nsAutoString sepChar; for (PRInt32 i = 0; i < sepCount; i++) { sepChar = (i < mSeparatorsCount) ? data[i] : data[mSeparatorsCount-1]; - mSeparatorsChar[i].SetData(sepChar); + mSeparatorsChar[i].SetData(aPresContext, sepChar); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i]); } } mSeparatorsCount = sepCount; @@ -202,11 +222,14 @@ nsMathMLmfencedFrame::Paint(nsIPresContext* aPresContext, aDirtyRect, aWhichLayer); //////////// // paint fences and separators - if (NS_SUCCEEDED(rv) && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { - if (mOpenChar) mOpenChar->Paint(aPresContext, aRenderingContext, mStyleContext); - if (mCloseChar) mCloseChar->Paint(aPresContext, aRenderingContext, mStyleContext); + if (NS_SUCCEEDED(rv)) { + if (mOpenChar) mOpenChar->Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); + if (mCloseChar) mCloseChar->Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); for (PRInt32 i = 0; i < mSeparatorsCount; i++) { - mSeparatorsChar[i].Paint(aPresContext, aRenderingContext, mStyleContext); + mSeparatorsChar[i].Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); } } return rv; @@ -218,172 +241,225 @@ nsMathMLmfencedFrame::Reflow(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - nsresult rv = NS_OK; + nsresult rv; + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + + ///////////// + // Reflow children + // Asking each child to cache its bounding metrics + nsReflowStatus childStatus; - nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize); nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight); - - ////////////////// - // Reflow Children - - nsRect rect; - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + nsHTMLReflowMetrics childDesiredSize(aDesiredSize.maxElementSize, + aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { ////////////// // WHITESPACE: don't forget that whitespace doesn't count in MathML! if (IsOnlyWhitespace(childFrame)) { - ReflowEmptyChild(aPresContext, childFrame); + ReflowEmptyChild(aPresContext, childFrame); } else { nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); - rv = ReflowChild(childFrame, aPresContext, - childDesiredSize, childReflowState, childStatus); + rv = ReflowChild(childFrame, aPresContext, childDesiredSize, + childReflowState, childStatus); NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); - if (NS_FAILED(rv)) { - return rv; - } + if (NS_FAILED(rv)) return rv; - // At this stage, the origin points of the children have no use, so we - // will use the origins as placeholders to store the child's ascent and - // descent. Before return, we should set the origins so as to overwrite - // what we are storing there now. + // At this stage, the origin points of the children have no use, so we will use the + // origins as placeholders to store the child's ascent and descent. Later on, + // we should set the origins so as to overwrite what we are storing there now. childFrame->SetRect(aPresContext, nsRect(childDesiredSize.descent, childDesiredSize.ascent, childDesiredSize.width, childDesiredSize.height)); - - aDesiredSize.width += childDesiredSize.width; - if (aDesiredSize.ascent < childDesiredSize.ascent) { - aDesiredSize.ascent = childDesiredSize.ascent; - } - if (aDesiredSize.descent < childDesiredSize.descent) { - aDesiredSize.descent = childDesiredSize.descent; - } } rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + + // get our bounding metrics using a tentative Place() + Place(aPresContext, *aReflowState.rendContext, PR_FALSE, aDesiredSize); + + // What size should we use to stretch our stretchy children + // XXX tune this + nsBoundingMetrics containerSize = mBoundingMetrics; ///////////// // Ask stretchy children to stretch themselves nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; - nsStretchMetrics parentSize(aDesiredSize); - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; - - childFrame = mFrames.FirstChild(); - while (childFrame) { - // retrieve the metrics that was stored at the previous pass - childFrame->GetRect(rect); - nsStretchMetrics childSize(rect.x, rect.y, rect.width, rect.height); - ////////// - // Stretch ... - // Only directed at frames that implement the nsIMathMLFrame interface - nsIMathMLFrame* aMathMLFrame; - rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); - if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - aMathMLFrame->Stretch(aPresContext, renderingContext, - stretchDir, parentSize, childSize); - // store the updated metrics - childFrame->SetRect(aPresContext, - nsRect(childSize.descent, childSize.ascent, - childSize.width, childSize.height)); - } - aDesiredSize.width += childSize.width; - if (aDesiredSize.ascent < childSize.ascent) { - aDesiredSize.ascent = childSize.ascent; - } - if (aDesiredSize.descent < childSize.descent) { - aDesiredSize.descent = childSize.descent; - } - childFrame->GetNextSibling(&childFrame); - } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - ////////////////////////////////////////// - // Prepare the opening fence, separators, and closing fence, and - // adjust the x-origin of children. - - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); - renderingContext.SetFont(font.mFont); - - // grab some metrics that will help to adjust the placements - nsCOMPtr fm; - nscoord fontAscent, fontDescent, em; - renderingContext.GetFontMetrics(*getter_AddRefs(fm)); - fm->GetMaxAscent(fontAscent); - fm->GetMaxDescent(fontDescent); - em = NSToCoordRound(float(font.mFont.size)); - parentSize = nsStretchMetrics(aDesiredSize); - - nscoord dx = 0; // running x-origin of children ... - - ///////////////// - // opening fence ... - ReflowChar(aPresContext, renderingContext, mStyleContext, mOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, - mPresentationData.scriptLevel, fontAscent, fontDescent, em, parentSize, aDesiredSize, dx); - ///////////////// - // separators ... - PRInt32 i = 0; + nsRect rect; + childFrame = mFrames.FirstChild(); while (childFrame) { if (!IsOnlyWhitespace(childFrame)) { - childFrame->GetRect(rect); - childFrame->MoveTo(aPresContext, dx, rect.y); - dx += rect.width; - if (i < mSeparatorsCount) { - ReflowChar(aPresContext, renderingContext, mStyleContext, &mSeparatorsChar[i], NS_MATHML_OPERATOR_FORM_INFIX, - mPresentationData.scriptLevel, fontAscent, fontDescent, em, parentSize, aDesiredSize, dx); - i++; + nsIMathMLFrame* aMathMLFrame; + rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && aMathMLFrame) { + // retrieve the metrics that was stored at the previous pass + childFrame->GetRect(rect); + aMathMLFrame->GetBoundingMetrics(childDesiredSize.mBoundingMetrics); + childDesiredSize.descent = rect.x; + childDesiredSize.ascent = rect.y; + childDesiredSize.height = rect.height; + childDesiredSize.width = rect.width; + + aMathMLFrame->Stretch(aPresContext, *aReflowState.rendContext, + stretchDir, containerSize, childDesiredSize); + // store the updated metrics + childFrame->SetRect(aPresContext, + nsRect(childDesiredSize.descent, childDesiredSize.ascent, + childDesiredSize.width, childDesiredSize.height)); + + if (aDesiredSize.descent < childDesiredSize.descent) + aDesiredSize.descent = childDesiredSize.descent; + if (aDesiredSize.ascent < childDesiredSize.ascent) + aDesiredSize.ascent = childDesiredSize.ascent; } } childFrame->GetNextSibling(&childFrame); } + + ////////////////////////////////////////// + // Prepare the opening fence, separators, and closing fence, and + // adjust the origin of children. + + PRInt32 i; + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + nsCOMPtr fm; + aPresContext->GetMetricsFor(font.mFont, getter_AddRefs(fm)); + nscoord axisHeight, em; + GetAxisHeight(fm, axisHeight); + em = NSToCoordRound(float(font.mFont.size)); + + nscoord fontAscent, fontDescent; + fm->GetMaxAscent(fontAscent); + fm->GetMaxDescent(fontDescent); + + // we need to center around the axis + nscoord delta = PR_MAX(containerSize.ascent - axisHeight, + containerSize.descent + axisHeight); + containerSize.ascent = delta + axisHeight; + containerSize.descent = delta - axisHeight; + + ///////////////// + // opening fence ... + ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar, + NS_MATHML_OPERATOR_FORM_PREFIX, mPresentationData.scriptLevel, + fontAscent, fontDescent, axisHeight, em, + containerSize, aDesiredSize); + ///////////////// + // separators ... + for (i = 0; i < mSeparatorsCount; i++) { + ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i], + NS_MATHML_OPERATOR_FORM_INFIX, mPresentationData.scriptLevel, + fontAscent, fontDescent, axisHeight, em, + containerSize, aDesiredSize); + } ///////////////// // closing fence ... - ReflowChar(aPresContext, renderingContext, mStyleContext, mCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, - mPresentationData.scriptLevel, fontAscent, fontDescent, em, parentSize, aDesiredSize, dx); - - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar, + NS_MATHML_OPERATOR_FORM_POSTFIX, mPresentationData.scriptLevel, + fontAscent, fontDescent, axisHeight, em, + containerSize, aDesiredSize); ////////////////// - // Adjust the y-origin of each child. - + // Adjust the origins of each child. + // and update our bounding metrics + + i = 0; + nscoord dy, dx = 0; + nsBoundingMetrics bm; + PRBool firstTime = PR_TRUE; + mBoundingMetrics.Clear(); + if (mOpenChar) { + mOpenChar->GetBoundingMetrics(bm); + mOpenChar->GetRect(rect); + dy = aDesiredSize.ascent - rect.y; + if (mOpenChar->GetEnum() == eMathMLChar_DONT_STRETCH) + dy += (fontAscent - bm.ascent); + mOpenChar->SetRect(nsRect(dx + rect.x, dy, + bm.width, rect.height)); + dx += rect.width; + + bm.descent = (bm.ascent + bm.descent) - rect.y; + bm.ascent = rect.y; + mBoundingMetrics = bm; + firstTime = PR_FALSE; + } + childFrame = mFrames.FirstChild(); while (childFrame) { if (!IsOnlyWhitespace(childFrame)) { - childFrame->GetRect(rect); - - // childFrame->MoveTo(aPresContext, rect.x, aDesiredSize.ascent - rect.y); nsHTMLReflowMetrics childSize(nsnull); - childSize.width = rect.width; - childSize.height = rect.height; - FinishReflowChild(childFrame, aPresContext, childSize, rect.x, aDesiredSize.ascent - rect.y, 0); + GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); + if (firstTime) { + firstTime = PR_FALSE; + mBoundingMetrics = bm; + } + else + mBoundingMetrics += bm; + + FinishReflowChild(childFrame, aPresContext, childSize, + dx, aDesiredSize.ascent - childSize.ascent, 0); + dx += childSize.width; + + if (i < mSeparatorsCount) { + mSeparatorsChar[i].GetBoundingMetrics(bm); + mSeparatorsChar[i].GetRect(rect); + dy = aDesiredSize.ascent - rect.y; + if (mSeparatorsChar[i].GetEnum() == eMathMLChar_DONT_STRETCH) + dy += (fontAscent - bm.ascent); + mSeparatorsChar[i].SetRect(nsRect(dx + rect.x, dy, + bm.width, rect.height)); + dx += rect.width; + + bm.descent = (bm.ascent + bm.descent) - rect.y; + bm.ascent = rect.y; + bm.leftBearing += rect.x; + bm.rightBearing += rect.x; + bm.width = rect.width; + mBoundingMetrics += bm; + } + i++; } childFrame->GetNextSibling(&childFrame); } - if (mOpenChar) { - mOpenChar->GetRect(rect); - mOpenChar->SetRect(nsRect(rect.x, aDesiredSize.ascent - rect.y, rect.width, rect.height)); - } + if (mCloseChar) { + mCloseChar->GetBoundingMetrics(bm); mCloseChar->GetRect(rect); - mCloseChar->SetRect(nsRect(rect.x, aDesiredSize.ascent - rect.y, rect.width, rect.height)); - } - for (i = 0; i < mSeparatorsCount; i++) { - mSeparatorsChar[i].GetRect(rect); - mSeparatorsChar[i].SetRect(nsRect(rect.x, aDesiredSize.ascent - rect.y, rect.width, rect.height)); + dy = aDesiredSize.ascent - rect.y; + if (mCloseChar->GetEnum() == eMathMLChar_DONT_STRETCH) + dy += (fontAscent - bm.ascent); + mCloseChar->SetRect(nsRect(dx + rect.x, dy, + bm.width, rect.height)); + bm.descent = (bm.ascent + bm.descent) - rect.y; + bm.ascent = rect.y; + bm.leftBearing += rect.x; + bm.rightBearing += rect.x; + bm.width = rect.width; + if (firstTime) + mBoundingMetrics = bm; + else + mBoundingMetrics += bm; } + aDesiredSize.width = mBoundingMetrics.width; + aDesiredSize.mBoundingMetrics = mBoundingMetrics; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + + mReference.x = 0; + mReference.y = aDesiredSize.ascent; + if (aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + aStatus = NS_FRAME_COMPLETE; return NS_OK; } @@ -392,61 +468,133 @@ nsMathMLmfencedFrame::Reflow(nsIPresContext* aPresContext, nsresult nsMathMLmfencedFrame::ReflowChar(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, nsMathMLChar* aMathMLChar, nsOperatorFlags aForm, PRInt32 aScriptLevel, nscoord fontAscent, nscoord fontDescent, + nscoord axisHeight, nscoord em, - nsStretchMetrics& aContainerSize, - nsHTMLReflowMetrics& aDesiredSize, - nscoord& aX) + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredSize) { if (aMathMLChar && 0 < aMathMLChar->Length()) { - nsStretchMetrics aCharSize(fontDescent, fontAscent, 0, fontDescent + fontAscent); - aRenderingContext.GetWidth(aMathMLChar->GetUnicode(), - PRUint32(aMathMLChar->Length()), - aCharSize.width); + // stretch the char to the appropriate height if it is not big enough. + nsBoundingMetrics charSize; + charSize.Clear(); // this will tell stretch that we don't know the default size + aMathMLChar->Stretch(aPresContext, aRenderingContext, + NS_STRETCH_DIRECTION_VERTICAL, + aContainerSize, charSize); + + if (eMathMLChar_DONT_STRETCH != aMathMLChar->GetEnum()) + { + // has changed... so center the char around the axis + nscoord height = charSize.ascent + charSize.descent; + charSize.ascent = height/2 + axisHeight; + charSize.descent = height - charSize.ascent; + + } + else { + charSize.ascent = fontAscent; + charSize.descent = fontDescent; + } + + if (aDesiredSize.ascent < charSize.ascent) + aDesiredSize.ascent = charSize.ascent; + if (aDesiredSize.descent < charSize.descent) + aDesiredSize.descent = charSize.descent; + nsOperatorFlags aFlags; float aLeftSpace = 0.0f; float aRightSpace = 0.0f; + nsAutoString aData; aMathMLChar->GetData(aData); PRBool found = nsMathMLOperators::LookupOperator(aData, aForm, - &aFlags, &aLeftSpace, &aRightSpace); - if (found) { - // If we don't want extra space when we are a script - if (aScriptLevel > 0) { - aLeftSpace /= 2.0f; - aRightSpace /= 2.0f; - } - if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) { - // Stretch the operator to the appropriate height if it is not big enough. - aMathMLChar->Stretch(aPresContext, aRenderingContext, aStyleContext, - NS_STRETCH_DIRECTION_VERTICAL, - aContainerSize, aCharSize); - } + &aFlags, &aLeftSpace, &aRightSpace); + + // If we don't want extra space when we are a script + if (found && aScriptLevel > 0) { + aLeftSpace /= 2.0f; + aRightSpace /= 2.0f; } - else { // call an involutive Stretch() to properly initialize and prepare the char - aMathMLChar->Stretch(aPresContext, aRenderingContext, aStyleContext, - NS_STRETCH_DIRECTION_VERTICAL, - aCharSize, aCharSize); - } - if (aDesiredSize.ascent < aCharSize.ascent) - aDesiredSize.ascent = aCharSize.ascent; - if (aDesiredSize.descent < aCharSize.descent) - aDesiredSize.descent = aCharSize.descent; - // y-origin is used to store the ascent ... - aMathMLChar->SetRect(nsRect(aX + nscoord( aLeftSpace * em ), - aCharSize.ascent, aCharSize.width, aCharSize.height)); // account the spacing - aCharSize.width += nscoord( (aLeftSpace + aRightSpace) * em ); + charSize.width += NSToCoordRound((aLeftSpace + aRightSpace) * em); - aDesiredSize.width += aCharSize.width; - aX += aCharSize.width; + // x-origin is used to store lspace ... + // y-origin is used to stored the ascent ... + aMathMLChar->SetRect(nsRect(NSToCoordRound(aLeftSpace * em), + charSize.ascent, charSize.width, + charSize.ascent + charSize.descent)); + } + return NS_OK; +} + +// ---------------------- +// the Style System will use these to pass the proper style context to our MathMLChar +NS_IMETHODIMP +nsMathMLmfencedFrame::GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const +{ + NS_PRECONDITION(aStyleContext, "null OUT ptr"); + PRInt32 openIndex = -1; + PRInt32 closeIndex = -1; + PRInt32 lastIndex = mSeparatorsCount-1; + + if (mOpenChar) { + lastIndex++; + openIndex = lastIndex; + } + if (mCloseChar) { + lastIndex++; + closeIndex = lastIndex; + } + if (aIndex < 0 || aIndex > lastIndex) { + return NS_ERROR_INVALID_ARG; + } + + *aStyleContext = nsnull; + if (aIndex < mSeparatorsCount) { + mSeparatorsChar[aIndex].GetStyleContext(aStyleContext); + } + else if (aIndex == openIndex) { + mOpenChar->GetStyleContext(aStyleContext); + } + else if (aIndex == closeIndex) { + mCloseChar->GetStyleContext(aStyleContext); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmfencedFrame::SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext) +{ + PRInt32 openIndex = -1; + PRInt32 closeIndex = -1; + PRInt32 lastIndex = mSeparatorsCount-1; + + if (mOpenChar) { + lastIndex++; + openIndex = lastIndex; + } + if (mCloseChar) { + lastIndex++; + closeIndex = lastIndex; + } + if (aIndex < 0 || aIndex > lastIndex) { + return NS_ERROR_INVALID_ARG; + } + + if (aIndex < mSeparatorsCount) { + mSeparatorsChar[aIndex].SetStyleContext(aStyleContext); + } + else if (aIndex == openIndex) { + mOpenChar->SetStyleContext(aStyleContext); + } + else if (aIndex == closeIndex) { + mCloseChar->SetStyleContext(aStyleContext); } - return NS_OK; } diff --git a/layout/mathml/base/src/nsMathMLmfencedFrame.h b/layout/mathml/base/src/nsMathMLmfencedFrame.h index 4373fbe04edc..2db947b7a749 100644 --- a/layout/mathml/base/src/nsMathMLmfencedFrame.h +++ b/layout/mathml/base/src/nsMathMLmfencedFrame.h @@ -33,7 +33,14 @@ class nsMathMLmfencedFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); - + + NS_IMETHOD + SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext); + NS_IMETHOD + GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const; + NS_IMETHOD Init(nsIPresContext* aPresContext, nsIContent* aContent, @@ -73,16 +80,15 @@ protected: static nsresult ReflowChar(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, - nsIStyleContext* aStyleContext, nsMathMLChar* aMathMLChar, nsOperatorFlags aForm, PRInt32 aScriptLevel, nscoord fontAscent, nscoord fontDescent, + nscoord axisHeight, nscoord em, - nsStretchMetrics& aContainerSize, - nsHTMLReflowMetrics& aDesiredSize, - nscoord& aX); + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredSize); // clean up void @@ -90,7 +96,7 @@ protected: // add fences and separators when all child frames are known nsresult - ReCreateFencesAndSeparators(); + ReCreateFencesAndSeparators(nsIPresContext* aPresContext); }; #endif /* nsMathMLmfencedFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmfracFrame.cpp b/layout/mathml/base/src/nsMathMLmfracFrame.cpp index 7fc472e4a4e8..026e9926a024 100644 --- a/layout/mathml/base/src/nsMathMLmfracFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmfracFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ @@ -43,6 +44,17 @@ // -- form a fraction from two subexpressions - implementation // +// various fraction line thicknesses (multiplicative values of the default rule thickness) + +#define THIN_FRACTION_LINE 0.5f +#define THIN_FRACTION_LINE_MINIMUM_PIXELS 1 // minimum of 1 pixel + +#define MEDIUM_FRACTION_LINE 1.5f +#define MEDIUM_FRACTION_LINE_MINIMUM_PIXELS 2 // minimum of 2 pixels + +#define THICK_FRACTION_LINE 2.0f +#define THICK_FRACTION_LINE_MINIMUM_PIXELS 4 // minimum of 4 pixels + nsresult NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { @@ -58,7 +70,8 @@ NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) return NS_OK; } -nsMathMLmfracFrame::nsMathMLmfracFrame() +nsMathMLmfracFrame::nsMathMLmfracFrame() : + mLineRect() { } @@ -80,52 +93,71 @@ nsMathMLmfracFrame::Init(nsIPresContext* aPresContext, return rv; } - nsAutoString value; +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif + return rv; +} - float p2t; - aPresContext->GetScaledPixelsToTwips(&p2t); - nscoord onePixel = NSIntPixelsToTwips(1, p2t); +nscoord +nsMathMLmfracFrame::CalcLineThickness(nsIPresContext* aPresContext, + nsIStyleContext* aStyleContext, + nsString& aThicknessAttribute, + nscoord onePixel, + nscoord aDefaultRuleThickness) +{ + nscoord defaultThickness = aDefaultRuleThickness; + nscoord lineThickness = aDefaultRuleThickness; + nscoord minimumThickness = onePixel; - nscoord defaultThickness = onePixel * DEFAULT_FRACTION_LINE_THICKNESS; - - mLineThickness = defaultThickness; - - // see if the linethickness attribute is there - if (NS_CONTENT_ATTR_HAS_VALUE == - GetAttribute(mContent, mPresentationData.mstyle, - nsMathMLAtoms::linethickness_, value)) - { - if (value == "thin") - mLineThickness = onePixel * THIN_FRACTION_LINE_THICKNESS; - else if (value == "medium") - mLineThickness = onePixel * MEDIUM_FRACTION_LINE_THICKNESS; - else if (value == "thick") - mLineThickness = onePixel * THICK_FRACTION_LINE_THICKNESS; + if (0 < aThicknessAttribute.Length()) { + if (aThicknessAttribute.Equals("thin")) { + lineThickness = NSToCoordFloor(defaultThickness * THIN_FRACTION_LINE); + minimumThickness = onePixel * THIN_FRACTION_LINE_MINIMUM_PIXELS; + // should visually decrease by at least one pixel, if default is not a pixel + if (defaultThickness > onePixel && lineThickness > defaultThickness - onePixel) + lineThickness = defaultThickness - onePixel; + } + else if (aThicknessAttribute.Equals("medium")) { + lineThickness = NSToCoordRound(defaultThickness * MEDIUM_FRACTION_LINE); + minimumThickness = onePixel * MEDIUM_FRACTION_LINE_MINIMUM_PIXELS; + // should visually increase by at least one pixel + if (lineThickness < defaultThickness + onePixel) + lineThickness = defaultThickness + onePixel; + } + else if (aThicknessAttribute.Equals("thick")) { + lineThickness = NSToCoordCeil(defaultThickness * THICK_FRACTION_LINE); + minimumThickness = onePixel * THICK_FRACTION_LINE_MINIMUM_PIXELS; + // should visually increase by at least two pixels + if (lineThickness < defaultThickness + 2*onePixel) + lineThickness = defaultThickness + 2*onePixel; + } else { // see if it is a plain number, or a percentage, or a h/v-unit like 1ex, 2px, 1em nsCSSValue cssValue; - if (ParseNumericValue(value, cssValue)) { + if (ParseNumericValue(aThicknessAttribute, cssValue)) { nsCSSUnit unit = cssValue.GetUnit(); if (eCSSUnit_Number == unit) - mLineThickness = nscoord(float(defaultThickness) * cssValue.GetFloatValue()); + lineThickness = nscoord(float(defaultThickness) * cssValue.GetFloatValue()); else if (eCSSUnit_Percent == unit) - mLineThickness = nscoord(float(defaultThickness) * cssValue.GetPercentValue()); + lineThickness = nscoord(float(defaultThickness) * cssValue.GetPercentValue()); else if (eCSSUnit_Null != unit) - mLineThickness = CalcLength(aPresContext, mStyleContext, cssValue); + lineThickness = CalcLength(aPresContext, aStyleContext, cssValue); } -#ifdef NS_DEBUG +#if 0 else { char str[50]; - value.ToCString(str, 50); + aThicknessAttribute.ToCString(str, 50); printf("Invalid attribute linethickness=%s\n", str); } #endif } } - mLineOrigin.x = 0; - mLineOrigin.y = 0; + // use minimum if the lineThickness is a non-zero value less than minimun + if (0 != lineThickness && lineThickness < minimumThickness) + lineThickness = minimumThickness; - return rv; + return lineThickness; } NS_IMETHODIMP @@ -134,21 +166,11 @@ nsMathMLmfracFrame::Paint(nsIPresContext* aPresContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer) { - nsresult rv = NS_OK; - - ///////////// - // paint the numerator and denominator - rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, - aDirtyRect, aWhichLayer); - - if (NS_FRAME_PAINT_LAYER_FOREGROUND != aWhichLayer) { - return rv; - } - //////////// // paint the fraction line - if (NS_SUCCEEDED(rv) && 0 < mLineThickness) { - + if ((NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) && + !NS_MATHML_HAS_ERROR(mPresentationData.flags) && + !mLineRect.IsEmpty()) { /* // line looking like
const nsStyleColor* color; @@ -158,115 +180,250 @@ nsMathMLmfracFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.SetColor(colors[0]); */ // solid line with the current text color - const nsStyleColor* color = - (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); - aRenderingContext.SetColor(color->mColor); + nsStyleColor color; + mStyleContext->GetStyle(eStyleStruct_Color, color); + aRenderingContext.SetColor(color.mColor); -// draw the line - aRenderingContext.FillRect(mLineOrigin.x, mLineOrigin.y, mRect.width, mLineThickness); +// draw the line, there is 1 pixel padding at either end + aRenderingContext.FillRect(mLineRect.x, mLineRect.y, + mLineRect.width, mLineRect.height); } - return rv; + ///////////// + // paint the numerator and denominator + return nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); +} + +// over-ride the default method to update presentation parameters +// Rule 15a, App. G, TeXbook +NS_IMETHODIMP +nsMathMLmfracFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, + PRInt32 aScriptLevelIncrement, + PRBool aDisplayStyle, + PRBool aCompressed) +{ + PRBool displayStyle = NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags); + PRBool compressed = NS_MATHML_IS_COMPRESSED(mPresentationData.flags); + + nsIFrame* childFrame = mFrames.FirstChild(); + while (nsnull != childFrame) { + if (!IsOnlyWhitespace(childFrame)) { + nsIMathMLFrame* aMathMLFrame = nsnull; + nsresult rv = childFrame->QueryInterface + (NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); + if (NS_SUCCEEDED(rv) && nsnull != aMathMLFrame) { + if (0 == aIndex++) { + // update numerator + if (displayStyle) { + // switch to text with current compression + aMathMLFrame->UpdatePresentationData(0, PR_FALSE, compressed); + } + else { + // apply the default rule + aMathMLFrame->UpdatePresentationData + (aScriptLevelIncrement, aDisplayStyle, aCompressed); + } + } + else { + // update denominator + if (displayStyle) { + // switch to text with compression + aMathMLFrame->UpdatePresentationData(0, PR_FALSE, PR_TRUE); + } + else { + // apply the default rule + aMathMLFrame->UpdatePresentationData + (aScriptLevelIncrement, aDisplayStyle, aCompressed); + } + } + + // propagate down the subtrees + aMathMLFrame->UpdatePresentationDataFromChildAt + (0, aScriptLevelIncrement, aDisplayStyle, aCompressed); + } + } + childFrame->GetNextSibling(&childFrame); + } + + return NS_OK; } NS_IMETHODIMP -nsMathMLmfracFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) +nsMathMLmfracFrame::Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize) { nsresult rv = NS_OK; - nsReflowStatus childStatus; - // 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); - ////////////////// - // Reflow Children + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsBoundingMetrics bmNum, bmDen; + nsHTMLReflowMetrics sizeNum (nsnull); + nsHTMLReflowMetrics sizeDen (nsnull); + nsIFrame* frameNum = nsnull; + nsIFrame* frameDen = nsnull; - nscoord count = 0; - nsRect rect[2]; - nsIFrame* child[2]; nsIFrame* childFrame = mFrames.FirstChild(); - while (nsnull != childFrame) - { - ////////////// - // WHITESPACE: don't forget that whitespace doesn't count in MathML! - if (IsOnlyWhitespace(childFrame)) { - ReflowEmptyChild(aPresContext, childFrame); - } - else if (2 > count) { - - nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); - rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); - if (NS_FAILED(rv)) { - return rv; + while (nsnull != childFrame) { + if (!IsOnlyWhitespace(childFrame)) { + if (0 == count) { + // numerator + frameNum = childFrame; + GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum); + } + else if (1 == count) { + // denominator + frameDen = childFrame; + GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen); } - - child[count] = childFrame; - rect[count].width = childDesiredSize.width; - rect[count].height = childDesiredSize.height; count++; } -// else { invalid markup... } - rv = childFrame->GetNextSibling(&childFrame); - NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } +#ifdef NS_DEBUG + if (2 != count) printf("mfrac: invalid markup"); +#endif + if ((2 != count) || !frameNum || !frameDen) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } + + ////////////////// + // Get shifts + + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + aRenderingContext.SetFont(font.mFont); + nsCOMPtr fm; + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); + + nscoord defaultRuleThickness; + GetRuleThickness(aRenderingContext, fm, defaultRuleThickness); + + // see if the linethickness attribute is there + nsAutoString value; + GetAttribute(mContent, mPresentationData.mstyle, nsMathMLAtoms::linethickness_, value); + mLineRect.height = CalcLineThickness(aPresContext, mStyleContext, + value, onePixel, defaultRuleThickness); + nscoord numShift = 0; + nscoord denShift = 0; + + // Rule 15b, App. G, TeXbook + nscoord numShift1, numShift2, numShift3; + nscoord denShift1, denShift2; + + GetNumeratorShifts(fm, numShift1, numShift2, numShift3); + GetDenominatorShifts(fm, denShift1, denShift2); + if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) { + // C > T + numShift = numShift1; + denShift = denShift1; + } + else { + numShift = (0 < mLineRect.height) ? numShift2 : numShift3; + denShift = denShift2; + } + + nscoord minClearance = 0; + nscoord actualClearance = 0; + nscoord axisHeight = 0; + + nscoord actualRuleThickness = (0 < mLineRect.height) ? mLineRect.height : 0; + + if (0 == actualRuleThickness) { + // Rule 15c, App. G, TeXbook + + // min clearance between numerator and denominator + minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? + 7 * defaultRuleThickness : 3 * defaultRuleThickness; + actualClearance = + (numShift - bmNum.descent) - (bmDen.ascent - denShift); + // actualClearance should be >= minClearance + if (actualClearance < minClearance) { + nscoord halfGap = (minClearance - actualClearance)/2; + numShift += halfGap; + denShift += halfGap; + } + } + else { + // Rule 15d, App. G, TeXbook + GetAxisHeight (fm, axisHeight); + + // min clearance between numerator or denominator and middle of bar + + // TeX has a different interpretation of the thickeness. + // Try $a \above10pt b$ to see. Here is what TeX does: + // minClearance = (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? + // 3 * actualRuleThickness : actualRuleThickness; + + // we don't follow TeX here, we use a modified version of Rule 15c in which + // one defaultRuleThickness is replaced by one actualRuleThickness + minClearance = actualRuleThickness + + (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) ? + 6 * defaultRuleThickness : 2 * defaultRuleThickness; + + // adjust numShift to maintain minClearance if needed + actualClearance = + (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2); + if (actualClearance < minClearance) { + numShift += (minClearance - actualClearance); + } + // adjust denShift to maintain minClearance if needed + actualClearance = + (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift); + if (actualClearance < minClearance) { + denShift += (minClearance - actualClearance); + } } ////////////////// // Place Children - // Get the line and center the fraction bar with the line. - nscoord strikeOffset, strikeThickness; - nsCOMPtr fm; - const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetStrikeout(strikeOffset, strikeThickness); + // there is 1 pixel padding at either end of the fraction + nscoord width = 2*onePixel + PR_MAX(bmNum.width, bmDen.width); + nscoord dxNum = (width - sizeNum.width)/2; + nscoord dxDen = (width - sizeDen.width)/2; - // Take care of mLineThickness - float p2t; - nscoord halfThickspace; - aPresContext->GetScaledPixelsToTwips(&p2t); - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + mBoundingMetrics.rightBearing = + PR_MAX(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing); + if (mBoundingMetrics.rightBearing < width - onePixel) + mBoundingMetrics.rightBearing = width - onePixel; + mBoundingMetrics.leftBearing = + PR_MIN(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing); + if (mBoundingMetrics.leftBearing > onePixel) + mBoundingMetrics.leftBearing = onePixel; + mBoundingMetrics.ascent = bmNum.ascent + numShift; + mBoundingMetrics.descent = bmDen.descent + denShift; + mBoundingMetrics.width = width; - // distance from the middle of the axis - halfThickspace = (mLineThickness > onePixel)? mLineThickness/2 : 0; - - aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); - aDesiredSize.ascent = rect[0].height + strikeOffset + halfThickspace; - aDesiredSize.descent = rect[1].height - strikeOffset + halfThickspace; + aDesiredSize.ascent = sizeNum.ascent + numShift; + aDesiredSize.descent = sizeDen.descent + denShift; aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; - rect[0].x = (aDesiredSize.width - rect[0].width) / 2; // center w.r.t largest width - rect[1].x = (aDesiredSize.width - rect[1].width) / 2; - rect[0].y = 0; - rect[1].y = aDesiredSize.height - rect[1].height; + mReference.x = 0; + mReference.y = aDesiredSize.ascent; - // 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; - } - 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/layout/mathml/base/src/nsMathMLmfracFrame.h b/layout/mathml/base/src/nsMathMLmfracFrame.h index daaeb746579d..96fff151bc62 100644 --- a/layout/mathml/base/src/nsMathMLmfracFrame.h +++ b/layout/mathml/base/src/nsMathMLmfracFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmfracFrame_h___ @@ -66,14 +67,6 @@ environment, but can be set explicitly only on the element. */ - -// default fraction line thickness in pixels -#define DEFAULT_FRACTION_LINE_THICKNESS 1 - -#define THIN_FRACTION_LINE_THICKNESS 1 -#define MEDIUM_FRACTION_LINE_THICKNESS 2 -#define THICK_FRACTION_LINE_THICKNESS 4 - class nsMathMLmfracFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); @@ -85,11 +78,18 @@ public: nsIStyleContext* aContext, nsIFrame* aPrevInFlow); + NS_IMETHOD + Place(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + PRBool aPlaceOrigin, + nsHTMLReflowMetrics& aDesiredSize); +#if 0 NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); +#endif NS_IMETHOD Paint(nsIPresContext* aPresContext, @@ -97,6 +97,12 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); + NS_IMETHOD + UpdatePresentationDataFromChildAt(PRInt32 aIndex, + PRInt32 aScriptLevelIncrement, + PRBool aDisplayStyle, + PRBool aCompressed); + NS_IMETHOD SetInitialChildList(nsIPresContext* aPresContext, nsIAtom* aListName, @@ -104,20 +110,18 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(0, 1, PR_FALSE); + UpdatePresentationDataFromChildAt(0, 1, PR_FALSE, PR_TRUE); InsertScriptLevelStyleContext(aPresContext); return rv; } - void - SetLineThickness(const nscoord aLineThickness) { - mLineThickness = aLineThickness; - } - - void - SetLineOrigin(const nsPoint& aOrigin) { - mLineOrigin = aOrigin; - } + // helper to translate the thickness attribute into a usable form + static nscoord + CalcLineThickness(nsIPresContext* aPresContext, + nsIStyleContext* aStyleContext, + nsString& aThicknessAttribute, + nscoord onePixel, + nscoord aDefaultRuleThickness); protected: nsMathMLmfracFrame(); @@ -125,8 +129,7 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } - nsPoint mLineOrigin; - nscoord mLineThickness; + nsRect mLineRect; }; #endif /* nsMathMLmfracFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmiFrame.cpp b/layout/mathml/base/src/nsMathMLmiFrame.cpp index e17281f5b11f..82b66d378567 100644 --- a/layout/mathml/base/src/nsMathMLmiFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmiFrame.cpp @@ -131,13 +131,13 @@ nsMathMLmiFrame::SetInitialChildList(nsIPresContext* aPresContext, if (NS_CONTENT_ATTR_HAS_VALUE == mstyleContent->GetAttribute(kNameSpaceID_None, nsMathMLAtoms::fontstyle_, fontStyle)) { - if (fontStyle == "italic") + if (fontStyle.Equals("italic")) return rv; } } // Get a pseudo style context for the appropriate style font - fontStyle = ":-moz-math-font-style-normal"; + fontStyle.Assign(":-moz-math-font-style-normal"); nsCOMPtr fontAtom(getter_AddRefs(NS_NewAtom(fontStyle))); nsCOMPtr newStyleContext; aPresContext->ResolvePseudoStyleContextFor(mContent, fontAtom, mStyleContext, diff --git a/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp b/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp index da6b55fc83c7..3231ee89de6d 100644 --- a/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.cpp @@ -124,16 +124,26 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, //////////////////////////////////////// // get x-height (an ex) +#if 0 nscoord xHeight = 0; nsCOMPtr fm; const nsStyleFont* aFont = (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); fm->GetXHeight (xHeight); +#endif - nscoord aRuleSize = 0; - // XXX need to do update this ... - GetRuleThickness (fm, aRuleSize); + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + aRenderingContext.SetFont(font.mFont); + nsCOMPtr fm; + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); + + nscoord xHeight; + fm->GetXHeight (xHeight); + + nscoord aRuleSize; + GetRuleThickness (aRenderingContext, fm, aRuleSize); ///////////////////////////////////// // first the shift for the subscript @@ -212,9 +222,9 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, nsHTMLReflowMetrics baseSize (nsnull); nsHTMLReflowMetrics subScriptSize (nsnull); nsHTMLReflowMetrics supScriptSize (nsnull); - nsIFrame* baseFrame; - nsIFrame* subScriptFrame; - nsIFrame* supScriptFrame; + nsIFrame* baseFrame = nsnull; + nsIFrame* subScriptFrame = nsnull; + nsIFrame* supScriptFrame = nsnull; PRBool firstPrescriptsPair = PR_FALSE; nsBoundingMetrics bmBase, bmSubScript, bmSupScript; @@ -311,7 +321,10 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, rightBearing = PR_MAX(rightBearing, bmSupScript.rightBearing + mScriptSpace); } - NS_ASSERTION((isSubScriptPresent || isSupScriptPresent),"mmultiscripts : both sup/subscripts are absent"); + if (!isSubScriptPresent && !isSupScriptPresent) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } if (!mprescriptsFrame) { // we are still looping over base & postscripts mBoundingMetrics.rightBearing = mBoundingMetrics.width + rightBearing; @@ -366,6 +379,11 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } + // note: width=0 if all sup-sub pairs match correctly + if ((0 != width) || !baseFrame || !subScriptFrame || !supScriptFrame) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } // we left out the width of prescripts, so ... mBoundingMetrics.rightBearing += prescriptsWidth; @@ -386,7 +404,7 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, aDesiredSize.width = mBoundingMetrics.width; mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; ////////////////// // Place Children @@ -405,7 +423,6 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, if (nsnull == aChildFrame) { // end of prescripts, // place the base ... aChildFrame = baseFrame; -// dy = mBoundingMetrics.ascent - bmBase.ascent; dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, aPresContext, baseSize, dx, dy, 0); dx += baseSize.width + bmBase.supItalicCorrection; @@ -433,14 +450,7 @@ nsMathMLmmultiscriptsFrame::Place(nsIPresContext* aPresContext, supScriptSize.width = aRect.width; supScriptSize.height = aRect.height; - // XXX should we really center the boxes - // XXX i'm leaving it as left-justified - // XXX which is consistent with what's done for - - // reverting to center. It looks much nicer and adds a bit - // of variety to the engine. At least we have two functions - // doing two different things. - + // center w.r.t. largest width width = PR_MAX(subScriptSize.width, supScriptSize.width); dy = aDesiredSize.ascent - diff --git a/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h b/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h index 006965ab8f1e..ed10039dacf4 100644 --- a/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h +++ b/layout/mathml/base/src/nsMathMLmmultiscriptsFrame.h @@ -55,7 +55,7 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(1, 1, PR_FALSE); + UpdatePresentationDataFromChildAt(1, 1, PR_FALSE, PR_FALSE); // switch the style of the postscripts and prescripts InsertScriptLevelStyleContext(aPresContext); // check whether or not this is an embellished operator diff --git a/layout/mathml/base/src/nsMathMLmnFrame.cpp b/layout/mathml/base/src/nsMathMLmnFrame.cpp deleted file mode 100644 index c2429d2e644b..000000000000 --- a/layout/mathml/base/src/nsMathMLmnFrame.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is Mozilla MathML Project. - * - * The Initial Developer of the The Original Code is The University Of - * Queensland. Portions created by The University Of Queensland are - * Copyright (C) 1999 The University Of Queensland. All Rights Reserved. - * - * Contributor(s): - * Roger B. Sidje - * Shyjan Mahamud - */ - -#include "nsCOMPtr.h" -#include "nsHTMLParts.h" -#include "nsIHTMLContent.h" -#include "nsFrame.h" -#include "nsLineLayout.h" -#include "nsHTMLIIDs.h" -#include "nsIPresContext.h" -#include "nsHTMLAtoms.h" -#include "nsUnitConversion.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsStyleChangeList.h" -#include "nsINameSpaceManager.h" -#include "nsIRenderingContext.h" -#include "nsIFontMetrics.h" -#include "nsStyleUtil.h" - -#include "nsMathMLmnFrame.h" - -// -// -- number - implementation -// - -nsresult -NS_NewMathMLmnFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsMathMLmnFrame* it = new (aPresShell) nsMathMLmnFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsMathMLmnFrame::nsMathMLmnFrame() -{ -} - -nsMathMLmnFrame::~nsMathMLmnFrame() -{ -} - -NS_IMETHODIMP -nsMathMLmnFrame::Init(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsIStyleContext* aContext, - nsIFrame* aPrevInFlow) -{ - nsresult rv = NS_OK; - rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - return rv; -} - -NS_IMETHODIMP -nsMathMLmnFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - return ReflowTokenFor(this, aPresContext, aDesiredSize, - aReflowState, aStatus); -} - -NS_IMETHODIMP -nsMathMLmnFrame::Place(nsIPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - PRBool aPlaceOrigin, - nsHTMLReflowMetrics& aDesiredSize) -{ - return PlaceTokenFor(this, aPresContext, aRenderingContext, - aPlaceOrigin, aDesiredSize); -} diff --git a/layout/mathml/base/src/nsMathMLmoFrame.cpp b/layout/mathml/base/src/nsMathMLmoFrame.cpp index e668575e796e..4db9e697821b 100644 --- a/layout/mathml/base/src/nsMathMLmoFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmoFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud * Pierre Phaneuf */ @@ -84,6 +85,10 @@ // the baseline) are identifiers displayed in a non-slanted font (i.e., under // the suggested rules, when both operands are multi-character identifiers). + +// additional style context to be used by our MathMLChar. +#define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX 0 + nsresult NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { @@ -115,19 +120,20 @@ nsMathMLmoFrame::Paint(nsIPresContext* aPresContext, { nsresult rv = NS_OK; - if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer && - NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { - rv = mMathMLChar.Paint(aPresContext, - aRenderingContext, - mStyleContext); + if (NS_MATHML_OPERATOR_GET_FORM(mFlags)) { + rv = mMathMLChar.Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) // for visual debug if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer && NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags)) { - aRenderingContext.SetColor(NS_RGB(0,0,255)); + aRenderingContext.SetColor(NS_RGB(0,255,255)); nscoord x = mReference.x + mBoundingMetrics.leftBearing; - nscoord y = mReference.y; + nscoord y = mReference.y - mBoundingMetrics.ascent; +//nsRect rect; +//mMathMLChar.GetRect(rect); +//y = rect.y; nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing; nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent; aRenderingContext.DrawRect(x,y,w,h); @@ -135,10 +141,8 @@ nsMathMLmoFrame::Paint(nsIPresContext* aPresContext, #endif } else { // let the base class worry about the painting - rv = nsMathMLContainerFrame::Paint(aPresContext, - aRenderingContext, - aDirtyRect, - aWhichLayer); + rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); } return rv; } @@ -160,20 +164,6 @@ nsMathMLmoFrame::Init(nsIPresContext* aPresContext, mMinSize = float(NS_UNCONSTRAINEDSIZE); mMaxSize = float(NS_UNCONSTRAINEDSIZE); -#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) - mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; -#endif - return rv; -} - -NS_IMETHODIMP -nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList) -{ - nsresult rv; - rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - // get the text that we enclose. // XXX aData.CompressWhitespace() ? nsAutoString aData; // PRInt32 aLength = 0; @@ -197,7 +187,22 @@ nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, } } // cache the operator - mMathMLChar.SetData(aData); + mMathMLChar.SetData(aPresContext, aData); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mMathMLChar); + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif + return rv; +} + +NS_IMETHODIMP +nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + nsresult rv; + rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); // fill our mEmbellishData member variable nsIFrame* firstChild = mFrames.FirstChild(); @@ -216,7 +221,7 @@ nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, // 2) do we have movablelimits="true" // they need the extra information to decide how to treat their scripts/limits - // (note: , , or need not necessarily be our + // (note: , , or need not necessarily be our // direct parent -- case of embellished operators) mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; // default is false @@ -227,53 +232,56 @@ nsMathMLmoFrame::SetInitialChildList(nsIPresContext* aPresContext, PRBool movablelimitsAttribute = PR_FALSE; // see if the accent attribute is there - if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, + if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, nsMathMLAtoms::accent_, value)) { accentAttribute = PR_TRUE; - if (value == "true") + if (value.Equals("true")) { mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; } } // see if the movablelimits attribute is there - if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, + if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, nsMathMLAtoms::movablelimits_, value)) { movablelimitsAttribute = PR_TRUE; - if (value == "true") + if (value.Equals("true")) { mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS; } } if (!accentAttribute || !movablelimitsAttribute) { - // If we reach here, it means one or both attributes are missing + // If we reach here, it means one or both attributes are missing. // Unfortunately, we have to lookup the dictionary to see who // we are, i.e., two lookups, counting also the one in Stretch()! // The lookup in Stretch() assumes that the surrounding frame tree // is already fully constructed, which is not true at this stage. // all accent="true" in the dictionary have form="postfix" - nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_POSTFIX; + // XXX should we check if the form attribute is there? + nsAutoString aData; + mMathMLChar.GetData(aData); + nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_POSTFIX; nsOperatorFlags aFlags = 0; float aLeftSpace, aRightSpace; PRBool found = nsMathMLOperators::LookupOperator(aData, aForm, &aFlags, &aLeftSpace, &aRightSpace); - + if (found && !accentAttribute && NS_MATHML_OPERATOR_IS_ACCENT(aFlags)) { mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; } - // all movablemits="true" in the dictionary have form="prefix", + // all movablemits="true" in the dictionary have form="prefix", // but this doesn't matter here, as the lookup has returned whatever // is in the dictionary if (found && !movablelimitsAttribute && NS_MATHML_OPERATOR_IS_MOVABLELIMITS(aFlags)) { mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS; - } + } } break; } @@ -317,7 +325,7 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) aParent->GetParent(&aParent); } while (IsEmbellishOperator(aParent)); // flag if we have an embellished ancestor - if (embellishAncestor != this) + if (embellishAncestor != this) { hasEmbellishAncestor = PR_TRUE; } @@ -376,13 +384,13 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) 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 operators are treated as non-symmetric... - // Uncomment the folllowing line to change this behavior. - //mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; + // All operators are symmetric. But this symmetric flag is *not* stored in + // the Operator Dictionary ... Add it now + mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; // If the operator exists in the dictionary and is stretchy, it is mutable - if (found && NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) { + if (found && NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) + { mFlags |= NS_MATHML_OPERATOR_MUTABLE; } @@ -437,12 +445,12 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) } if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, - nsMathMLAtoms::symmetric_, value)) { - if (value == ktrue) mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; + nsMathMLAtoms::symmetric_, value)) { if (value == kfalse) mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC; + else if (value == ktrue) mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; } - // If we are an accent without explicit lspace="." or rspace=".", + // If we are an accent without explicit lspace="." or rspace=".", // ignore our default left/right space // Get the value of 'em' @@ -454,8 +462,13 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, nsMathMLAtoms::lspace_, value)) { nsCSSValue cssValue; - if (ParseNumericValue(value, cssValue) && cssValue.IsLengthUnit()) { - mLeftSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em; + if (ParseNumericValue(value, cssValue)) + { + if ((eCSSUnit_Number == cssValue.GetUnit()) && + (0.0f == cssValue.GetFloatValue())) + mLeftSpace = 0.0f; + else if (cssValue.IsLengthUnit()) + mLeftSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em; } } else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { @@ -466,8 +479,13 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle, nsMathMLAtoms::rspace_, value)) { nsCSSValue cssValue; - if (ParseNumericValue(value, cssValue) && cssValue.IsLengthUnit()) { - mRightSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em; + if (ParseNumericValue(value, cssValue)) + { + if ((eCSSUnit_Number == cssValue.GetUnit()) && + (0.0f == cssValue.GetFloatValue())) + mRightSpace = 0.0f; + else if (cssValue.IsLengthUnit()) + mRightSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em; } } else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) { @@ -508,8 +526,12 @@ nsMathMLmoFrame::InitData(nsIPresContext* aPresContext) } } - // If the stretchy attribute has been disabled, the operator is not mutable - if (!found || !NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) { + // If the stretchy or largeop attributes have been disabled, + // the operator is not mutable + if (!found || + (!NS_MATHML_OPERATOR_IS_STRETCHY(mFlags) && + !NS_MATHML_OPERATOR_IS_LARGEOP(mFlags))) + { mFlags &= ~NS_MATHML_OPERATOR_MUTABLE; } } @@ -521,8 +543,8 @@ NS_IMETHODIMP nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize) + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredStretchSize) { if (NS_MATHML_STRETCH_WAS_DONE(mEmbellishData.flags)) { printf("WARNING *** it is wrong to fire stretch more than once on a frame...\n"); @@ -530,141 +552,167 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, } mEmbellishData.flags |= NS_MATHML_STRETCH_DONE; -// if (0 == mFlags) { // first time... - InitData(aPresContext); -// } + InitData(aPresContext); + // get the axis height; + nsStyleFont font; + mStyleContext->GetStyle(eStyleStruct_Font, font); + nsCOMPtr fm; + aPresContext->GetMetricsFor(font.mFont, getter_AddRefs(fm)); + nscoord fontAscent, fontDescent, axisHeight; + GetAxisHeight(fm, axisHeight); + fm->GetMaxAscent(fontAscent); + fm->GetMaxDescent(fontDescent); - ///////// - // See if it is okay to stretch + // Operators that exist in the dictionary are handled by the MathMLChar - if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { + if (!NS_MATHML_OPERATOR_GET_FORM(mFlags)) { + // Place our children + Place(aPresContext, aRenderingContext, PR_TRUE, aDesiredStretchSize); + } + else { + // The rendering will be handled by our MathML char - nsStretchMetrics initialSize(aDesiredStretchSize); - nsStretchMetrics container(aContainerSize); + nsBoundingMetrics charSize; + nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics; + nsBoundingMetrics container = initialSize; - // little adjustments if the operator is symmetric + // see if it is okay to stretch + if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { - if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) && - ((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) || - (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT && - mMathMLChar.GetStretchDirection() == NS_STRETCH_DIRECTION_VERTICAL))) - { - container.ascent = PR_MAX(container.ascent, container.descent); - container.descent = container.ascent; - container.height = container.ascent + container.descent; + container = aContainerSize; - // get ready in case we encounter user-desired min-max - initialSize.ascent = PR_MAX(initialSize.ascent, initialSize.descent); - initialSize.descent = initialSize.ascent; - initialSize.height = initialSize.ascent + initialSize.descent; - } + // some adjustments if the operator is symmetric and vertical - // check for user-desired min-max size + if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) && + ((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) || + (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT && + mMathMLChar.GetStretchDirection() == NS_STRETCH_DIRECTION_VERTICAL))) + { + // we need to center about the axis + nscoord delta = PR_MAX(container.ascent - axisHeight, + container.descent + axisHeight); + container.ascent = delta + axisHeight; + container.descent = delta - axisHeight; - if (mMaxSize != float(NS_UNCONSTRAINEDSIZE) && mMaxSize > 0.0f) { - // if we are here, there is a user defined maxsize ... - if (NS_MATHML_OPERATOR_MAXSIZE_IS_EXPLICIT(mFlags)) { - // there is an explicit value like maxsize="20pt" - // try to maintain the aspect ratio of the char - float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent); - container.ascent = - PR_MIN(container.ascent, nscoord(initialSize.ascent * aspect)); - container.descent = - PR_MIN(container.descent, nscoord(initialSize.descent * aspect)); - // below we use a type cast instead of a conversion to avoid a VC++ bug - // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP - container.width = - PR_MIN(container.width, (nscoord)mMaxSize); + // get ready in case we encounter user-desired min-max size + delta = PR_MAX(initialSize.ascent - axisHeight, + initialSize.descent + axisHeight); + initialSize.ascent = delta + axisHeight; + initialSize.descent = delta - axisHeight; } - else { // multiplicative value - container.ascent = - PR_MIN(container.ascent, nscoord(initialSize.ascent * mMaxSize)); - container.descent = - PR_MIN(container.descent, nscoord(initialSize.descent * mMaxSize)); - container.width = - PR_MIN(container.width, nscoord(initialSize.width * mMaxSize)); + + // check for user-desired min-max size + + if (mMaxSize != float(NS_UNCONSTRAINEDSIZE) && mMaxSize > 0.0f) { + // if we are here, there is a user defined maxsize ... + if (NS_MATHML_OPERATOR_MAXSIZE_IS_EXPLICIT(mFlags)) { + // there is an explicit value like maxsize="20pt" + // try to maintain the aspect ratio of the char + float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent); + container.ascent = + PR_MIN(container.ascent, nscoord(initialSize.ascent * aspect)); + container.descent = + PR_MIN(container.descent, nscoord(initialSize.descent * aspect)); + // below we use a type cast instead of a conversion to avoid a VC++ bug + // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP + container.width = + PR_MIN(container.width, (nscoord)mMaxSize); + } + else { // multiplicative value + container.ascent = + PR_MIN(container.ascent, nscoord(initialSize.ascent * mMaxSize)); + container.descent = + PR_MIN(container.descent, nscoord(initialSize.descent * mMaxSize)); + container.width = + PR_MIN(container.width, nscoord(initialSize.width * mMaxSize)); + } + } + + if (mMinSize != float(NS_UNCONSTRAINEDSIZE) && mMinSize > 0.0f) { + // if we are here, there is a user defined minsize ... + if (NS_MATHML_OPERATOR_MINSIZE_IS_EXPLICIT(mFlags)) { + // there is an explicit value like minsize="20pt" + // try to maintain the aspect ratio of the char + float aspect = mMinSize / float(initialSize.ascent + initialSize.descent); + container.ascent = + PR_MAX(container.ascent, nscoord(initialSize.ascent * aspect)); + container.descent = + PR_MAX(container.descent, nscoord(initialSize.descent * aspect)); + container.width = + PR_MAX(container.width, (nscoord)mMinSize); + } + else { // multiplicative value + container.ascent = + PR_MAX(container.ascent, nscoord(initialSize.ascent * mMinSize)); + container.descent = + PR_MAX(container.descent, nscoord(initialSize.descent * mMinSize)); + container.width = + PR_MAX(container.width, nscoord(initialSize.width * mMinSize)); + } } } - if (mMinSize != float(NS_UNCONSTRAINEDSIZE) && mMinSize > 0.0f) { - // if we are here, there is a user defined minsize ... - if (NS_MATHML_OPERATOR_MINSIZE_IS_EXPLICIT(mFlags)) { - // there is an explicit value like minsize="20pt" - // try to maintain the aspect ratio of the char - float aspect = mMinSize / float(initialSize.ascent + initialSize.descent); - container.ascent = - PR_MAX(container.ascent, nscoord(initialSize.ascent * aspect)); - container.descent = - PR_MAX(container.descent, nscoord(initialSize.descent * aspect)); - container.width = - PR_MAX(container.width, (nscoord)mMinSize); - } - else { // multiplicative value - container.ascent = - PR_MAX(container.ascent, nscoord(initialSize.ascent * mMinSize)); - container.descent = - PR_MAX(container.descent, nscoord(initialSize.descent * mMinSize)); - container.width = - PR_MAX(container.width, nscoord(initialSize.width * mMinSize)); - } - } - - // things may have changed - container.height = container.ascent + container.descent; - // let the MathMLChar stretch itself... + charSize.Clear(); // this will tell stretch that we don't know the default size mMathMLChar.Stretch(aPresContext, aRenderingContext, - mStyleContext, aStretchDirection, - container, aDesiredStretchSize); - if (initialSize == aDesiredStretchSize) { // hasn't changed ! - mFlags &= ~NS_MATHML_OPERATOR_MUTABLE; - } - } - - ///////// - // Place our children and adjust our children's offsets to leave the spacing. - - if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { - // The rendering will be handled by our MathML char - mMathMLChar.SetRect(nsRect(0, 0, aDesiredStretchSize.width, - aDesiredStretchSize.height)); - // update our bounding metrics... it becomes that of our MathML char + aStretchDirection, container, charSize); + // update our bounding metrics... it becomes that of our MathML char mMathMLChar.GetBoundingMetrics(mBoundingMetrics); - } - else { - nsHTMLReflowMetrics aReflowMetrics(nsnull); - Place(aPresContext, aRenderingContext, PR_TRUE, aReflowMetrics); - // Prepare the metrics to be returned - aDesiredStretchSize.width = aReflowMetrics.width; - aDesiredStretchSize.height = aReflowMetrics.height; - aDesiredStretchSize.ascent = aReflowMetrics.ascent; - aDesiredStretchSize.descent = aReflowMetrics.descent; + // For vertical operators we want to center about the axis of the container. + if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) && + ((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) || + (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT && + mMathMLChar.GetStretchDirection() == NS_STRETCH_DIRECTION_VERTICAL))) + { + // the desired size returned by mMathMLChar maybe different + // from the size of the container. + // the mMathMLChar.mRect.y calculation is subtle, watch out!!! + nscoord height = mBoundingMetrics.ascent + mBoundingMetrics.descent; + mBoundingMetrics.ascent = height/2 + axisHeight; + mBoundingMetrics.descent = height - mBoundingMetrics.ascent; + } + + // Prepare the metrics to return + aDesiredStretchSize.ascent = PR_MAX(fontAscent, mBoundingMetrics.ascent); /* + delta1*/ + aDesiredStretchSize.descent = PR_MAX(fontDescent, mBoundingMetrics.descent); /* + delta2*/ + aDesiredStretchSize.width = mBoundingMetrics.width; + aDesiredStretchSize.height = aDesiredStretchSize.ascent + aDesiredStretchSize.descent; + aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; + + nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent; + if (mMathMLChar.GetEnum() == eMathMLChar_DONT_STRETCH) + { + dy = (aDesiredStretchSize.ascent - charSize.ascent); + aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics = charSize; + } + + mMathMLChar.SetRect( + nsRect(0, dy, charSize.width, + charSize.ascent + charSize.descent)); + + mReference.x = 0; + mReference.y = aDesiredStretchSize.ascent; } - aDesiredStretchSize.leftSpace = mLeftSpace; - aDesiredStretchSize.rightSpace = mRightSpace; - - mReference.x = 0; - mReference.y = aDesiredStretchSize.ascent - mBoundingMetrics.ascent; // Before we leave... there is a last item in the check-list: // If our parent is not embellished, it means we are the outermost embellished // container and so we put the spacing, otherwise we don't include the spacing, // the outermost embellished container will take care of it. - + if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) { - + // Get the value of 'em' nsStyleFont font; mStyleContext->GetStyle(eStyleStruct_Font, font); nscoord em = NSToCoordRound(float(font.mFont.size)); // Account the spacing - aDesiredStretchSize.width += nscoord( (aDesiredStretchSize.leftSpace + aDesiredStretchSize.rightSpace) * em ); + aDesiredStretchSize.width += nscoord((mLeftSpace + mRightSpace) * em); mBoundingMetrics.width = aDesiredStretchSize.width; + nscoord dx = nscoord(mLeftSpace * em); - nscoord dx = nscoord( mLeftSpace * em ); if (0 == dx) return NS_OK; // adjust the offsets @@ -672,7 +720,7 @@ nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext, mBoundingMetrics.rightBearing += dx; nsRect rect; - if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) { + if (NS_MATHML_OPERATOR_GET_FORM(mFlags)) { mMathMLChar.GetRect(rect); mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y, rect.width, rect.height)); } @@ -707,3 +755,39 @@ nsMathMLmoFrame::Place(nsIPresContext* aPresContext, return PlaceTokenFor(this, aPresContext, aRenderingContext, aPlaceOrigin, aDesiredSize); } + +// ---------------------- +// the Style System will use these to pass the proper style context to our MathMLChar +NS_IMETHODIMP +nsMathMLmoFrame::GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const +{ + NS_PRECONDITION(aStyleContext, "null OUT ptr"); + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + *aStyleContext = nsnull; + switch (aIndex) { + case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX: + mMathMLChar.GetStyleContext(aStyleContext); + break; + default: + return NS_ERROR_INVALID_ARG; + } + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmoFrame::SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext) +{ + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + switch (aIndex) { + case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX: + mMathMLChar.SetStyleContext(aStyleContext); + break; + } + return NS_OK; +} diff --git a/layout/mathml/base/src/nsMathMLmoFrame.h b/layout/mathml/base/src/nsMathMLmoFrame.h index 703317fc9d1b..d2ab0db62914 100644 --- a/layout/mathml/base/src/nsMathMLmoFrame.h +++ b/layout/mathml/base/src/nsMathMLmoFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmoFrame_h___ @@ -33,7 +34,14 @@ class nsMathMLmoFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); - + + NS_IMETHOD + SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext); + NS_IMETHOD + GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const; + NS_IMETHOD Init(nsIPresContext* aPresContext, nsIContent* aContent, @@ -70,8 +78,8 @@ public: Stretch(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, - nsStretchMetrics& aContainerSize, - nsStretchMetrics& aDesiredStretchSize); + nsBoundingMetrics& aContainerSize, + nsHTMLReflowMetrics& aDesiredStretchSize); // helper method to lookup the operator dictionary and initialize our member data void @@ -83,12 +91,13 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } - nsMathMLChar mMathMLChar; // Here is the MathMLChar that will deal with the operator. - nsOperatorFlags mFlags; - float mLeftSpace; - float mRightSpace; - float mMinSize; - float mMaxSize; + nsMathMLChar mMathMLChar; // Here is the MathMLChar that will deal with the operator. + + nsOperatorFlags mFlags; + float mLeftSpace; + float mRightSpace; + float mMinSize; + float mMaxSize; }; #endif /* nsMathMLmoFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmoverFrame.cpp b/layout/mathml/base/src/nsMathMLmoverFrame.cpp index 2cfe0fd905f8..224c20c2fd02 100644 --- a/layout/mathml/base/src/nsMathMLmoverFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmoverFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud * Pierre Phaneuf */ @@ -76,8 +77,11 @@ nsMathMLmoverFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -177,6 +181,7 @@ XXX The winner is the outermost in conflicting settings like these: if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) mPresentationData.flags |= NS_MATHML_ACCENTOVER; } +//XXX should sync the presentation data be at this spot, after the if? } } } @@ -191,8 +196,8 @@ XXX The winner is the outermost in conflicting settings like these: if (overscriptMathMLFrame) { incrementScriptLevel = NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)? 0 : 1; - overscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE); - overscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE); + overscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE, PR_FALSE); + overscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE, PR_FALSE); } // switch the style of the overscript @@ -200,35 +205,6 @@ XXX The winner is the outermost in conflicting settings like these: return rv; } - -NS_IMETHODIMP -nsMathMLmoverFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - - nsresult rv = NS_OK; - - ///////////// - // Reflow children - ReflowChildren(1, aPresContext, aDesiredSize, aReflowState, aStatus); - - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - - ///////////// - // Ask stretchy children to stretch themselves - nsStretchMetrics containerSize(aDesiredSize); - nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; - StretchChildren(aPresContext, renderingContext, stretchDir, containerSize); - - ///////////// - // Place children now by re-adjusting the origins to align the baselines - FinalizeReflow(1, aPresContext, renderingContext, aDesiredSize); - - aStatus = NS_FRAME_COMPLETE; - return NS_OK; -} /* The REC says: @@ -254,84 +230,152 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nscoord count = 0; - nsRect rect[2]; - nsIFrame* child[2]; - nscoord width[2]; - nscoord maxWidth = 0; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsBoundingMetrics bmBase, bmOver; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics overSize (nsnull); + nsIFrame* baseFrame = nsnull; + nsIFrame* overFrame = nsnull; + nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 2 > count) { - childFrame->GetRect(rect[count]); - child[count] = childFrame; - - if (aPlaceOrigin) { - width[count] = rect[count].width; - if (IsEmbellishOperator(childFrame)) { - // treated as if embellishments were not there... - nsIMathMLFrame* aMathMLFrame = nsnull; - nsresult rv = childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame); - NS_ASSERTION(NS_SUCCEEDED(rv) && aMathMLFrame, "Mystery!"); - if (NS_SUCCEEDED(rv) && aMathMLFrame) { - nsRect rect; - 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 + if (!IsOnlyWhitespace(childFrame)) { + if (0 == count) { + // base + baseFrame = childFrame; + GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); + } + else if (1 == count) { + // over + overFrame = childFrame; + GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver); } - count++; - } - childFrame->GetNextSibling(&childFrame); + } + rv = childFrame->GetNextSibling(&childFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } + if ((2 != count) || !baseFrame || !overFrame) { +#ifdef NS_DEBUG + printf("mover: invalid markup"); +#endif + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); } - aDesiredSize.ascent = rect[0].y; - aDesiredSize.descent = rect[0].x; - aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); + //////////////////// + // Place Children - aDesiredSize.ascent += rect[1].height; - aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - if (aPlaceOrigin) { - rect[0].x = (maxWidth - width[0]) / 2; // center w.r.t largest width - rect[1].x = (maxWidth - width[1]) / 2; - rect[1].y = 0; - rect[0].y = rect[1].height; - } -//ignore the leading (line spacing) that is attached to the text - nscoord leading; + const nsStyleFont* font = + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aRenderingContext.SetFont(font->mFont); nsCOMPtr fm; - const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetLeading(leading); - - aDesiredSize.height -= leading; - aDesiredSize.ascent -= leading; - rect[0].y -= leading; -// - if (aPlaceOrigin) { - // child[0]->SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; iGetXHeight (xHeight); + + nscoord ruleThickness; + GetRuleThickness (aRenderingContext, fm, ruleThickness); + + // there are 2 different types of placement depending on + // whether we want an accented overscript or not + + nscoord correction = 0; + nscoord delta1 = 0; // gap between base and overscript + nscoord delta2 = 0; // extra space above overscript + if (!NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)) { + // Rule 13a, App. G, TeXbook +// GetItalicCorrectionFromChild (baseFrame, correction); + nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; + GetBigOpSpacings (fm, + bigOpSpacing1, dummy, + bigOpSpacing3, dummy, + bigOpSpacing5); + delta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent)); + delta2 = bigOpSpacing5; + + // XXX This is not a TeX rule... + // delta1 (as computed abvove) can become really big when bmOver.descent is + // negative, e.g., if the content is &OverBar. In such case, we use the height + if (bmOver.descent < 0) + delta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent))); } - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; + else { + // Rule 12, App. G, TeXbook + GetSkewCorrectionFromChild (aPresContext, baseFrame, correction); +#if 0 + delta1 = -PR_MIN(bmBase.ascent, xHeight); +#endif + // We don't follow Rule 12 here since TeX has some implicit + // assumptions in the computation of delta1. + // Should we use Rule 9 like \overline does? + delta1 = ruleThickness; + delta2 = ruleThickness; + } + // empty over? + if (0 == (bmOver.ascent + bmOver.descent)) delta1 = 0; + + mBoundingMetrics.ascent = + bmOver.ascent + bmOver.descent + delta1 + bmBase.ascent; + +#if 0 + // Rule 12 (cont.) + if (NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)) { + // delta1 is -ve for an accent + // hence as per Rule 12, App. G, TeXbook, we should ... + mBoundingMetrics.ascent = PR_MAX(mBoundingMetrics.ascent, bmBase.ascent); + } +#endif + + mBoundingMetrics.descent = bmBase.descent; + if (NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)) { + mBoundingMetrics.width = PR_MAX(bmBase.width, bmOver.width); + } + else { + mBoundingMetrics.width = + PR_MAX(bmBase.width/2,(bmOver.width + correction/2)/2) + + PR_MAX(bmBase.width/2,(bmOver.width - correction/2)/2); } - // XXX Fix me! - mBoundingMetrics.ascent = aDesiredSize.ascent; - mBoundingMetrics.descent = aDesiredSize.descent; - mBoundingMetrics.width = aDesiredSize.width; + aDesiredSize.descent = baseSize.descent; + aDesiredSize.ascent = mBoundingMetrics.ascent + delta2; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; + + nscoord dxBase, dyBase; + nscoord dxOver, dyOver; + + dxBase = (mBoundingMetrics.width - bmBase.width) / 2; + dyBase = aDesiredSize.ascent - baseSize.ascent; + + if (NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)) { + dxOver = correction + (mBoundingMetrics.width - bmOver.width)/2; + } + else { + dxOver = correction/2 + (mBoundingMetrics.width - bmOver.width)/2; + } + + dyOver = aDesiredSize.ascent - mBoundingMetrics.ascent + bmOver.ascent - overSize.ascent; + + mReference.x = 0; + mReference.y = aDesiredSize.ascent; + + mBoundingMetrics.leftBearing = + PR_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing); + mBoundingMetrics.rightBearing = + PR_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing); + + if (aPlaceOrigin) { + // place base + FinishReflowChild (baseFrame, aPresContext, baseSize, dxBase, dyBase, 0); + // place overscript + FinishReflowChild (overFrame, aPresContext, overSize, dxOver, dyOver, 0); + } return NS_OK; } diff --git a/layout/mathml/base/src/nsMathMLmoverFrame.h b/layout/mathml/base/src/nsMathMLmoverFrame.h index 83ee958bdbae..41d3c7f2e720 100644 --- a/layout/mathml/base/src/nsMathMLmoverFrame.h +++ b/layout/mathml/base/src/nsMathMLmoverFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmoverFrame_h___ @@ -41,12 +42,6 @@ public: nsIStyleContext* aContext, nsIFrame* aPrevInFlow); - NS_IMETHOD - Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); - NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/mathml/base/src/nsMathMLmpaddedFrame.cpp b/layout/mathml/base/src/nsMathMLmpaddedFrame.cpp index c0f032b41ff7..59ef91deb371 100644 --- a/layout/mathml/base/src/nsMathMLmpaddedFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmpaddedFrame.cpp @@ -89,7 +89,7 @@ nsMathMLmpaddedFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; /* parse the attributes @@ -139,6 +139,9 @@ nsMathMLmpaddedFrame::Init(nsIPresContext* aPresContext, ParseAttribute(value, mLeftSpaceSign, mLeftSpace, mLeftSpacePseudoUnit); } +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -172,11 +175,9 @@ nsMathMLmpaddedFrame::ParseAttribute(nsString& aString, else aSign = NS_MATHML_SIGN_UNSPECIFIED; -/* - // skip any space in-between + // skip any space after the sign while (i < stringLength && XP_IS_SPACE(aString[i])) i++; -*/ /////////////////////// // get the string that represents the numeric value @@ -226,15 +227,18 @@ nsMathMLmpaddedFrame::ParseAttribute(nsString& aString, return PR_FALSE; } + // else the only other valid possibility here is a percentage value, + // otherwise ParseNumericValue() would have failed + aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF; return PR_TRUE; } aString.Right(value, stringLength - i); - if (value == "width") aPseudoUnit = NS_MATHML_PSEUDO_UNIT_WIDTH; - else if (value == "height") aPseudoUnit = NS_MATHML_PSEUDO_UNIT_HEIGHT; - else if (value == "depth") aPseudoUnit = NS_MATHML_PSEUDO_UNIT_DEPTH; - else if (value == "lspace") aPseudoUnit = NS_MATHML_PSEUDO_UNIT_LSPACE; + if (value.Equals("width")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_WIDTH; + else if (value.Equals("height")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_HEIGHT; + else if (value.Equals("depth")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_DEPTH; + else if (value.Equals("lspace")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_LSPACE; else // unexpected pseudo-unit { aCSSValue.Reset(); @@ -265,7 +269,7 @@ nsMathMLmpaddedFrame::UpdateValue(nsIPresContext* aPresContext, PRInt32 aPseudoUnit, nsCSSValue& aCSSValue, nscoord aLeftSpace, - nsHTMLReflowMetrics& aReflowMetrics, + nsBoundingMetrics& aBoundingMetrics, nscoord& aValueToUpdate) { nsCSSUnit unit = aCSSValue.GetUnit(); @@ -278,15 +282,15 @@ nsMathMLmpaddedFrame::UpdateValue(nsIPresContext* aPresContext, switch(aPseudoUnit) { case NS_MATHML_PSEUDO_UNIT_WIDTH: - scaler = aReflowMetrics.width; + scaler = aBoundingMetrics.width; break; case NS_MATHML_PSEUDO_UNIT_HEIGHT: - scaler = aReflowMetrics.ascent; + scaler = aBoundingMetrics.ascent; break; case NS_MATHML_PSEUDO_UNIT_DEPTH: - scaler = aReflowMetrics.descent; + scaler = aBoundingMetrics.descent; break; case NS_MATHML_PSEUDO_UNIT_LSPACE: @@ -295,16 +299,16 @@ nsMathMLmpaddedFrame::UpdateValue(nsIPresContext* aPresContext, default: // if we ever reach here, it would mean something is wrong - // somwehere with the setup and/or the caller + // somewhere with the setup and/or the caller NS_ASSERTION(0, "Unexpected Pseudo Unit"); return; } } if (eCSSUnit_Number == unit) - amount = nscoord(float(scaler) * aCSSValue.GetFloatValue()); + amount = NSToCoordRound(float(scaler) * aCSSValue.GetFloatValue()); else if (eCSSUnit_Percent == unit) - amount = nscoord(float(scaler) * aCSSValue.GetPercentValue()); + amount = NSToCoordRound(float(scaler) * aCSSValue.GetPercentValue()); else amount = CalcLength(aPresContext, aStyleContext, aCSSValue); @@ -322,7 +326,7 @@ nsMathMLmpaddedFrame::UpdateValue(nsIPresContext* aPresContext, to 0 if it would otherwise become negative. Dimensions which are initially 0 can be made negative */ - if (0 <= oldValue && 0 > aValueToUpdate) aValueToUpdate = 0; + if (0 < oldValue && 0 > aValueToUpdate) aValueToUpdate = 0; } } @@ -344,9 +348,9 @@ nsMathMLmpaddedFrame::Reflow(nsIPresContext* aPresContext, return rv; } - nscoord height = aDesiredSize.ascent; - nscoord depth = aDesiredSize.descent; - nscoord width = aDesiredSize.width; + nscoord height = mBoundingMetrics.ascent; + nscoord depth = mBoundingMetrics.descent; + nscoord width = mBoundingMetrics.width; nscoord lspace = 0; // it is unclear from the REC what is the default here PRInt32 pseudoUnit; @@ -356,33 +360,51 @@ nsMathMLmpaddedFrame::Reflow(nsIPresContext* aPresContext, ? NS_MATHML_PSEUDO_UNIT_WIDTH : mWidthPseudoUnit; UpdateValue(aPresContext, mStyleContext, mWidthSign, pseudoUnit, mWidth, - lspace, aDesiredSize, width); + lspace, mBoundingMetrics, width); // update height pseudoUnit = (mHeightPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_HEIGHT : mHeightPseudoUnit; UpdateValue(aPresContext, mStyleContext, mHeightSign, pseudoUnit, mHeight, - lspace, aDesiredSize, height); + lspace, mBoundingMetrics, height); // update depth pseudoUnit = (mDepthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_DEPTH : mDepthPseudoUnit; UpdateValue(aPresContext, mStyleContext, mDepthSign, pseudoUnit, mDepth, - lspace, aDesiredSize, depth); + lspace, mBoundingMetrics, depth); // update lspace -- should be *last* because lspace is overwritten!! pseudoUnit = (mLeftSpacePseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_LSPACE : mLeftSpacePseudoUnit; UpdateValue(aPresContext, mStyleContext, mLeftSpaceSign, pseudoUnit, mLeftSpace, - lspace, aDesiredSize, lspace); + lspace, mBoundingMetrics, lspace); // do the padding now that we have everything - nscoord dy = height - aDesiredSize.ascent; + if (lspace != 0) { // there was padding on the left + mBoundingMetrics.leftBearing = 0; + } + + if (width != mBoundingMetrics.width) { // there was padding on the right + mBoundingMetrics.rightBearing = lspace + width; + } + + nscoord dy = height - mBoundingMetrics.ascent; nscoord dx = lspace; + + mBoundingMetrics.ascent = height; + mBoundingMetrics.descent = depth; + mBoundingMetrics.width = lspace + width; + + aDesiredSize.ascent += dy; + aDesiredSize.descent += depth - mBoundingMetrics.descent; + aDesiredSize.width = mBoundingMetrics.width; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + if (0 != dx || 0 != dy) { nsRect rect; nsIFrame* childFrame = mFrames.FirstChild(); @@ -393,12 +415,8 @@ nsMathMLmpaddedFrame::Reflow(nsIPresContext* aPresContext, } } - aDesiredSize.ascent = height; - aDesiredSize.descent = depth; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - aDesiredSize.width = width; - - // XXX need to tweak mBoundingMetrics/mReference as well ... + mReference.x = 0; + mReference.y = aDesiredSize.ascent; return NS_OK; } diff --git a/layout/mathml/base/src/nsMathMLmpaddedFrame.h b/layout/mathml/base/src/nsMathMLmpaddedFrame.h index 6d212cd37108..a7ac2a63f12e 100644 --- a/layout/mathml/base/src/nsMathMLmpaddedFrame.h +++ b/layout/mathml/base/src/nsMathMLmpaddedFrame.h @@ -83,7 +83,7 @@ private: PRInt32 aPseudoUnit, nsCSSValue& aCSSValue, nscoord aLeftSpace, - nsHTMLReflowMetrics& aReflowMetrics, + nsBoundingMetrics& aBoundingMetrics, nscoord& aValueToUpdate); }; diff --git a/layout/mathml/base/src/nsMathMLmphantomFrame.cpp b/layout/mathml/base/src/nsMathMLmphantomFrame.cpp index aee7ea32295c..a8728f9f831f 100644 --- a/layout/mathml/base/src/nsMathMLmphantomFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmphantomFrame.cpp @@ -66,6 +66,19 @@ nsMathMLmphantomFrame::~nsMathMLmphantomFrame() { } +NS_IMETHODIMP +nsMathMLmphantomFrame::Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; + return rv; +} + NS_METHOD nsMathMLmphantomFrame::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/mathml/base/src/nsMathMLmphantomFrame.h b/layout/mathml/base/src/nsMathMLmphantomFrame.h index 34fe411b0b8c..9076cc8f1438 100644 --- a/layout/mathml/base/src/nsMathMLmphantomFrame.h +++ b/layout/mathml/base/src/nsMathMLmphantomFrame.h @@ -34,6 +34,13 @@ class nsMathMLmphantomFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmphantomFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + Init(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/mathml/base/src/nsMathMLmrootFrame.cpp b/layout/mathml/base/src/nsMathMLmrootFrame.cpp index 9a11657e669d..024e587b036f 100644 --- a/layout/mathml/base/src/nsMathMLmrootFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmrootFrame.cpp @@ -19,6 +19,7 @@ * Roger B. Sidje * David J. Fiddes * Vilya Harvey + * Shyjan Mahamud */ @@ -41,9 +42,18 @@ #include "nsMathMLmrootFrame.h" // -// and -- form a radical +// and -- form a radical - implementation // +//TODO: +// The code assumes that TeX fonts are picked! Another separate version of +// Reflow() is needed as a fall-back for cases where TeX fonts (CMSY/CMEX) +// are not installed on the system, e.g., the fall-back could explicitly +// draw the branches of the radical using th default rule thickness. + +// additional style context to be used by our MathMLChar. +#define NS_SQR_CHAR_STYLE_CONTEXT_INDEX 0 + nsresult NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { @@ -55,16 +65,14 @@ NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } - *aNewFrame = it; + *aNewFrame = it; return NS_OK; } nsMathMLmrootFrame::nsMathMLmrootFrame() : mSqrChar(), - mBarChar() + mBarRect() { - mSqrChar.SetEnum(eMathMLChar_Sqrt); - mBarChar.SetEnum(eMathMLChar_OverBar); } nsMathMLmrootFrame::~nsMathMLmrootFrame() @@ -73,14 +81,23 @@ nsMathMLmrootFrame::~nsMathMLmrootFrame() NS_IMETHODIMP nsMathMLmrootFrame::Init(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsIStyleContext* aContext, - nsIFrame* aPrevInFlow) + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) { - nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + nsresult rv = NS_OK; + rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, + aContext, aPrevInFlow); - // XXX Attributes? + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; + + mSqrChar.SetEnum(aPresContext, eMathMLChar_Sqrt); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSqrChar); + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -90,18 +107,47 @@ nsMathMLmrootFrame::Paint(nsIPresContext* aPresContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer) { - ///////////// - // paint the base and the index - nsresult rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, - aDirtyRect, aWhichLayer); + nsresult rv = NS_OK; - if (NS_SUCCEEDED(rv) && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { - // paint the sqrt symbol - rv = mSqrChar.Paint(aPresContext, aRenderingContext, mStyleContext); + + ///////////// + // paint the sqrt symbol + if ((NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) && + !NS_MATHML_HAS_ERROR(mPresentationData.flags)) + { + mSqrChar.Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); // paint the overline bar - rv = mBarChar.Paint(aPresContext, aRenderingContext, mStyleContext); + nsStyleColor color; + mStyleContext->GetStyle(eStyleStruct_Color, color); + aRenderingContext.SetColor(color.mColor); + aRenderingContext.FillRect(mBarRect.x, mBarRect.y, + mBarRect.width, mBarRect.height); + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + // for visual debug + if (NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags)) + { + nsRect rect; + mSqrChar.GetRect(rect); + + nsBoundingMetrics bm; + mSqrChar.GetBoundingMetrics(bm); + + aRenderingContext.SetColor(NS_RGB(255,0,0)); + nscoord x = rect.x + bm.leftBearing; + nscoord y = rect.y; + nscoord w = bm.rightBearing - bm.leftBearing; + nscoord h = bm.ascent + bm.descent; + aRenderingContext.DrawRect(x,y,w,h); + } +#endif } + ///////////// + // paint the content we are square-rooting + rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer); return rv; } @@ -112,28 +158,30 @@ nsMathMLmrootFrame::Reflow(nsIPresContext* aPresContext, nsReflowStatus& aStatus) { nsresult rv = NS_OK; - nsReflowStatus childStatus; // 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); + nsReflowStatus childStatus; + + aDesiredSize.width = aDesiredSize.height = 0; + aDesiredSize.ascent = aDesiredSize.descent = 0; + + nsBoundingMetrics bmSqr, bmBase, bmIndex; + nsIRenderingContext& renderingContext = *aReflowState.rendContext; ////////////////// // Reflow Children PRInt32 count = 0; - nsIFrame* child[2]; - nsRect rect[4]; - aDesiredSize.width = aDesiredSize.height = aDesiredSize.ascent = aDesiredSize.descent = 0; + nsIFrame* baseFrame = nsnull; + nsIFrame* indexFrame = nsnull; + nsHTMLReflowMetrics baseSize(nsnull); + nsHTMLReflowMetrics indexSize(nsnull); nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - ////////////// - // WHITESPACE: don't forget that whitespace doesn't count in MathML! - if (IsOnlyWhitespace(childFrame)) { - ReflowEmptyChild(aPresContext, childFrame); - } - else if (2 > count) { + if (!IsOnlyWhitespace(childFrame)) { nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); rv = ReflowChild(childFrame, aPresContext, @@ -143,134 +191,199 @@ nsMathMLmrootFrame::Reflow(nsIPresContext* aPresContext, return rv; } if (0 == count) { - aDesiredSize.descent = childDesiredSize.descent; - aDesiredSize.ascent = childDesiredSize.ascent; - aDesiredSize.width = childDesiredSize.width; + // base + baseFrame = childFrame; + baseSize = childDesiredSize; + bmBase = childDesiredSize.mBoundingMetrics; + } + else if (1 == count) { + // index + indexFrame = childFrame; + indexSize = childDesiredSize; + bmIndex = childDesiredSize.mBoundingMetrics; } - // At this stage, the origin points of the children have no use, so we - // will use the origins as placeholders to store the child's ascent and - // descent. Before return, we should set the origins so as to overwrite - // what we are storing there now. - child[count] = childFrame; - rect[count] = nsRect(childDesiredSize.descent, childDesiredSize.ascent, - childDesiredSize.width, childDesiredSize.height); count++; } -// else { invalid markup... } - rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + if ((2 != count) || !baseFrame || !indexFrame) { +#ifdef NS_DEBUG + printf("mroot: invalid markup"); +#endif + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, renderingContext, aDesiredSize); + } //////////// // Prepare the radical symbol and the overline bar - nsIRenderingContext& renderingContext = *aReflowState.rendContext; nsStyleFont font; mStyleContext->GetStyle(eStyleStruct_Font, font); renderingContext.SetFont(font.mFont); - - // grab some metrics to help adjusting the placements nsCOMPtr fm; - nscoord fontAscent, fontDescent; renderingContext.GetFontMetrics(*getter_AddRefs(fm)); - fm->GetMaxAscent(fontAscent); - fm->GetMaxDescent(fontDescent); - nsBoundingMetrics bmSqr, bmBar; - nscoord dx, dy; + nscoord ruleThickness; + GetRuleThickness(renderingContext, fm, ruleThickness); - // radical symbol - renderingContext.GetBoundingMetrics(mSqrChar.GetUnicode(), PRUint32(1), bmSqr); - nscoord widthSqr = bmSqr.width; // width of the radical symbol + // Rule 11, App. G, TeXbook + // psi = clearance between rule and content + nscoord phi = 0, psi = 0; + if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) + fm->GetXHeight(phi); + else + phi = ruleThickness; + psi = ruleThickness + phi/4; + + // Stretch the radical symbol to the appropriate height if it is not big enough. + nsBoundingMetrics contSize = bmBase; + contSize.descent = bmBase.ascent + bmBase.descent + psi; + contSize.ascent = ruleThickness; - // overline bar - renderingContext.GetBoundingMetrics(mBarChar.GetUnicode(), PRUint32(1), bmBar); - nscoord heightBar = bmBar.ascent - bmBar.descent; // height of the overline bar + nsBoundingMetrics radicalSize; + radicalSize.Clear(); // this tells Stretch() that we don't know the current size - // Stretch the sqrt symbol to the appropriate height if it is not big enough. - nsStretchMetrics contSize(aDesiredSize); - nsStretchMetrics desSize(fontDescent, fontAscent, widthSqr, fontAscent + fontDescent); - mSqrChar.Stretch(aPresContext, renderingContext, mStyleContext, - NS_STRETCH_DIRECTION_VERTICAL, contSize, desSize); - widthSqr = desSize.width; - if (aDesiredSize.ascent < desSize.ascent) { - aDesiredSize.ascent = desSize.ascent; - } - if (aDesiredSize.descent < desSize.descent) { - aDesiredSize.descent = desSize.descent; - } + // height(radical) should be >= height(base) + psi + ruleThickness + // however, nsMathMLChar will only try to meet this condition + // with no guarantee. + mSqrChar.Stretch(aPresContext, renderingContext, + NS_STRETCH_DIRECTION_VERTICAL, + contSize, radicalSize, + NS_STRETCH_LARGER); + // radicalSize have changed at this point, and should match with + // the bounding metrics of the char + mSqrChar.GetBoundingMetrics(bmSqr); + + // According to TeX, the ascent of the returned radical should be + // the thickness of the overline + ruleThickness = bmSqr.ascent; + + // adjust clearance psi to absorb any excess difference if any + // in height between radical and content + + if (bmSqr.descent > (bmBase.ascent + bmBase.descent) + psi) + psi = (psi + bmSqr.descent - (bmBase.ascent + bmBase.descent))/2; + + // Update the desired size for the container (like msqrt, index is not yet uncluded) + // the baseline will be that of the base. + mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; + mBoundingMetrics.descent = + PR_MAX(bmBase.descent, (bmSqr.descent - (bmBase.ascent + psi))); + mBoundingMetrics.width = bmSqr.width + bmBase.width; + mBoundingMetrics.leftBearing = bmSqr.leftBearing; + mBoundingMetrics.rightBearing = bmSqr.width + + PR_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule + + aDesiredSize.ascent = mBoundingMetrics.ascent + ruleThickness; + aDesiredSize.descent = + PR_MAX(baseSize.descent, (mBoundingMetrics.descent + ruleThickness)); aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; - dx = 0; - dy = bmSqr.ascent - fontAscent; - rect[2] = nsRect(dx, dy, desSize.width, aDesiredSize.height); - dx = bmSqr.rightBearing; + ///////////// + // Re-adjust the desired size to include the index. + + // the index is raised by some fraction of the height + // of the radical, see \mroot macro in App. B, TexBook + nscoord raiseIndexDelta = NSToCoordRound(0.6f * (bmSqr.ascent + bmSqr.descent)); + nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical + - (bmSqr.ascent + bmSqr.descent) // to bottom of radical + + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index - // Stretch the overline bar to the appropriate width if it is not big enough. - contSize = nsStretchMetrics(aDesiredSize); - desSize = nsStretchMetrics(fontDescent, fontAscent, bmBar.rightBearing-bmBar.leftBearing, fontAscent + fontDescent); - nsStretchMetrics oldSize = desSize; - mBarChar.Stretch(aPresContext, renderingContext, mStyleContext, - NS_STRETCH_DIRECTION_HORIZONTAL, contSize, desSize); - - dy = bmBar.ascent - fontAscent; - if (oldSize == desSize) { // hasn't changed size! Char will be painted as a normal char - dx -= bmBar.leftBearing; // adjust so that it coincides with the sqrt char - } - rect[3] = nsRect(dx, dy, desSize.width, heightBar); - - ////////////////// - // Place Children now by setting the origin of each child. - - nscoord thickspace = bmBar.ascent-bmBar.descent; // height of the bar - aDesiredSize.ascent += thickspace; - rect[0].y = aDesiredSize.ascent - rect[0].y; // y-origin of base - dy = thickspace + (bmSqr.ascent-bmSqr.descent)/3 - rect[1].height; - rect[1].y = dy; - if (0 > dy) { - dy = -dy; - aDesiredSize.ascent += dy; - rect[0].y += dy; - rect[1].y = 0; - rect[2].y += dy; // y-origin of bar - rect[3].y += dy; // y-origin of sqrt char + nscoord indexClearance = 0; + if (mBoundingMetrics.ascent < indexRaisedAscent) { + indexClearance = + indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index + mBoundingMetrics.ascent = indexRaisedAscent; + aDesiredSize.ascent = mBoundingMetrics.ascent + ruleThickness; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; } - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - rect[1].x = 0; // x-origin of index - rect[0].x = widthSqr; - aDesiredSize.width = widthSqr + rect[0].width; - if (0 < rect[1].width) { - dx = rect[1].width - (bmSqr.rightBearing - bmSqr.leftBearing)/2; - aDesiredSize.width += dx; - rect[0].x += dx; // x-origin of base - rect[2].x += dx; // x-origin of sqrt char - rect[3].x += dx; // x-origin of bar + // the index is tucked in closer to the radical + // XXX assumes that the kern does not make the content and radical collide. + nscoord xHeight = 0; + fm->GetXHeight(xHeight); + nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight); + if (indexRadicalKern < bmIndex.width) + { + mBoundingMetrics.width += (bmIndex.width - indexRadicalKern); + aDesiredSize.width = mBoundingMetrics.width; } - - // child[0]->SetRect(aPresContext, rect[0]); - // child[1]->SetRect(aPresContext, rect[1]); - nsHTMLReflowMetrics childSize(nsnull); - for (PRInt32 i=0; i bmIndex.width) ? indexRadicalKern - bmIndex.width : 0; + dy = aDesiredSize.ascent - (indexRaisedAscent + indexSize.ascent - bmIndex.ascent); + FinishReflowChild(indexFrame, aPresContext, indexSize, dx, dy, 0); + + lbearing = dx + bmIndex.leftBearing; + + // place the radical symbol + dx = (indexRadicalKern > bmIndex.width) ? 0 : bmIndex.width - indexRadicalKern; + dy = indexClearance + ruleThickness; // leave a kern=ruleThickness at the top + mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); + + if (lbearing < dx + bmSqr.leftBearing) { + mBoundingMetrics.leftBearing = lbearing; + mBoundingMetrics.rightBearing += dx; } - mSqrChar.SetRect(rect[2]); - mBarChar.SetRect(rect[3]); + + // place the radical bar + dx += bmSqr.width; + dy = indexClearance + ruleThickness; // leave a kern=ruleThickness at the top + mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness); + + // place the base + dy = aDesiredSize.ascent - baseSize.ascent; + FinishReflowChild(baseFrame, aPresContext, baseSize, dx, dy, 0); if (nsnull != aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + aDesiredSize.mBoundingMetrics = mBoundingMetrics; aStatus = NS_FRAME_COMPLETE; + return NS_OK; +} - // XXX Fix me! - mBoundingMetrics.ascent = aDesiredSize.ascent; - mBoundingMetrics.descent = aDesiredSize.descent; - mBoundingMetrics.width = aDesiredSize.width; +// ---------------------- +// the Style System will use these to pass the proper style context to our MathMLChar +NS_IMETHODIMP +nsMathMLmrootFrame::GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const +{ + NS_PRECONDITION(aStyleContext, "null OUT ptr"); + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + *aStyleContext = nsnull; + switch (aIndex) { + case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: + mSqrChar.GetStyleContext(aStyleContext); + break; + default: + return NS_ERROR_INVALID_ARG; + } + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmrootFrame::SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext) +{ + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + switch (aIndex) { + case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: + mSqrChar.SetStyleContext(aStyleContext); + break; + } return NS_OK; } diff --git a/layout/mathml/base/src/nsMathMLmrootFrame.h b/layout/mathml/base/src/nsMathMLmrootFrame.h index 0946a38828b2..06402cc36564 100644 --- a/layout/mathml/base/src/nsMathMLmrootFrame.h +++ b/layout/mathml/base/src/nsMathMLmrootFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmrootFrame_h___ @@ -33,7 +34,14 @@ class nsMathMLmrootFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); - + + NS_IMETHOD + SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext); + NS_IMETHOD + GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const; + NS_IMETHOD Init(nsIPresContext* aPresContext, nsIContent* aContent, @@ -48,7 +56,7 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(1, 2, PR_FALSE); + UpdatePresentationDataFromChildAt(1, 2, PR_FALSE, PR_FALSE); InsertScriptLevelStyleContext(aPresContext); return rv; } @@ -71,7 +79,8 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } - nsMathMLChar mSqrChar, mBarChar; + nsMathMLChar mSqrChar; + nsRect mBarRect; }; #endif /* nsMathMLmrootFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmrowFrame.cpp b/layout/mathml/base/src/nsMathMLmrowFrame.cpp index e913dcc45e33..0ec0876223ac 100644 --- a/layout/mathml/base/src/nsMathMLmrowFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmrowFrame.cpp @@ -75,8 +75,10 @@ nsMathMLmrowFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; - // XXX Attributes? +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } diff --git a/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp b/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp index 4df076e7147e..1868c0d91f6a 100644 --- a/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmsqrtFrame.cpp @@ -19,6 +19,7 @@ * Roger B. Sidje * David J. Fiddes * Vilya Harvey + * Shyjan Mahamud */ @@ -44,6 +45,15 @@ // and -- form a radical - implementation // +//TODO: +// The code assumes that TeX fonts are picked! Another separate version of +// Reflow() is needed as a fall-back for cases where TeX fonts (CMSY/CMEX) +// are not installed on the system, e.g., the fall-back could explicitly +// draw the branches of the radical using th default rule thickness. + +// additional style context to be used by our MathMLChar. +#define NS_SQR_CHAR_STYLE_CONTEXT_INDEX 0 + nsresult NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { @@ -61,10 +71,8 @@ NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) nsMathMLmsqrtFrame::nsMathMLmsqrtFrame() : mSqrChar(), - mBarChar() + mBarRect() { - mSqrChar.SetEnum(eMathMLChar_Sqrt); - mBarChar.SetEnum(eMathMLChar_OverBar); } nsMathMLmsqrtFrame::~nsMathMLmsqrtFrame() @@ -82,9 +90,14 @@ nsMathMLmsqrtFrame::Init(nsIPresContext* aPresContext, rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; - // TODO: other attributes... + mSqrChar.SetEnum(aPresContext, eMathMLChar_Sqrt); + ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSqrChar); + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -95,19 +108,46 @@ nsMathMLmsqrtFrame::Paint(nsIPresContext* aPresContext, nsFramePaintLayer aWhichLayer) { nsresult rv = NS_OK; + + ///////////// + // paint the sqrt symbol + if ((NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) && + !NS_MATHML_HAS_ERROR(mPresentationData.flags)) + { + mSqrChar.Paint(aPresContext, aRenderingContext, + aDirtyRect, aWhichLayer, this); + // paint the overline bar + nsStyleColor color; + mStyleContext->GetStyle(eStyleStruct_Color, color); + aRenderingContext.SetColor(color.mColor); + aRenderingContext.FillRect(mBarRect.x, mBarRect.y, + mBarRect.width, mBarRect.height); + +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + // for visual debug + if (NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags)) + { + nsRect rect; + mSqrChar.GetRect(rect); + + nsBoundingMetrics bm; + mSqrChar.GetBoundingMetrics(bm); + + aRenderingContext.SetColor(NS_RGB(255,0,0)); + nscoord x = rect.x + bm.leftBearing; + nscoord y = rect.y; + nscoord w = bm.rightBearing - bm.leftBearing; + nscoord h = bm.ascent + bm.descent; + aRenderingContext.DrawRect(x,y,w,h); + } +#endif + } + ///////////// // paint the content we are square-rooting rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); - - if (NS_SUCCEEDED(rv) && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { - // paint the sqrt symbol - rv = mSqrChar.Paint(aPresContext, aRenderingContext, mStyleContext); - // paint the overline bar - rv = mBarChar.Paint(aPresContext, aRenderingContext, mStyleContext); - } - return rv; } @@ -119,96 +159,111 @@ nsMathMLmsqrtFrame::Reflow(nsIPresContext* aPresContext, { nsresult rv = NS_OK; + nsBoundingMetrics bmSqr, bmBase; + /////////////// // Let the base class format our content like an inferred mrow - rv = nsMathMLContainerFrame::Reflow(aPresContext, aDesiredSize, + nsHTMLReflowMetrics baseSize(aDesiredSize); + rv = nsMathMLContainerFrame::Reflow(aPresContext, baseSize, aReflowState, aStatus); NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); if (NS_FAILED(rv)) { return rv; } - nscoord oldAscent = aDesiredSize.ascent; + + bmBase = baseSize.mBoundingMetrics; //////////// // Prepare the radical symbol and the overline bar + nsIRenderingContext& renderingContext = *aReflowState.rendContext; nsStyleFont font; mStyleContext->GetStyle(eStyleStruct_Font, font); renderingContext.SetFont(font.mFont); - - // grab some metrics that will help to adjust the placements nsCOMPtr fm; - nscoord fontAscent, fontDescent; renderingContext.GetFontMetrics(*getter_AddRefs(fm)); - fm->GetMaxAscent(fontAscent); - fm->GetMaxDescent(fontDescent); - float p2t; - aPresContext->GetScaledPixelsToTwips(&p2t); - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nscoord ruleThickness; + GetRuleThickness(renderingContext, fm, ruleThickness); - nsBoundingMetrics bmSqr, bmBar; - nscoord dx, dy; + // Rule 11, App. G, TeXbook + // psi = clearance between rule and content + nscoord phi = 0, psi = 0; + if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) + fm->GetXHeight(phi); + else + phi = ruleThickness; + psi = ruleThickness + phi/4; + + // Stretch the radical symbol to the appropriate height if it is not big enough. + nsBoundingMetrics contSize = bmBase; + contSize.ascent = ruleThickness; + contSize.descent = bmBase.ascent + bmBase.descent + psi; - // radical symbol - renderingContext.GetBoundingMetrics(mSqrChar.GetUnicode(), PRUint32(1), bmSqr); - nscoord charWidth = bmSqr.width; // width of the radical symbol + nsBoundingMetrics radicalSize; + radicalSize.Clear(); // this tells Stretch() that we don't know the current size - // overline bar - renderingContext.GetBoundingMetrics(mBarChar.GetUnicode(), PRUint32(1), bmBar); - nscoord thickspace = bmBar.ascent + bmBar.descent; // height of the overline bar + // height(radical) should be >= height(base) + psi + ruleThickness + // however, nsMathMLChar will only try to meet this condition + // with no guarantee. + mSqrChar.Stretch(aPresContext, renderingContext, + NS_STRETCH_DIRECTION_VERTICAL, + contSize, radicalSize, + NS_STRETCH_LARGER); + // radicalSize have changed at this point, and should match with + // the bounding metrics of the char + mSqrChar.GetBoundingMetrics(bmSqr); - // Stretch the sqrt symbol to the appropriate height if it is not big enough. - nsStretchMetrics contSize(aDesiredSize); - nsStretchMetrics desSize(fontDescent, fontAscent, charWidth, fontAscent + fontDescent); - mSqrChar.Stretch(aPresContext, renderingContext, mStyleContext, - NS_STRETCH_DIRECTION_VERTICAL, contSize, desSize); - charWidth = desSize.width; - if (aDesiredSize.ascent < desSize.ascent) { - aDesiredSize.ascent = desSize.ascent; - } - if (aDesiredSize.descent < desSize.descent) { - aDesiredSize.descent = desSize.descent; - } + // According to TeX, the ascent of the returned radical should be + // the thickness of the overline + ruleThickness = bmSqr.ascent; + + // adjust clearance psi to absorb any excess difference if any + // in height between radical and content + + if (bmSqr.descent > (bmBase.ascent + bmBase.descent) + psi) + psi = (psi + bmSqr.descent - (bmBase.ascent + bmBase.descent))/2; + + nscoord dx = 0, dy = 0; + // place the radical symbol + dy = ruleThickness; // leave a kern=ruleThickness at the top + mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); + + // place the radical bar + dx = bmSqr.width; + dy = ruleThickness; // leave a kern=ruleThickness at the top + mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness); + + // Update the desired size for the container. + // the baseline will be that of the base. + mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; + mBoundingMetrics.descent = + PR_MAX(bmBase.descent, (bmSqr.descent - (bmBase.ascent + psi))); + mBoundingMetrics.width = bmSqr.width + bmBase.width; + mBoundingMetrics.leftBearing = bmSqr.leftBearing; + mBoundingMetrics.rightBearing = bmSqr.width + + PR_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule + + aDesiredSize.ascent = bmBase.ascent + psi + 2*ruleThickness; + aDesiredSize.descent = + PR_MAX(baseSize.descent, (mBoundingMetrics.descent + ruleThickness)); aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; - dx = 0; - dy = 2*onePixel + (bmSqr.ascent - fontAscent); - mSqrChar.SetRect(nsRect(dx, dy, desSize.width, aDesiredSize.height)); - dx = bmSqr.rightBearing; - - // Stretch the overline bar to the appropriate width if it is not big enough. - - contSize = nsStretchMetrics(aDesiredSize); - desSize = nsStretchMetrics(fontDescent, fontAscent, bmBar.rightBearing-bmBar.leftBearing, fontAscent + fontDescent); - nsStretchMetrics oldSize = desSize; - mBarChar.Stretch(aPresContext, renderingContext, mStyleContext, - NS_STRETCH_DIRECTION_HORIZONTAL, contSize, desSize); - - dy = 2*onePixel + (bmBar.ascent - fontAscent); - if (oldSize == desSize) { // hasn't changed size! Char will be painted as a normal char - dx -= bmBar.leftBearing; // adjust so that it coincides with the sqrt char - // XXX need also to check when a single glyph wil be used - } - mBarChar.SetRect(nsRect(dx, dy, desSize.width, 2*onePixel + thickspace)); - - // Update the size of the container - aDesiredSize.width += charWidth; - aDesiredSize.ascent += 2*onePixel + thickspace; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + mReference.x = 0; + mReference.y = aDesiredSize.ascent; ////////////////// // Adjust the origins to leave room for the sqrt char and the overline bar - nsRect rect; - dx = charWidth; - dy = aDesiredSize.ascent - oldAscent; + nsPoint origin; + dx = radicalSize.width; + dy = aDesiredSize.ascent - baseSize.ascent; nsIFrame* childFrame = mFrames.FirstChild(); while (nsnull != childFrame) { if (!IsOnlyWhitespace(childFrame)) { - childFrame->GetRect(rect); - childFrame->MoveTo(aPresContext, dx, rect.y + dy); - dx += rect.width; + childFrame->GetOrigin(origin); + childFrame->MoveTo(aPresContext, origin.x + dx, origin.y + dy); } rv = childFrame->GetNextSibling(&childFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); @@ -218,7 +273,43 @@ nsMathMLmsqrtFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } + aDesiredSize.mBoundingMetrics = mBoundingMetrics; aStatus = NS_FRAME_COMPLETE; return NS_OK; } +// ---------------------- +// the Style System will use these to pass the proper style context to our MathMLChar +NS_IMETHODIMP +nsMathMLmsqrtFrame::GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const +{ + NS_PRECONDITION(aStyleContext, "null OUT ptr"); + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + *aStyleContext = nsnull; + switch (aIndex) { + case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: + mSqrChar.GetStyleContext(aStyleContext); + break; + default: + return NS_ERROR_INVALID_ARG; + } + return NS_OK; +} + +NS_IMETHODIMP +nsMathMLmsqrtFrame::SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext) +{ + if (aIndex < 0) { + return NS_ERROR_INVALID_ARG; + } + switch (aIndex) { + case NS_SQR_CHAR_STYLE_CONTEXT_INDEX: + mSqrChar.SetStyleContext(aStyleContext); + break; + } + return NS_OK; +} diff --git a/layout/mathml/base/src/nsMathMLmsqrtFrame.h b/layout/mathml/base/src/nsMathMLmsqrtFrame.h index ef98ec5cc340..b8172831b131 100644 --- a/layout/mathml/base/src/nsMathMLmsqrtFrame.h +++ b/layout/mathml/base/src/nsMathMLmsqrtFrame.h @@ -19,6 +19,7 @@ * Roger B. Sidje * David J. Fiddes * Vilya Harvey + * Shyjan Mahamud */ #ifndef nsMathMLmsqrtFrame_h___ @@ -58,6 +59,13 @@ class nsMathMLmsqrtFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); + NS_IMETHOD + SetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext* aStyleContext); + NS_IMETHOD + GetAdditionalStyleContext(PRInt32 aIndex, + nsIStyleContext** aStyleContext) const; + NS_IMETHOD Init(nsIPresContext* aPresContext, nsIContent* aContent, @@ -83,7 +91,8 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } - nsMathMLChar mSqrChar, mBarChar; + nsMathMLChar mSqrChar; + nsRect mBarRect; }; #endif /* nsMathMLmsqrtFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmstyleFrame.cpp b/layout/mathml/base/src/nsMathMLmstyleFrame.cpp index 3a5581d3977c..9ce95bb4bfd7 100644 --- a/layout/mathml/base/src/nsMathMLmstyleFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmstyleFrame.cpp @@ -76,6 +76,8 @@ nsMathMLmstyleFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; + mPresentationData.mstyle = this; mInnerScriptLevelIncrement = 0; @@ -120,7 +122,8 @@ nsMathMLmstyleFrame::Init(nsIPresContext* aPresContext, NS_IMETHODIMP nsMathMLmstyleFrame::UpdatePresentationData(PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) + PRBool aDisplayStyle, + PRBool aCompressed) { // mstyle is special... // Since UpdatePresentationData() can be called by a parent frame, the @@ -136,6 +139,10 @@ nsMathMLmstyleFrame::UpdatePresentationData(PRInt32 aScriptLevelIncrement, if (!NS_MATHML_IS_MSTYLE_WITH_EXPLICIT_SCRIPTLEVEL(mPresentationData.flags)) { mPresentationData.scriptLevel += aScriptLevelIncrement; } + if (aCompressed) + mPresentationData.flags |= NS_MATHML_COMPRESSED; + else + mPresentationData.flags &= ~NS_MATHML_COMPRESSED; return NS_OK; } @@ -143,12 +150,14 @@ nsMathMLmstyleFrame::UpdatePresentationData(PRInt32 aScriptLevelIncrement, NS_IMETHODIMP nsMathMLmstyleFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle) + PRBool aDisplayStyle, + PRBool aCompressed) { // mstyle is special... // Since UpdatePresentationDataFromChildAt() can be called by a parent frame, // wee need to ensure that the attributes of mstyle take precedence + PRBool compressed = NS_MATHML_IS_COMPRESSED(mPresentationData.flags); PRBool displayStyle = NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags); if (NS_MATHML_IS_MSTYLE_WITH_DISPLAYSTYLE(mPresentationData.flags)) { aDisplayStyle = displayStyle; @@ -156,10 +165,12 @@ nsMathMLmstyleFrame::UpdatePresentationDataFromChildAt(PRInt32 aIndex, if (NS_MATHML_IS_MSTYLE_WITH_EXPLICIT_SCRIPTLEVEL(mPresentationData.flags)) { aScriptLevelIncrement = 0; } - if (0 == aScriptLevelIncrement && aDisplayStyle == displayStyle) - return NS_OK; - + if (0 == aScriptLevelIncrement && + aDisplayStyle == displayStyle && + aCompressed == compressed) + return NS_OK; // quick return, there is nothing to change + // let the base class worry about the update return nsMathMLContainerFrame::UpdatePresentationDataFromChildAt(aIndex, - aScriptLevelIncrement, aDisplayStyle); + aScriptLevelIncrement, aDisplayStyle, aCompressed); } diff --git a/layout/mathml/base/src/nsMathMLmstyleFrame.h b/layout/mathml/base/src/nsMathMLmstyleFrame.h index 7c6db0fad9e3..f37976410778 100644 --- a/layout/mathml/base/src/nsMathMLmstyleFrame.h +++ b/layout/mathml/base/src/nsMathMLmstyleFrame.h @@ -30,19 +30,6 @@ // -- style change // -#if 0 - -#define NS_MATHML_MSTYLE_SCRIPTLEVEL_EXPLICIT (1) -#define NS_MATHML_MSTYLE_DISPLAYSTYLE (1<<1) - -#define NS_MATHML_MSTYLE_HAS_SCRIPTLEVEL_EXPLICIT(_flags) \ - (NS_MATHML_MSTYLE_SCRIPTLEVEL_EXPLICIT == ((_flags) & NS_MATHML_MSTYLE_SCRIPTLEVEL_EXPLICIT)) - -#define NS_MATHML_MSTYLE_HAS_DISPLAYSTYLE(_flags) \ - (NS_MATHML_MSTYLE_DISPLAYSTYLE == ((_flags) & NS_MATHML_MSTYLE_DISPLAYSTYLE)) - -#endif - class nsMathMLmstyleFrame : public nsMathMLContainerFrame { public: friend nsresult NS_NewMathMLmstyleFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); @@ -56,12 +43,14 @@ public: NS_IMETHOD UpdatePresentationData(PRInt32 aScriptLevel, - PRBool aDisplayStyle); + PRBool aDisplayStyle, + PRBool aCompressed); NS_IMETHOD UpdatePresentationDataFromChildAt(PRInt32 aIndex, PRInt32 aScriptLevelIncrement, - PRBool aDisplayStyle); + PRBool aDisplayStyle, + PRBool aCompressed); NS_IMETHOD SetInitialChildList(nsIPresContext* aPresContext, @@ -70,7 +59,8 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(0, mInnerScriptLevelIncrement, NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)); + UpdatePresentationDataFromChildAt(0, mInnerScriptLevelIncrement, + NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags), PR_FALSE); InsertScriptLevelStyleContext(aPresContext); return rv; } @@ -82,7 +72,6 @@ protected: virtual PRIntn GetSkipSides() const { return 0; } PRInt32 mInnerScriptLevelIncrement; -// PRInt32 mFlags; }; #endif /* nsMathMLmstyleFrame_h___ */ diff --git a/layout/mathml/base/src/nsMathMLmsubFrame.cpp b/layout/mathml/base/src/nsMathMLmsubFrame.cpp index c8b3ea9b5ec2..337465f06a3b 100644 --- a/layout/mathml/base/src/nsMathMLmsubFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmsubFrame.cpp @@ -91,7 +91,7 @@ nsMathMLmsubFrame::Init(nsIPresContext* aPresContext, } #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) - mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +// mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; #endif return rv; } @@ -136,15 +136,18 @@ nsMathMLmsubFrame::Place(nsIPresContext* aPresContext, // parameter v, Rule 18a, App. G, TeXbook minSubScriptShift = bmBase.descent + aSubDrop; } - else { - NS_ASSERTION((count < 2),"nsMathMLmsubFrame : invalid markup"); - } count++; } - rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } +#ifdef NS_DEBUG + if (2 != count) printf("msub: invalid markup"); +#endif + if ((2 != count) || !baseFrame || !subScriptFrame) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } ////////////////// // Place Children @@ -199,7 +202,7 @@ nsMathMLmsubFrame::Place(nsIPresContext* aPresContext, aDesiredSize.width = baseSize.width + mScriptSpace + subScriptSize.width; mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dx, dy; diff --git a/layout/mathml/base/src/nsMathMLmsubFrame.h b/layout/mathml/base/src/nsMathMLmsubFrame.h index 53d7ba15b289..32c1a38fdb91 100644 --- a/layout/mathml/base/src/nsMathMLmsubFrame.h +++ b/layout/mathml/base/src/nsMathMLmsubFrame.h @@ -55,7 +55,7 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(1, 1, PR_FALSE); + UpdatePresentationDataFromChildAt(1, 1, PR_FALSE, PR_FALSE); // switch the style of the subscript InsertScriptLevelStyleContext(aPresContext); // check whether or not this is an embellished operator diff --git a/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp b/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp index 1d59625dfc4f..a47d888ecf9f 100644 --- a/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmsubsupFrame.cpp @@ -100,7 +100,7 @@ nsMathMLmsubsupFrame::Init(nsIPresContext* aPresContext, } #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) - mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +// mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; #endif return rv; } @@ -120,9 +120,9 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, nsHTMLReflowMetrics baseSize (nsnull); nsHTMLReflowMetrics subScriptSize (nsnull); nsHTMLReflowMetrics supScriptSize (nsnull); - nsIFrame* baseFrame; - nsIFrame* subScriptFrame; - nsIFrame* supScriptFrame; + nsIFrame* baseFrame = nsnull; + nsIFrame* subScriptFrame = nsnull; + nsIFrame* supScriptFrame = nsnull; // parameter v, Rule 18a, Appendix G of the TeXbook nscoord minSubScriptShift = 0; // parameter u in Rule 18a, Appendix G of the TeXbook @@ -159,15 +159,18 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, // parameter u, Rule 18a, App. G, TeXbook minSupScriptShift = bmBase.ascent - aSupDrop; } - else { - NS_ASSERTION((count < 2),"nsMathMLmsubFrame : invalid markup"); - } count++; } - rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } +#ifdef NS_DEBUG + if (3 != count) printf("msubsup: invalid markup"); +#endif + if ((3 != count) || !baseFrame || !subScriptFrame || !supScriptFrame) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } ////////////////// // Place Children @@ -184,18 +187,21 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, // 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); - const nsStyleFont* aFont; - baseFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)aFont); + const nsStyleFont* font; + baseFrame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)font); + aRenderingContext.SetFont(font->mFont); + nsCOMPtr fm; + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); - aPresContext->GetMetricsFor (aFont->mFont, getter_AddRefs(fm)); + // get x-height (an ex) + nscoord xHeight; fm->GetXHeight (xHeight); + + nscoord aRuleSize; + GetRuleThickness (aRenderingContext, fm, aRuleSize); // Get aSubScriptShift{1,2} default from font GetSubScriptShifts (fm, aSubScriptShift1, aSubScriptShift2); @@ -206,7 +212,7 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, aSubScriptShift1 = PR_MAX(aSubScriptShift1, mSubScriptShift); aSubScriptShift2 = NSToCoordRound(aFactor * aSubScriptShift1); } - + // get a tentative value for subscriptshift // Rule 18d, App. G, TeXbook nscoord aSubScriptShift = @@ -271,10 +277,6 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, // Rule 18e, App. G, TeXbook ////////////////////////////////////////////////// - nscoord aRuleSize; - // XXX need to do update this ... - GetRuleThickness (fm, aRuleSize); -// aRuleSize /= 2; nscoord gap = (aSupScriptShift - bmSupScript.descent) - (bmSubScript.ascent - aSubScriptShift); @@ -310,7 +312,7 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, PR_MAX((bmBase.supItalicCorrection + bmSupScript.width), (bmBase.subItalicCorrection + bmSubScript.width)); - // to be simplfied later + // to be simplified later nscoord dyBase = mBoundingMetrics.ascent - bmBase.ascent; nscoord dySubScript = mBoundingMetrics.ascent - bmSubScript.ascent + aSubScriptShift; nscoord dySupScript = mBoundingMetrics.ascent - bmSupScript.ascent - aSupScriptShift; @@ -327,7 +329,7 @@ nsMathMLmsubsupFrame::Place(nsIPresContext* aPresContext, aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; mBoundingMetrics.leftBearing = bmBase.leftBearing; mBoundingMetrics.rightBearing = bmBase.width + mScriptSpace + PR_MAX((bmBase.supItalicCorrection + bmSupScript.rightBearing), diff --git a/layout/mathml/base/src/nsMathMLmsubsupFrame.h b/layout/mathml/base/src/nsMathMLmsubsupFrame.h index 696cb7a31ebb..cc2fef995fdd 100644 --- a/layout/mathml/base/src/nsMathMLmsubsupFrame.h +++ b/layout/mathml/base/src/nsMathMLmsubsupFrame.h @@ -55,7 +55,7 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(1, 1, PR_FALSE); + UpdatePresentationDataFromChildAt(1, 1, PR_FALSE, PR_FALSE); // switch the style of the subscript and superscript InsertScriptLevelStyleContext(aPresContext); // check whether or not this is an embellished operator diff --git a/layout/mathml/base/src/nsMathMLmsupFrame.cpp b/layout/mathml/base/src/nsMathMLmsupFrame.cpp index 1e18c65ad70e..1798e09de99d 100644 --- a/layout/mathml/base/src/nsMathMLmsupFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmsupFrame.cpp @@ -90,7 +90,7 @@ nsMathMLmsupFrame::Init(nsIPresContext* aPresContext, } #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) - mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +// mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; #endif return rv; } @@ -110,8 +110,8 @@ nsMathMLmsupFrame::Place(nsIPresContext* aPresContext, nsRect aRect; nsHTMLReflowMetrics baseSize (nsnull); nsHTMLReflowMetrics supScriptSize (nsnull); - nsIFrame* baseFrame; - nsIFrame* supScriptFrame; + nsIFrame* baseFrame = nsnull; + nsIFrame* supScriptFrame = nsnull; // parameter u in Rule 18a, Appendix G of the TeXbook nscoord minSupScriptShift = 0; @@ -136,14 +136,18 @@ nsMathMLmsupFrame::Place(nsIPresContext* aPresContext, // parameter u, Rule 18a, App. G, TeXbook minSupScriptShift = bmBase.ascent - aSupDrop; } - else { - NS_ASSERTION((count < 2),"nsMathMLmsupFrame : invalid markup"); - } count++; } rv = aChildFrame->GetNextSibling(&aChildFrame); NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); } +#ifdef NS_DEBUG + if (2 != count) printf("msup: invalid markup"); +#endif + if ((2 != count) || !baseFrame || !supScriptFrame) { + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); + } ////////////////// // Place Children @@ -226,7 +230,7 @@ nsMathMLmsupFrame::Place(nsIPresContext* aPresContext, aDesiredSize.width = baseSize.width + mScriptSpace + supScriptSize.width; mReference.x = 0; - mReference.y = aDesiredSize.ascent - mBoundingMetrics.ascent; + mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { nscoord dx, dy; diff --git a/layout/mathml/base/src/nsMathMLmsupFrame.h b/layout/mathml/base/src/nsMathMLmsupFrame.h index 9e2ff5671dce..c9170ccd08dc 100644 --- a/layout/mathml/base/src/nsMathMLmsupFrame.h +++ b/layout/mathml/base/src/nsMathMLmsupFrame.h @@ -55,7 +55,7 @@ public: { nsresult rv; rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); - UpdatePresentationDataFromChildAt(1, 1, PR_FALSE); + UpdatePresentationDataFromChildAt(1, 1, PR_FALSE, PR_FALSE); // switch the style of the superscript InsertScriptLevelStyleContext(aPresContext); // check whether or not this is an embellished operator diff --git a/layout/mathml/base/src/nsMathMLmtdFrame.cpp b/layout/mathml/base/src/nsMathMLmtdFrame.cpp index eacfd1f2b096..b28fbf1bbe25 100644 --- a/layout/mathml/base/src/nsMathMLmtdFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmtdFrame.cpp @@ -47,6 +47,8 @@ nsresult NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) { +// return NS_NewMathMLmrowFrame(aPresShell, aNewFrame); + NS_PRECONDITION(aNewFrame, "null OUT ptr"); if (nsnull == aNewFrame) { return NS_ERROR_NULL_POINTER; @@ -69,20 +71,201 @@ nsMathMLmtdFrame::~nsMathMLmtdFrame() { } +#if 0 +// wrap our children in an anonymous inferred mrow +NS_IMETHODIMP +nsMathMLmtdFrame::SetInitialChildList(nsIPresContext* aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + // First, let the base class do its work + nsresult rv = nsAreaFrame::SetInitialChildList(aPresContext, aListName, aChildList); + + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + + nsIFrame* newFrame = nsnull; + NS_NewMathMLmrowFrame(shell, &newFrame); + NS_ASSERTION(newFrame, "Failed to create new frame"); + if (newFrame) { + nsCOMPtr newStyleContext; + aPresContext->ResolvePseudoStyleContextFor(mContent, nsHTMLAtoms::mozAnonymousBlock, + mStyleContext, PR_FALSE, + getter_AddRefs(newStyleContext)); + rv = newFrame->Init(aPresContext, mContent, this, newStyleContext, nsnull); + if (NS_FAILED(rv)) { + newFrame->Destroy(aPresContext); + return rv; + } + // our children become children of the new frame + nsIFrame* firstChild = mFrames.FirstChild(); + 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); + } + + return rv; +} +#endif + + NS_IMETHODIMP nsMathMLmtdFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) - { - nsresult rv = NS_OK; - // Let the base class do the reflow - rv = nsAreaFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + + printf("Ending cell body with aDesiredSize: asc:%d desc:%d\n", + aDesiredSize.ascent, aDesiredSize.descent); + +#if 0 + // make sure that we return the desired size of our inner mrow frame + nsIFrame* childFrame = mFrames.FirstChild(); + nsIMathMLFrame* aMathMLFrame = nsnull; + rv = childFrame->QueryInterface(nsIMathMLFrame::GetIID(), (void**)&aMathMLFrame); + NS_ASSERTION(NS_SUCCEEDED(rv) && nsnull != aMathMLFrame, "Mystery"); + if (NS_SUCCEEDED(rv) && nsnull != aMathMLFrame) { + // get our ascent and descent + nsPoint ref; + aMathMLFrame->GetReference(ref); + nsBoundingMetrics bm; + aMathMLFrame->GetBoundingMetrics(bm); + +// aDesiredSize.ascent = ref.y + bm.ascent; +// aDesiredSize.descent = aDesiredSize.height - ref.y; + + nsRect rect; + childFrame->GetRect(rect); + + nsFrame::ListTag(stdout, childFrame); + printf("\nEnding mtd with: rect(%d,%d,%d,%d) ref(%d,%d) bm:asc=%d,desc=%d, asc:%d desc:%d\n", + rect.x,rect.y,rect.width,rect.height, ref.x, ref.y, bm.ascent,bm.descent, aDesiredSize.ascent,aDesiredSize.descent); + } +#endif // more about and later // ... - return rv; } + +NS_IMETHODIMP +nsMathMLmtdFrame::DidReflow(nsIPresContext* aPresContext, + nsDidReflowStatus aStatus) +{ + nsRect rect; + GetRect(rect); + nsFrame::ListTag(stdout, this); + printf("\nend mtd with: rect(%d,%d,%d,%d)\n", + rect.x,rect.y,rect.width,rect.height); + + #if 0 + nsIFrame* childFrame = mFrames.FirstChild(); + childFrame->GetRect(rect); + nsFrame::ListTag(stdout, this); + printf("\nend child mtd with: rect(%d,%d,%d,%d)\n", + rect.x,rect.y,rect.width,rect.height); +#endif + +// NS_ASSERTION(0, "Break in mtd::DidReflow"); + + return nsHTMLContainerFrame::DidReflow(aPresContext, aStatus); +} + +#if 0 +NS_IMETHODIMP +nsMathMLmtdFrame:Reflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aReflowStatus) +{ + nsresult rv = NS_OK; + + nsIFrame* kid = mFrames.FirstChild(); + nsIFrame* nextRCFrame = nsnull; + if (aReflowState.reason == eReflowReason_Incremental) { + nsIFrame* target; + aReflowState.reflowCommand->GetTarget(target); + if (this != target) { + aReflowState.reflowCommand->GetNext(nextRCFrame); + } + } + + // Setup reflow state for our child + nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); + const nsMargin& bp = aReflowState.mComputedBorderPadding; + nscoord lr = bp.left + bp.right; + nscoord tb = bp.top + bp.bottom; + if (NS_UNCONSTRAINEDSIZE != availSize.width) { + availSize.width -= lr; + } + if (NS_UNCONSTRAINEDSIZE != availSize.height) { + availSize.height -= tb; + } + + // Reflow the child + if (!aReflowState.mLineLayout) { +printf("No line layout for mtd ....\n"); + // When there is no lineLayout provided, we provide our own. The + // only time that the first-letter-frame is not reflowing in a + // line context is when its floating. + nsHTMLReflowState rs(aPresContext, aReflowState, kid, availSize); + nsLineLayout ll(aPresContext, nsnull, &aReflowState, + nsnull != aMetrics.maxElementSize); +// ll.BeginLineReflow(0, 0, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, +// PR_FALSE, PR_TRUE); + + ll.BeginLineReflow(0, 0, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, + PR_FALSE, PR_FALSE); + +// aLineLayout.BeginLineReflow(x, aState.mY, +// availWidth, availHeight, +// impactedByFloaters, +// PR_FALSE /*XXX isTopOfPage*/); + + + rs.mLineLayout = ≪ +// ll.SetFirstLetterStyleOK(PR_TRUE); + + kid->WillReflow(aPresContext); + kid->Reflow(aPresContext, aMetrics, rs, aReflowStatus); + + ll.EndLineReflow(); + } + else { +printf("Line layout for mtd is %p....\n", aReflowState.mLineLayout); + + // Pretend we are a span and reflow the child frame + nsLineLayout* ll = aReflowState.mLineLayout; + PRBool pushedFrame; + + ll->BeginSpan(this, &aReflowState, bp.left, availSize.width); + ll->ReflowFrame(kid, &nextRCFrame, aReflowStatus, &aMetrics, pushedFrame); + nsSize size; + ll->EndSpan(this, size, aMetrics.maxElementSize); + } + + // Place and size the child and update the output metrics + kid->MoveTo(aPresContext, bp.left, bp.top); + kid->SizeTo(aPresContext, aMetrics.width, aMetrics.height); + kid->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + aMetrics.width += lr; + aMetrics.height += tb; + aMetrics.ascent += bp.top; + aMetrics.descent += bp.bottom; + if (aMetrics.maxElementSize) { + aMetrics.maxElementSize->width += lr; + aMetrics.maxElementSize->height += tb; + } + + return rv; +} +#endif diff --git a/layout/mathml/base/src/nsMathMLmtdFrame.h b/layout/mathml/base/src/nsMathMLmtdFrame.h index e5116339ecf6..28df06df6773 100644 --- a/layout/mathml/base/src/nsMathMLmtdFrame.h +++ b/layout/mathml/base/src/nsMathMLmtdFrame.h @@ -31,15 +31,27 @@ // class nsMathMLmtdFrame : public nsAreaFrame { +//class nsMathMLmtdFrame : public nsBlockFrame { public: friend nsresult NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); +#if 0 + NS_IMETHOD + SetInitialChildList(nsIPresContext* aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList); +#endif + NS_IMETHOD Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); + NS_IMETHOD + DidReflow(nsIPresContext* aPresContext, + nsDidReflowStatus aStatus); + protected: nsMathMLmtdFrame(); virtual ~nsMathMLmtdFrame(); diff --git a/layout/mathml/base/src/nsMathMLmunderFrame.cpp b/layout/mathml/base/src/nsMathMLmunderFrame.cpp index 6a3d51eb242b..45e9e10fe5b1 100644 --- a/layout/mathml/base/src/nsMathMLmunderFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmunderFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud * Pierre Phaneuf */ @@ -76,8 +77,11 @@ nsMathMLmunderFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; +#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) + mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS; +#endif return rv; } @@ -190,8 +194,8 @@ XXX The winner is the outermost setting in conflicting settings like these: if (underscriptMathMLFrame) { incrementScriptLevel = NS_MATHML_IS_ACCENTUNDER(mPresentationData.flags)? 0 : 1; - underscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE); - underscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE); + underscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE, PR_FALSE); + underscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE, PR_FALSE); } // switch the style of the underscript @@ -200,37 +204,6 @@ XXX The winner is the outermost setting in conflicting settings like these: return rv; } -NS_IMETHODIMP -nsMathMLmunderFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - - nsresult rv = NS_OK; - - ///////////// - // Reflow children - - ReflowChildren(1, aPresContext, aDesiredSize, aReflowState, aStatus); - - ///////////// - // Ask stretchy children to stretch themselves - - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - nsStretchMetrics containerSize(aDesiredSize); - nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; - - StretchChildren(aPresContext, renderingContext, stretchDir, containerSize); - - ///////////// - // Place children now by re-adjusting the origins to align the baselines - FinalizeReflow(1, aPresContext, renderingContext, aDesiredSize); - - aStatus = NS_FRAME_COMPLETE; - return NS_OK; -} - /* The REC says: * If the base is an operator with movablelimits="true" (or @@ -256,61 +229,120 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nscoord count = 0; - nsRect rect[2]; - nsIFrame* child[2]; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsBoundingMetrics bmBase, bmUnder; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics underSize (nsnull); + nsIFrame* baseFrame = nsnull; + nsIFrame* underFrame = nsnull; + nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 2 > count) { - childFrame->GetRect(rect[count]); - child[count] = childFrame; + if (!IsOnlyWhitespace(childFrame)) { + if (0 == count) { + // base + baseFrame = childFrame; + GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); + } + else if (1 == count) { + // under + underFrame = childFrame; + GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder); + } count++; } - childFrame->GetNextSibling(&childFrame); + rv = childFrame->GetNextSibling(&childFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } + if ((2 != count) || !baseFrame || !underFrame) { +#ifdef NS_DEBUG + printf("munder: invalid markup"); +#endif + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); } - aDesiredSize.descent = rect[0].x; - aDesiredSize.ascent = rect[0].y; - - aDesiredSize.descent += rect[1].height; - aDesiredSize.width = PR_MAX(rect[0].width, rect[1].width); - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + //////////////////// + // Place Children - rect[0].x = (aDesiredSize.width - rect[0].width) / 2; // center w.r.t largest width - rect[1].x = (aDesiredSize.width - rect[1].width) / 2; - rect[0].y = 0; - rect[1].y = aDesiredSize.height - rect[1].height; - -//ignore the leading (line spacing) that is attached to the text - nscoord leading; + const nsStyleFont* font = + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aRenderingContext.SetFont(font->mFont); nsCOMPtr fm; - const nsStyleFont* aFont = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - aPresContext->GetMetricsFor(aFont->mFont, getter_AddRefs(fm)); - fm->GetLeading(leading); + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); + + nscoord xHeight = 0; + fm->GetXHeight (xHeight); + + nscoord ruleThickness; + GetRuleThickness (aRenderingContext, fm, ruleThickness); + + // there are 2 different types of placement depending on + // whether we want an accented under or not + + nscoord italicCorrection = 0; + nscoord delta1 = 0; // gap between base and underscript + nscoord delta2 = 0; // extra space beneath underscript + if (!NS_MATHML_IS_ACCENTUNDER(mPresentationData.flags)) { + // Rule 13a, App. G, TeXbook +// GetItalicCorrectionFromChild (baseFrame, italicCorrection); + nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; + GetBigOpSpacings (fm, + dummy, bigOpSpacing2, + dummy, bigOpSpacing4, + bigOpSpacing5); + delta1 = PR_MAX(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent)); + delta2 = bigOpSpacing5; + } + else { + // No corresponding rule in TeXbook - we are on our own here + // XXX tune the gap delta between base and underscript + + // Should we use Rule 10 like \underline does? + delta1 = ruleThickness; + delta2 = ruleThickness; + } + // empty under? + if (0 == (bmUnder.ascent + bmUnder.descent)) delta1 = 0; + + mBoundingMetrics.ascent = bmBase.ascent; + mBoundingMetrics.descent = + bmBase.descent + delta1 + bmUnder.ascent + bmUnder.descent; + mBoundingMetrics.width = + PR_MAX(bmBase.width/2,(bmUnder.width + italicCorrection/2)/2) + + PR_MAX(bmBase.width/2,(bmUnder.width - italicCorrection/2)/2); + + nscoord dxBase = (mBoundingMetrics.width - bmBase.width) / 2; + nscoord dxUnder = (mBoundingMetrics.width - (bmUnder.width + italicCorrection/2)) / 2; + + aDesiredSize.ascent = baseSize.ascent; + aDesiredSize.descent = mBoundingMetrics.descent + delta2; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; + + mReference.x = 0; + mReference.y = aDesiredSize.ascent; + + mBoundingMetrics.leftBearing = + PR_MIN(dxBase + bmBase.leftBearing, dxUnder + bmUnder.leftBearing); + mBoundingMetrics.rightBearing = + PR_MAX(dxBase + bmBase.rightBearing, dxUnder + bmUnder.rightBearing); - aDesiredSize.height -= leading; - aDesiredSize.descent -= leading; - rect[1].y -= leading; -// 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 dy = 0; + // place base + dy = 0; + FinishReflowChild(baseFrame, aPresContext, baseSize, dxBase, dy, 0); + // place underscript + dy = aDesiredSize.ascent + mBoundingMetrics.descent - bmUnder.descent - underSize.ascent; + FinishReflowChild(underFrame, aPresContext, underSize, dxUnder, dy, 0); } - // XXX Fix me! - mBoundingMetrics.ascent = aDesiredSize.ascent; - mBoundingMetrics.descent = aDesiredSize.descent; - mBoundingMetrics.width = aDesiredSize.width; return NS_OK; } + diff --git a/layout/mathml/base/src/nsMathMLmunderFrame.h b/layout/mathml/base/src/nsMathMLmunderFrame.h index 3733102e2853..2420724ac17f 100644 --- a/layout/mathml/base/src/nsMathMLmunderFrame.h +++ b/layout/mathml/base/src/nsMathMLmunderFrame.h @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmunderFrame_h___ @@ -41,12 +42,6 @@ public: nsIStyleContext* aContext, nsIFrame* aPrevInFlow); - NS_IMETHOD - Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); - NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp b/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp index 55773032ef33..5939ce9a427a 100644 --- a/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmunderoverFrame.cpp @@ -18,6 +18,7 @@ * Contributor(s): * Roger B. Sidje * David J. Fiddes + * Shyjan Mahamud * Pierre Phaneuf */ @@ -76,7 +77,7 @@ nsMathMLmunderoverFrame::Init(nsIPresContext* aPresContext, { nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); - mEmbellishData.flags = NS_MATHML_STRETCH_ALL_CHILDREN; + mEmbellishData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; return rv; } @@ -137,7 +138,7 @@ nsMathMLmunderoverFrame::SetInitialChildList(nsIPresContext* aPresContext, baseFrame->GetContent(getter_AddRefs(baseContent)); if (NS_CONTENT_ATTR_HAS_VALUE == baseContent->GetAttribute(kNameSpaceID_None, nsMathMLAtoms::movablelimits_, value)) { - if (value == "true") { + if (value.Equals("true")) { mPresentationData.flags |= NS_MATHML_MOVABLELIMITS; } } @@ -167,8 +168,8 @@ nsMathMLmunderoverFrame::SetInitialChildList(nsIPresContext* aPresContext, if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None, nsMathMLAtoms::accentunder_, value)) { - if (value == "true") embellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; - else if (value == "false") embellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; + if (value.Equals("true")) embellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; + else if (value.Equals("false")) embellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; aMathMLFrame->SetEmbellishData(embellishData); } @@ -195,8 +196,8 @@ nsMathMLmunderoverFrame::SetInitialChildList(nsIPresContext* aPresContext, if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None, nsMathMLAtoms::accent_, value)) { - if (value == "true") embellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; - else if (value == "false") embellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; + if (value.Equals("true")) embellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; + else if (value.Equals("false")) embellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; aMathMLFrame->SetEmbellishData(embellishData); } @@ -221,15 +222,15 @@ nsMathMLmunderoverFrame::SetInitialChildList(nsIPresContext* aPresContext, if (underscriptMathMLFrame) { incrementScriptLevel = NS_MATHML_IS_ACCENTUNDER(mPresentationData.flags)? 0 : 1; - underscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE); - underscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE); + underscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE, PR_FALSE); + underscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE, PR_FALSE); } if (overscriptMathMLFrame) { incrementScriptLevel = NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)? 0 : 1; - overscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE); - overscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE); + overscriptMathMLFrame->UpdatePresentationData(incrementScriptLevel, PR_FALSE, PR_FALSE); + overscriptMathMLFrame->UpdatePresentationDataFromChildAt(0, incrementScriptLevel, PR_FALSE, PR_FALSE); } // switch the style of the underscript and the overscript @@ -238,37 +239,6 @@ nsMathMLmunderoverFrame::SetInitialChildList(nsIPresContext* aPresContext, return rv; } -NS_IMETHODIMP -nsMathMLmunderoverFrame::Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - - nsresult rv = NS_OK; - - ///////////// - // Reflow children - - ReflowChildren(1, aPresContext, aDesiredSize, aReflowState, aStatus); - - ///////////// - // Ask stretchy children to stretch themselves - - nsIRenderingContext& renderingContext = *aReflowState.rendContext; - nsStretchMetrics containerSize(aDesiredSize); - nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_HORIZONTAL; - - StretchChildren(aPresContext, renderingContext, stretchDir, containerSize); - - ///////////// - // Place children now by re-adjusting the origins to align the baselines - FinalizeReflow(1, aPresContext, renderingContext, aDesiredSize); - - aStatus = NS_FRAME_COMPLETE; - return NS_OK; -} - /* The REC says: * If the base is an operator with movablelimits="true" (or an embellished @@ -294,65 +264,174 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { - nscoord count = 0; - nsRect rect[3]; - nsIFrame* child[3]; - aDesiredSize.width = 0; + nsresult rv = NS_OK; + + //////////////////////////////////// + // Get the children's desired sizes + + PRInt32 count = 0; + nsBoundingMetrics bmBase, bmUnder, bmOver; + nsHTMLReflowMetrics baseSize (nsnull); + nsHTMLReflowMetrics underSize (nsnull); + nsHTMLReflowMetrics overSize (nsnull); + nsIFrame* baseFrame = nsnull; + nsIFrame* overFrame = nsnull; + nsIFrame* underFrame = nsnull; + nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { - if (!IsOnlyWhitespace(childFrame) && 3 > count) { - child[count] = childFrame; - childFrame->GetRect(rect[count]); - if (aDesiredSize.width < rect[count].width) aDesiredSize.width = rect[count].width; + if (!IsOnlyWhitespace(childFrame)) { + if (0 == count) { + // base + baseFrame = childFrame; + GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); + } + else if (1 == count) { + // under + underFrame = childFrame; + GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder); + } + else if (2 == count) { + // over + overFrame = childFrame; + GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver); + } count++; } - childFrame->GetNextSibling(&childFrame); + rv = childFrame->GetNextSibling(&childFrame); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next child"); + } + if ((3 != count) || !baseFrame || !underFrame || !overFrame) { +#ifdef NS_DEBUG + printf("munderover: invalid markup\n"); +#endif + // report an error, encourage people to get their markups in order + return ReflowError(aPresContext, aRenderingContext, aDesiredSize); } - aDesiredSize.descent = rect[0].x; - aDesiredSize.ascent = rect[0].y; - - aDesiredSize.ascent += rect[2].height; - aDesiredSize.descent += rect[1].height; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - rect[0].x = (aDesiredSize.width - rect[0].width) / 2; // center w.r.t largest width - rect[1].x = (aDesiredSize.width - rect[1].width) / 2; - rect[2].x = (aDesiredSize.width - rect[2].width) / 2; - rect[0].y = rect[2].height; - rect[1].y = aDesiredSize.height - rect[1].height; - rect[2].y = 0; -//ignore the leading (line spacing) that is attached to the text - nsStyleFont font; - mStyleContext->GetStyle(eStyleStruct_Font, font); + //////////////////// + // Place Children + + const nsStyleFont* font = + (const nsStyleFont*) mStyleContext->GetStyleData (eStyleStruct_Font); + aRenderingContext.SetFont(font->mFont); nsCOMPtr fm; - aPresContext->GetMetricsFor(font.mFont, getter_AddRefs(fm)); - nscoord leading; - fm->GetLeading(leading); + aRenderingContext.GetFontMetrics(*getter_AddRefs(fm)); - aDesiredSize.height -= 2*leading; - aDesiredSize.ascent -= leading; - aDesiredSize.descent -= leading; - rect[0].y -= leading; - rect[1].y -= 2*leading; -// + nscoord xHeight = 0; + fm->GetXHeight (xHeight); + + nscoord ruleThickness; + GetRuleThickness (aRenderingContext, fm, ruleThickness); + + // there are 2 different types of placement depending on + // whether we want an accented under or not + + nscoord italicCorrection = 0; + nscoord underDelta1 = 0; // gap between base and underscript + nscoord underDelta2 = 0; // extra space beneath underscript + + if (!NS_MATHML_IS_ACCENTUNDER(mPresentationData.flags)) { + // Rule 13a, App. G, TeXbook +// GetItalicCorrectionFromChild (baseFrame, italicCorrection); + nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; + GetBigOpSpacings (fm, + dummy, bigOpSpacing2, + dummy, bigOpSpacing4, + bigOpSpacing5); + underDelta1 = PR_MAX(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent)); + underDelta2 = bigOpSpacing5; + } + else { + // No corresponding rule in TeXbook - we are on our own here + // XXX tune the gap delta between base and underscript + + // Should we use Rule 10 like \underline does? + underDelta1 = ruleThickness; + underDelta2 = ruleThickness; + } + // empty under? + if (0 == (bmUnder.ascent + bmUnder.descent)) underDelta1 = 0; + + nscoord aCorrection = 0; + nscoord overDelta1 = 0; // gap between base and overscript + nscoord overDelta2 = 0; // extra space above overscript + + if (!NS_MATHML_IS_ACCENTOVER(mPresentationData.flags)) { + // Rule 13a, App. G, TeXbook +// GetItalicCorrectionFromChild (baseFrame, aCorrection); + nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; + GetBigOpSpacings (fm, + bigOpSpacing1, dummy, + bigOpSpacing3, dummy, + bigOpSpacing5); + overDelta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent)); + overDelta2 = bigOpSpacing5; + + // XXX This is not a TeX rule... + // delta1 (as computed abvove) can become really big when bmOver.descent is + // negative, e.g., if the content is &OverBar. In such case, we use the height + if (bmOver.descent < 0) + overDelta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent))); + } + else { + // Rule 13, App. G, TeXbook + GetSkewCorrectionFromChild (aPresContext, baseFrame, aCorrection); +#if 0 + // XXX tune these + overDelta1 = PR_MIN(bmOver.ascent,xHeight); + overDelta2 = 0; +#endif + overDelta1 = ruleThickness; + overDelta2 = ruleThickness; + } + // empty over? + if (0 == (bmOver.ascent + bmOver.descent)) overDelta1 = 0; + + mBoundingMetrics.ascent = + bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent; + mBoundingMetrics.descent = + bmBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent; + mBoundingMetrics.width = + PR_MAX(bmBase.width/2,PR_MAX((bmUnder.width + italicCorrection/2)/2,(bmOver.width - aCorrection/2)/2)) + + PR_MAX(bmBase.width/2,PR_MAX((bmUnder.width - italicCorrection/2)/2,(bmOver.width + aCorrection/2)/2)); + + nscoord dxBase = (mBoundingMetrics.width - bmBase.width) / 2; + nscoord dxOver = (mBoundingMetrics.width - (bmOver.width - aCorrection/2)) / 2; + nscoord dxUnder = (mBoundingMetrics.width - (bmUnder.width + italicCorrection/2)) / 2; + + aDesiredSize.ascent = + mBoundingMetrics.ascent + overDelta2; + aDesiredSize.descent = + mBoundingMetrics.descent + underDelta2; + aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; + aDesiredSize.width = mBoundingMetrics.width; + + mReference.x = 0; + mReference.y = aDesiredSize.ascent; + + mBoundingMetrics.leftBearing = + PR_MIN(dxBase + bmBase.leftBearing, dxUnder + bmUnder.leftBearing); + mBoundingMetrics.rightBearing = + PR_MAX(dxBase + bmBase.rightBearing, dxUnder + bmUnder.rightBearing); + mBoundingMetrics.leftBearing = + PR_MIN(mBoundingMetrics.leftBearing, dxOver + bmOver.leftBearing); + mBoundingMetrics.rightBearing = + PR_MAX(mBoundingMetrics.rightBearing, dxOver + bmOver.rightBearing); + + aDesiredSize.mBoundingMetrics = mBoundingMetrics; 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; i * David J. Fiddes + * Shyjan Mahamud */ #ifndef nsMathMLmunderoverFrame_h___ @@ -41,12 +42,6 @@ public: nsIStyleContext* aContext, nsIFrame* aPrevInFlow); - NS_IMETHOD - Reflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); - NS_IMETHOD Place(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext,