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