Revamp of the architecture for stretchy symbols so that nsMathMLChar only deals with the atomic stretchy task.

This commit is contained in:
rbs%maths.uq.edu.au 1999-10-12 02:12:36 +00:00
Родитель 8241422540
Коммит 6ba1cb69a5
4 изменённых файлов: 280 добавлений и 249 удалений

Просмотреть файл

@ -49,37 +49,21 @@
NS_IMETHODIMP
nsMathMLChar::Stretch(nsIPresContext& aPresContext,
nsIStyleContext* aStyleContext,
nsStretchDirection aStretchDirection,
nsCharMetrics& aContainerSize,
nsCharMetrics& aDesiredStretchSize)
{
// get the value of 'em';
const nsStyleFont* aFont =
(const nsStyleFont*)aStyleContext->GetStyleData(eStyleStruct_Font);
nscoord em = NSToCoordRound(float(aFont->mFont.size));
mOffset.x = nscoord(mLeftSpace * em);
mOffset.y = 0;
// do the stretching
if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
if (mDirection == NS_STRETCH_DIRECTION_VERTICAL) {
mOffset.y = aContainerSize.ascent - aDesiredStretchSize.ascent;
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;
}
else if (mDirection == NS_STRETCH_DIRECTION_HORIZONTAL) {
else if (aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL) {
// horizontal stretching... for an accent
aDesiredStretchSize.width = aContainerSize.width;
}
}
// adjust the spacing
aDesiredStretchSize.width += nscoord((mLeftSpace+mRightSpace)*em);
return NS_OK;
}
@ -88,7 +72,7 @@ NS_IMETHODIMP
nsMathMLChar::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
nsIStyleContext* aStyleContext,
const nsRect& aRect)
const nsPoint& aOffset)
{
nsresult rv = NS_OK;
const nsStyleColor* color =
@ -102,13 +86,7 @@ nsMathMLChar::Paint(nsIPresContext& aPresContext,
// Display the char
const PRUnichar* aString = mData.GetUnicode();
PRUint32 aLength = mLength;
aRenderingContext.DrawString(aString, aLength, mOffset.x, mOffset.y);
// DEBUG
// Draw a border around the char
//aRenderingContext.SetColor(NS_RGB(255,0,0));
//aRenderingContext.DrawRect(aRect);
aRenderingContext.DrawString(aString, PRUint32(mData.Length()), aOffset.x, aOffset.y);
return rv;
}

Просмотреть файл

@ -24,48 +24,82 @@
#include "nsMathMLOperators.h"
typedef PRUint32 nsStretchDirection;
#define NS_STRETCH_DIRECTION_HORIZONTAL 0
#define NS_STRETCH_DIRECTION_VERTICAL 1
// Structure used for a char's size and alignment information.
struct nsCharMetrics {
// nscoord leading;
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(const nsCharMetrics& aCharMetrics) {
width = aCharMetrics.width;
height = aCharMetrics.height;
ascent = aCharMetrics.ascent;
descent = aCharMetrics.descent;
}
nsCharMetrics(const nsReflowMetrics& aReflowMetrics) {
width = aReflowMetrics.width;
height = aReflowMetrics.height;
ascent = aReflowMetrics.ascent;
descent = aReflowMetrics.descent;
}
void
operator=(const nsCharMetrics& aCharMetrics) {
width = aCharMetrics.width;
height = aCharMetrics.height;
ascent = aCharMetrics.ascent;
descent = aCharMetrics.descent;
}
PRBool
operator==(const nsCharMetrics& aCharMetrics) {
return (width == aCharMetrics.width &&
height == aCharMetrics.height &&
ascent == aCharMetrics.ascent &&
descent == aCharMetrics.descent);
}
};
// class used to handle stretchy symbols (accent and boundary symbols)
class nsMathMLChar
{
public:
NS_IMETHOD Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
nsIStyleContext* aStyleContext,
const nsRect& aRect);
const nsPoint& aOffset);
// 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, including padding that we want.
// 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);
void Init(nsIFrame* aFrame,
const PRInt32 aLength,
const nsString& aData,
const nsOperatorFlags aFlags,
const float aLeftSpace,
const float aRightSpace,
const nsStretchDirection aDirection)
void SetData(nsString& aData)
{
mFrame = aFrame;
mLength = aLength;
mData = aData;
mFlags = aFlags;
mLeftSpace = aLeftSpace;
mRightSpace = aRightSpace;
mDirection = aDirection;
}
void SetLength(const PRInt32 aLength)
{
mLength = aLength;
}
PRInt32 GetLength()
{
return mLength;
void GetData(nsString& aData) {
aData = mData;
}
// constructor and destructor
@ -78,14 +112,7 @@ public:
}
protected:
PRInt32 mLength;
nsString mData;
nsOperatorFlags mFlags;
float mLeftSpace;
float mRightSpace;
nsStretchDirection mDirection;
nsPoint mOffset;
nsIFrame* mFrame; // up-pointer to the frame that contains us.
};
#endif /* nsMathMLChar_h___ */

Просмотреть файл

@ -38,10 +38,6 @@
#include "nsIDOMText.h"
#include "nsMathMLAtoms.h"
#include "nsMathMLParts.h"
#include "nsMathMLChar.h"
#include "nsMathMLOperators.h"
#include "nsMathMLmoFrame.h"
//
@ -111,30 +107,6 @@ nsMathMLmoFrame::~nsMathMLmoFrame()
{
}
NS_IMETHODIMP
nsMathMLmoFrame::Init(nsIPresContext& aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = NS_OK;
rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
if (NS_FAILED(rv)) {
return rv;
}
// candidly assume we are an operator until proven false -- see Stretch()
mOperator = PR_TRUE;
// record that the MathChar doesn't know anything yet
mMathMLChar.SetLength(-1);
// mMathMLChar.Init(this, -1, 0, 0, 0.0f, 0.0f, 0);
return rv;
}
NS_IMETHODIMP
nsMathMLmoFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
@ -143,18 +115,14 @@ nsMathMLmoFrame::Paint(nsIPresContext& aPresContext,
{
nsresult rv = NS_OK;
if (NS_FRAME_PAINT_LAYER_FOREGROUND != aWhichLayer)
return rv;
if (mOperator && 0 < mMathMLChar.GetLength()) {
//printf("Doing the painting with mMathMLChar\n");
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer &&
NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) {
rv = mMathMLChar.Paint(aPresContext,
aRenderingContext,
mStyleContext,
nsRect(0,0,mRect.width,mRect.height));
mCharOffset);
}
else { // let the base class worry about the painting
//printf("Doing the painting with nsMathMLContainerFrame\n");
rv = nsMathMLContainerFrame::Paint(aPresContext,
aRenderingContext,
aDirtyRect,
@ -163,58 +131,33 @@ nsMathMLmoFrame::Paint(nsIPresContext& aPresContext,
return rv;
}
#if 0
void DEBUG_PrintString(const nsString aString) {
#if 0
PRUnichar* pc = (PRUnichar*)(const PRUnichar*)aString.GetUnicode();
while (*pc) {
if (*pc < 0x00FF)
printf("%c", char(*pc++));
else
printf("[%04x]", *pc++);
}
#endif
PRInt32 i;
for (i = 0; i<aString.Length(); i++) {
PRUnichar ch = aString.CharAt(i);
if (nsString::IsAlpha(ch) || nsString::IsDigit(ch) || ch == ' ')
printf("%c", char(ch));
else
printf("[0x%04X]", ch);
}
}
#endif
// NOTE: 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_IMETHODIMP
nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext,
nsStretchDirection aStretchDirection,
nsCharMetrics& aContainerSize,
nsCharMetrics& aDesiredStretchSize)
nsMathMLmoFrame::Init(nsIPresContext& aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = NS_OK;
// Let the base class do its Init()
nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
if (!mOperator) // don't wander here if we are not an operator
return NS_OK; // XXX Need to set default values for lspace and rspace
// Init our local attributes
mFlags = 0;
mLeftSpace = 0.0f; // .27777f;
mRightSpace = 0.0f; // .27777f;
mCharOffset.x = 0;
mCharOffset.y = 0;
// find the text that we enclose if it is the first time we come here
PRInt32 aLength = mMathMLChar.GetLength();
if (0 > aLength) { // this means it is the very first time we have been here.
// we will not be going over all this again when the
// window is repainted (resize, scroll).
return rv;
}
// if we exit prematurely from now on, we are surely not an operator
mOperator = PR_FALSE;
// get the text that we enclose. XXX TrimWhitespace?
void
nsMathMLmoFrame::InitData()
{
// get the text that we enclose. // XXX aData.CompressWhitespace() ?
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...
PRInt32 numKids;
@ -235,7 +178,19 @@ nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext,
}
}
// Look at our position from our parent (frames are singly-linked together).
// find our form
nsAutoString value;
nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_INFIX;
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::form, value)) {
if (value == "prefix")
aForm = NS_MATHML_OPERATOR_FORM_PREFIX;
else if (value == "postfix")
aForm = NS_MATHML_OPERATOR_FORM_POSTFIX;
}
else { // look at our position from our parent (frames are singly-linked together).
//////////////
// WHITESPACE: don't forget that whitespace doesn't count in MathML!
// Here is the situation: we may have empty frames between us:
@ -262,34 +217,35 @@ nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext,
break; // we can exit the while loop
}
}
rv = aFrame->GetNextSibling(&aFrame);
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get next sibbling");
aFrame->GetNextSibling(&aFrame);
}
// set our form flag depending on our position
nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_INFIX;
if (nsnull == prev && nsnull != next)
aForm = NS_MATHML_OPERATOR_FORM_PREFIX;
else if (nsnull != prev && nsnull == next)
aForm = NS_MATHML_OPERATOR_FORM_POSTFIX;
}
// Now that we know the text, we can lookup the operator dictionary to see if
// it was right to assume that this is an operator
// XXX aData.CompressWhitespace() ?
nsOperatorFlags aFlags;
float aLeftSpace, aRightSpace;
mOperator = nsMathMLOperators::LookupOperator(aData, aForm,
&aFlags, &aLeftSpace, &aRightSpace);
// cache our form
mFlags |= aForm;
// If it doesn't exist in the the dictionary, stop now
if (!mOperator)
return NS_OK;
// Now that we know our text an our form, we can lookup the operator dictionary
PRBool found;
found = nsMathMLOperators::LookupOperator(aData, aForm,
&mFlags, &mLeftSpace, &mRightSpace);
// XXX If we don't want extra space when we are a script
// If the operator exists in the dictionary and is stretchy, it is mutable
if (found && NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
mFlags |= NS_MATHML_OPERATOR_MUTABLE;
}
// If we don't want extra space when we are a script
// if (mScriptLevel > 0) {
// aLeftSpace = aRightSpace = 0;
// mLeftSpace = mRightSpace = 0;
// }
// XXX Factor all this in nsMathMLAttributes.cpp
// Now see if there are user-defined attributes that override the dictionary.
@ -300,49 +256,114 @@ nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext,
// movablelimits|separator|largeop|accent|fence|stretchy|form
nsAutoString kfalse("false");
nsAutoString value;
if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) {
if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::stretchy, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
}
if (NS_MATHML_OPERATOR_IS_FENCE(aFlags)) {
if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::fence, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_FENCE;
mFlags &= ~NS_MATHML_OPERATOR_FENCE;
}
if (NS_MATHML_OPERATOR_IS_ACCENT(aFlags)) {
if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::accent, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_ACCENT;
mFlags &= ~NS_MATHML_OPERATOR_ACCENT;
}
if (NS_MATHML_OPERATOR_IS_LARGEOP(aFlags)) {
if (NS_MATHML_OPERATOR_IS_LARGEOP(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::largeop, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
}
if (NS_MATHML_OPERATOR_IS_SEPARATOR(aFlags)) {
if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::separator, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
}
if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(aFlags)) {
if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags)) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute(kNameSpaceID_None,
nsMathMLAtoms::movablelimits, value) && value == kfalse)
aFlags &= ~NS_MATHML_OPERATOR_MOVABLELIMITS;
mFlags &= ~NS_MATHML_OPERATOR_MOVABLELIMITS;
}
// TODO: add also lspace and rspace, minsize, maxsize later ...
// cache all what we have learnt about this operator
mMathMLChar.Init(this, aData.Length(), aData, aFlags,
aLeftSpace, aRightSpace, aStretchDirection);
// If the stretchy attribute has been disabled, the operator is not mutable
if (!found || !NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
mFlags &= ~NS_MATHML_OPERATOR_MUTABLE;
return;
}
// cache the operator
mMathMLChar.SetData(aData);
return;
}
// NOTE: 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_IMETHODIMP
nsMathMLmoFrame::Stretch(nsIPresContext& aPresContext,
nsStretchDirection aStretchDirection,
nsCharMetrics& aContainerSize,
nsCharMetrics& aDesiredStretchSize)
{
if (0 == mFlags) { // first time...
InitData();
}
// get the value of 'em';
const nsStyleFont* aFont =
(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
nsCharMetrics old(aDesiredStretchSize);
// let the MathMLChar stretch itself...
mMathMLChar.Stretch(aPresContext, mStyleContext,
mMathMLChar.Stretch(aPresContext, mStyleContext, aStretchDirection,
aContainerSize, aDesiredStretchSize);
return rv;
if (old == aDesiredStretchSize) { // hasn't changed !
mFlags &= ~NS_MATHML_OPERATOR_MUTABLE;
mCharOffset.y = 0;
}
}
else {
mFlags &= ~NS_MATHML_OPERATOR_MUTABLE;
}
// account the spacing
aDesiredStretchSize.width += mCharOffset.x + nscoord( mRightSpace * em );
// adjust the offsets of our children to leave the spacing
if (0 < mCharOffset.x || 0 < mCharOffset.y) {
nsRect rect;
nscoord dx = mCharOffset.x;
nsIFrame* childFrame = mFrames.FirstChild();
while (nsnull != childFrame) {
if (!IsOnlyWhitespace(childFrame)) {
childFrame->GetRect(rect);
childFrame->MoveTo(dx, rect.y + mCharOffset.y);
dx += rect.width;
}
childFrame->GetNextSibling(&childFrame);
}
}
return NS_OK;
}

Просмотреть файл

@ -25,7 +25,6 @@
#include "nsCOMPtr.h"
#include "nsMathMLContainerFrame.h"
#include "nsMathMLChar.h"
//
// <mo> -- operator, fence, or separator
@ -56,14 +55,20 @@ public:
nsCharMetrics& aContainerSize,
nsCharMetrics& aDesiredStretchSize);
// helper method to lookup the operator dictionary and initialize our member data
void InitData();
protected:
nsMathMLmoFrame();
virtual ~nsMathMLmoFrame();
virtual PRIntn GetSkipSides() const { return 0; }
PRBool mOperator; // True if we are listed in the operator dictionary.
nsMathMLChar mMathMLChar; // Here is the MathChar that will deal with the operator.
nsOperatorFlags mFlags;
float mLeftSpace;
float mRightSpace;
nsPoint mCharOffset;
};
#endif /* nsMathMLmoFrame_h___ */