1999-09-21 02:12:01 +00:00
|
|
|
/*
|
|
|
|
* 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/
|
1999-12-10 13:02:23 +00:00
|
|
|
*
|
1999-09-21 02:12:01 +00:00
|
|
|
* 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.
|
1999-12-10 13:02:23 +00:00
|
|
|
*
|
1999-09-21 02:12:01 +00:00
|
|
|
* The Original Code is Mozilla MathML Project.
|
1999-12-10 13:02:23 +00:00
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is The University Of
|
1999-09-21 02:12:01 +00:00
|
|
|
* Queensland. Portions created by The University Of Queensland are
|
|
|
|
* Copyright (C) 1999 The University Of Queensland. All Rights Reserved.
|
1999-12-10 13:02:23 +00:00
|
|
|
*
|
|
|
|
* Contributor(s):
|
1999-09-21 02:12:01 +00:00
|
|
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
|
|
|
* David J. Fiddes <D.J.Fiddes@hw.ac.uk>
|
2000-03-28 09:38:24 +00:00
|
|
|
* Shyjan Mahamud <mahamud@cs.cmu.edu>
|
2000-02-02 22:24:56 +00:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
1999-09-21 02:12:01 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#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 "nsINameSpaceManager.h"
|
|
|
|
#include "nsIRenderingContext.h"
|
|
|
|
#include "nsIFontMetrics.h"
|
|
|
|
#include "nsStyleUtil.h"
|
|
|
|
|
|
|
|
#include "nsIDOMText.h"
|
|
|
|
|
|
|
|
#include "nsMathMLmoFrame.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
// <mo> -- operator, fence, or separator - implementation
|
|
|
|
//
|
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// TODO:
|
1999-09-21 02:12:01 +00:00
|
|
|
// * Handle embellished operators
|
|
|
|
// See the section "Exception for embellished operators"
|
|
|
|
// in http://www.w3.org/TR/REC-MathML/chap3_2.html
|
|
|
|
//
|
|
|
|
// * For a markup <mo>content</mo>, if "content" is not found in
|
|
|
|
// the operator dictionary, the REC sets default attributes :
|
1999-12-10 13:02:23 +00:00
|
|
|
// fence = false
|
|
|
|
// separator = false
|
|
|
|
// lspace = .27777em
|
|
|
|
// rspace = .27777em
|
|
|
|
// stretchy = false
|
1999-09-21 02:12:01 +00:00
|
|
|
// symmetric = true
|
|
|
|
// maxsize = infinity
|
|
|
|
// minsize = 1
|
|
|
|
// largeop = false
|
1999-12-10 13:02:23 +00:00
|
|
|
// movablelimits = false
|
1999-09-21 02:12:01 +00:00
|
|
|
// accent = false
|
|
|
|
//
|
|
|
|
// We only have to handle *lspace* and *rspace*, perhaps via a CSS padding rule
|
|
|
|
// in mathml.css, and override the rule if the content is found?
|
|
|
|
//
|
|
|
|
|
|
|
|
// * The spacing is wrong in certain situations, e.g.// <mrow> <mo>∀</mo> <mo>+</mo></mrow>
|
|
|
|
//
|
1999-12-10 13:02:23 +00:00
|
|
|
// The REC tells more about lspace and rspace attributes:
|
1999-09-21 02:12:01 +00:00
|
|
|
//
|
1999-12-10 13:02:23 +00:00
|
|
|
// The values for lspace and rspace given here range from 0 to 6/18 em in
|
1999-09-21 02:12:01 +00:00
|
|
|
// units of 1/18 em. For the invisible operators whose content is
|
1999-12-10 13:02:23 +00:00
|
|
|
// "⁢" or "⁡", it is suggested that MathML
|
1999-09-21 02:12:01 +00:00
|
|
|
// renderers choose spacing in a context-sensitive way (which is an exception to
|
1999-12-10 13:02:23 +00:00
|
|
|
// the static values given in the following table). For <mo>⁡</mo>,
|
1999-09-21 02:12:01 +00:00
|
|
|
// the total spacing (lspace + rspace) in expressions such as "sin x"
|
1999-12-10 13:02:23 +00:00
|
|
|
// (where the right operand doesn't start with a fence) should be greater
|
1999-09-21 02:12:01 +00:00
|
|
|
// than 0; for <mo>⁢</mo>, the total spacing should be greater
|
1999-12-10 13:02:23 +00:00
|
|
|
// than 0 when both operands (or the nearest tokens on either side, if on
|
|
|
|
// the baseline) are identifiers displayed in a non-slanted font (i.e., under
|
|
|
|
// the suggested rules, when both operands are multi-character identifiers).
|
1999-09-21 02:12:01 +00:00
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
|
|
|
|
// additional style context to be used by our MathMLChar.
|
|
|
|
#define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX 0
|
|
|
|
|
1999-09-21 02:12:01 +00:00
|
|
|
nsresult
|
1999-12-10 13:02:23 +00:00
|
|
|
NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
1999-09-21 02:12:01 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLmoFrame* it = new (aPresShell) nsMathMLmoFrame;
|
1999-09-21 02:12:01 +00:00
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
*aNewFrame = it;
|
1999-09-21 02:12:01 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMathMLmoFrame::nsMathMLmoFrame()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsMathMLmoFrame::~nsMathMLmoFrame()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMathMLmoFrame::Paint(nsIPresContext* aPresContext,
|
1999-09-21 02:12:01 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsFramePaintLayer aWhichLayer)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
1999-10-12 02:12:36 +00:00
|
|
|
|
2001-02-02 21:29:21 +00:00
|
|
|
if (NS_MATHML_OPERATOR_GET_FORM(mFlags) ||
|
|
|
|
NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
|
2000-03-28 09:38:24 +00:00
|
|
|
rv = mMathMLChar.Paint(aPresContext, aRenderingContext,
|
|
|
|
aDirtyRect, aWhichLayer, this);
|
2000-01-27 12:38:03 +00:00
|
|
|
#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
|
2000-01-18 04:35:37 +00:00
|
|
|
// for visual debug
|
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer &&
|
|
|
|
NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags))
|
|
|
|
{
|
2000-03-28 09:38:24 +00:00
|
|
|
aRenderingContext.SetColor(NS_RGB(0,255,255));
|
2000-01-18 04:35:37 +00:00
|
|
|
nscoord x = mReference.x + mBoundingMetrics.leftBearing;
|
2000-03-28 09:38:24 +00:00
|
|
|
nscoord y = mReference.y - mBoundingMetrics.ascent;
|
2000-01-18 04:35:37 +00:00
|
|
|
nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
|
|
|
|
nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent;
|
|
|
|
aRenderingContext.DrawRect(x,y,w,h);
|
|
|
|
}
|
|
|
|
#endif
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
1999-09-21 02:12:01 +00:00
|
|
|
else { // let the base class worry about the painting
|
2000-03-28 09:38:24 +00:00
|
|
|
rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext,
|
|
|
|
aDirtyRect, aWhichLayer);
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-10-12 02:12:36 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMathMLmoFrame::Init(nsIPresContext* aPresContext,
|
1999-10-12 02:12:36 +00:00
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aContext,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
|
|
|
// Let the base class do its Init()
|
|
|
|
nsresult rv = nsMathMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
|
2001-02-02 09:40:53 +00:00
|
|
|
|
1999-10-12 02:12:36 +00:00
|
|
|
// Init our local attributes
|
|
|
|
mFlags = 0;
|
|
|
|
mLeftSpace = 0.0f; // .27777f;
|
|
|
|
mRightSpace = 0.0f; // .27777f;
|
2000-01-26 06:49:38 +00:00
|
|
|
mMinSize = float(NS_UNCONSTRAINEDSIZE);
|
|
|
|
mMaxSize = float(NS_UNCONSTRAINEDSIZE);
|
1999-10-12 02:12:36 +00:00
|
|
|
|
|
|
|
// get the text that we enclose. // XXX aData.CompressWhitespace() ?
|
|
|
|
nsAutoString aData;
|
|
|
|
// PRInt32 aLength = 0;
|
|
|
|
// kids can be comment-nodes, attribute-nodes, text-nodes...
|
1999-11-17 00:49:37 +00:00
|
|
|
// we use the DOM to ensure that we only look at text-nodes...
|
1999-10-12 02:12:36 +00:00
|
|
|
PRInt32 numKids;
|
|
|
|
mContent->ChildCount(numKids);
|
|
|
|
for (PRInt32 kid=0; kid<numKids; kid++) {
|
|
|
|
nsCOMPtr<nsIContent> kidContent;
|
|
|
|
mContent->ChildAt(kid, *getter_AddRefs(kidContent));
|
1999-12-10 13:02:23 +00:00
|
|
|
if (kidContent.get()) {
|
1999-10-12 02:12:36 +00:00
|
|
|
nsCOMPtr<nsIDOMText> kidText(do_QueryInterface(kidContent));
|
|
|
|
if (kidText.get()) {
|
|
|
|
// PRUint32 kidLength;
|
|
|
|
// kidText->GetLength(&kidLength);
|
1999-12-10 13:02:23 +00:00
|
|
|
// aLength += kidLength;
|
1999-10-12 02:12:36 +00:00
|
|
|
nsAutoString kidData;
|
|
|
|
kidText->GetData(kidData);
|
|
|
|
aData += kidData;
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
// cache the operator
|
2000-03-28 09:38:24 +00:00
|
|
|
mMathMLChar.SetData(aPresContext, aData);
|
2000-05-08 07:31:05 +00:00
|
|
|
PRBool isMutable = ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mMathMLChar);
|
|
|
|
if (isMutable) {
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_MUTABLE;
|
|
|
|
}
|
2000-03-28 09:38:24 +00:00
|
|
|
|
|
|
|
#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);
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2000-01-14 08:38:25 +00:00
|
|
|
// fill our mEmbellishData member variable
|
1999-12-10 13:02:23 +00:00
|
|
|
nsIFrame* firstChild = mFrames.FirstChild();
|
|
|
|
while (firstChild) {
|
|
|
|
if (!IsOnlyWhitespace(firstChild)) {
|
2000-01-14 08:38:25 +00:00
|
|
|
mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR;
|
2000-01-07 14:49:46 +00:00
|
|
|
mEmbellishData.core = this;
|
|
|
|
mEmbellishData.direction = mMathMLChar.GetStretchDirection();
|
2000-01-14 08:38:25 +00:00
|
|
|
|
|
|
|
// for consistency, set the first non-empty child as the embellished child
|
|
|
|
mEmbellishData.firstChild = firstChild;
|
|
|
|
|
|
|
|
// there are two extra things that we need to record so that if our
|
|
|
|
// parent is <mover>, <munder>, or <munderover>, they will treat us properly:
|
|
|
|
// 1) do we have accent="true"
|
|
|
|
// 2) do we have movablelimits="true"
|
|
|
|
|
|
|
|
// they need the extra information to decide how to treat their scripts/limits
|
2000-03-28 09:38:24 +00:00
|
|
|
// (note: <mover>, <munder>, or <munderover> need not necessarily be our
|
2000-01-14 08:38:25 +00:00
|
|
|
// direct parent -- case of embellished operators)
|
|
|
|
|
|
|
|
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; // default is false
|
|
|
|
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS; // default is false
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
PRBool accentAttribute = PR_FALSE;
|
|
|
|
PRBool movablelimitsAttribute = PR_FALSE;
|
|
|
|
|
|
|
|
// see if the accent attribute is there
|
2000-03-28 09:38:24 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
2000-01-14 08:38:25 +00:00
|
|
|
nsMathMLAtoms::accent_, value))
|
|
|
|
{
|
|
|
|
accentAttribute = PR_TRUE;
|
2000-04-28 08:55:55 +00:00
|
|
|
if (value.EqualsWithConversion("true"))
|
2000-01-14 08:38:25 +00:00
|
|
|
{
|
|
|
|
mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if the movablelimits attribute is there
|
2000-03-28 09:38:24 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
2000-01-14 08:38:25 +00:00
|
|
|
nsMathMLAtoms::movablelimits_, value))
|
|
|
|
{
|
|
|
|
movablelimitsAttribute = PR_TRUE;
|
2000-04-28 08:55:55 +00:00
|
|
|
if (value.EqualsWithConversion("true"))
|
2000-01-14 08:38:25 +00:00
|
|
|
{
|
|
|
|
mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!accentAttribute || !movablelimitsAttribute) {
|
2000-03-28 09:38:24 +00:00
|
|
|
// If we reach here, it means one or both attributes are missing.
|
2000-01-14 08:38:25 +00:00
|
|
|
// 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"
|
2000-03-28 09:38:24 +00:00
|
|
|
// XXX should we check if the form attribute is there?
|
|
|
|
nsAutoString aData;
|
|
|
|
mMathMLChar.GetData(aData);
|
|
|
|
nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_POSTFIX;
|
2000-01-14 08:38:25 +00:00
|
|
|
nsOperatorFlags aFlags = 0;
|
|
|
|
float aLeftSpace, aRightSpace;
|
|
|
|
PRBool found = nsMathMLOperators::LookupOperator(aData, aForm,
|
|
|
|
&aFlags, &aLeftSpace, &aRightSpace);
|
2000-03-28 09:38:24 +00:00
|
|
|
|
2000-01-14 08:38:25 +00:00
|
|
|
if (found && !accentAttribute && NS_MATHML_OPERATOR_IS_ACCENT(aFlags))
|
|
|
|
{
|
|
|
|
mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
|
|
|
|
}
|
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// all movablemits="true" in the dictionary have form="prefix",
|
2000-01-14 08:38:25 +00:00
|
|
|
// 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;
|
2000-03-28 09:38:24 +00:00
|
|
|
}
|
2000-01-14 08:38:25 +00:00
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
firstChild->GetNextSibling(&firstChild);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-01-26 06:49:38 +00:00
|
|
|
nsMathMLmoFrame::InitData(nsIPresContext* aPresContext)
|
1999-12-10 13:02:23 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
2000-05-08 07:31:05 +00:00
|
|
|
|
|
|
|
// Remember the mutable bit from Init().
|
|
|
|
// Some chars are listed under different forms in the dictionary,
|
|
|
|
// and there could be a form under which the char is mutable.
|
|
|
|
// If the char is the core of an embellished container, we will keep
|
|
|
|
// it mutable irrespective of the form of the embellished container
|
|
|
|
mFlags &= NS_MATHML_OPERATOR_MUTABLE;
|
1999-10-12 02:12:36 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// find our form
|
1999-10-12 02:12:36 +00:00
|
|
|
nsAutoString value;
|
|
|
|
nsOperatorFlags aForm = NS_MATHML_OPERATOR_FORM_INFIX;
|
2000-05-08 07:31:05 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
nsIMathMLFrame* aMathMLFrame = nsnull;
|
2000-05-08 07:31:05 +00:00
|
|
|
nsEmbellishData embellishData;
|
|
|
|
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::form_, value)) {
|
2000-04-28 08:55:55 +00:00
|
|
|
if (value.EqualsWithConversion("prefix"))
|
1999-10-12 02:12:36 +00:00
|
|
|
aForm = NS_MATHML_OPERATOR_FORM_PREFIX;
|
2000-04-28 08:55:55 +00:00
|
|
|
else if (value.EqualsWithConversion("postfix"))
|
1999-10-12 02:12:36 +00:00
|
|
|
aForm = NS_MATHML_OPERATOR_FORM_POSTFIX;
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2000-05-08 07:31:05 +00:00
|
|
|
// see if we have an embellished ancestor, and check that we are really
|
|
|
|
// the 'core' of the ancestor, not just a sibling of the core
|
|
|
|
rv = mParent->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame);
|
|
|
|
if (NS_SUCCEEDED(rv) && aMathMLFrame) {
|
|
|
|
aMathMLFrame->GetEmbellishData(embellishData);
|
|
|
|
if (embellishData.core == this) {
|
|
|
|
// flag if we have an embellished ancestor
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
|
|
|
|
}
|
2000-01-14 08:38:25 +00:00
|
|
|
}
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
else {
|
|
|
|
// Get our outermost embellished container and its parent
|
2000-05-08 07:31:05 +00:00
|
|
|
nsIFrame* embellishAncestor;
|
1999-12-10 13:02:23 +00:00
|
|
|
nsIFrame* aParent = this;
|
|
|
|
do {
|
2000-01-14 08:38:25 +00:00
|
|
|
embellishAncestor = aParent;
|
2000-05-08 07:31:05 +00:00
|
|
|
embellishAncestor->GetParent(&aParent);
|
|
|
|
rv = aParent->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&aMathMLFrame);
|
|
|
|
if (NS_SUCCEEDED(rv) && aMathMLFrame) {
|
|
|
|
aMathMLFrame->GetEmbellishData(embellishData);
|
|
|
|
}
|
|
|
|
else {
|
2001-02-02 09:40:53 +00:00
|
|
|
embellishData.core = nsnull;
|
2000-05-08 07:31:05 +00:00
|
|
|
}
|
|
|
|
} while (embellishData.core == this);
|
1999-12-10 13:02:23 +00:00
|
|
|
// flag if we have an embellished ancestor
|
2000-03-28 09:38:24 +00:00
|
|
|
if (embellishAncestor != this)
|
2000-01-14 08:38:25 +00:00
|
|
|
{
|
2000-05-08 07:31:05 +00:00
|
|
|
mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
|
1999-12-10 13:02:23 +00:00
|
|
|
}
|
1999-09-21 02:12:01 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// Find the position of our outermost embellished container w.r.t
|
2000-01-07 14:49:46 +00:00
|
|
|
// its siblings (frames are singly-linked together).
|
1999-09-21 02:12:01 +00:00
|
|
|
//////////////
|
|
|
|
// WHITESPACE: don't forget that whitespace doesn't count in MathML!
|
|
|
|
// Here is the situation: we may have empty frames between us:
|
2000-01-14 08:38:25 +00:00
|
|
|
// [space*] [prev] [space*] [embellishAncestor] [space*] [next]
|
1999-12-10 13:02:23 +00:00
|
|
|
// We want to skip them...
|
1999-09-21 02:12:01 +00:00
|
|
|
// The problem looks like a regexp, we ask a little flag to help us.
|
|
|
|
PRInt32 state = 0;
|
|
|
|
nsIFrame* prev = nsnull;
|
|
|
|
nsIFrame* next = nsnull;
|
|
|
|
nsIFrame* aFrame;
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2000-01-28 09:00:03 +00:00
|
|
|
aParent->FirstChild(aPresContext, nsnull, &aFrame);
|
1999-12-10 13:02:23 +00:00
|
|
|
while (aFrame) {
|
2000-01-14 08:38:25 +00:00
|
|
|
if (aFrame == embellishAncestor) { // we start looking for next
|
1999-09-21 02:12:01 +00:00
|
|
|
state++;
|
|
|
|
}
|
|
|
|
else if (!IsOnlyWhitespace(aFrame)) {
|
|
|
|
if (0 == state) { // we are still looking for prev
|
1999-12-10 13:02:23 +00:00
|
|
|
prev = aFrame;
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
|
|
|
else if (1 == state) { // we got next
|
|
|
|
next = aFrame;
|
|
|
|
break; // we can exit the while loop
|
|
|
|
}
|
|
|
|
}
|
1999-10-12 02:12:36 +00:00
|
|
|
aFrame->GetNextSibling(&aFrame);
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
|
|
|
|
// set our form flag depending on the position
|
|
|
|
if (!prev && next)
|
1999-09-21 02:12:01 +00:00
|
|
|
aForm = NS_MATHML_OPERATOR_FORM_PREFIX;
|
1999-12-10 13:02:23 +00:00
|
|
|
else if (prev && !next)
|
1999-09-21 02:12:01 +00:00
|
|
|
aForm = NS_MATHML_OPERATOR_FORM_POSTFIX;
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
1999-09-21 02:12:01 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// Lookup the operator dictionary
|
|
|
|
nsAutoString aData;
|
|
|
|
mMathMLChar.GetData(aData);
|
2001-02-02 21:29:21 +00:00
|
|
|
//NS_ASSERTION(aData[0] != '+', "Breaking...");
|
2001-02-02 09:40:53 +00:00
|
|
|
mMathMLChar.SetData(aPresContext, aData); // XXX hack to reset, bug 45010
|
1999-12-10 13:02:23 +00:00
|
|
|
PRBool found = nsMathMLOperators::LookupOperator(aData, aForm,
|
|
|
|
&mFlags, &mLeftSpace, &mRightSpace);
|
|
|
|
|
|
|
|
// If we don't want too much extra space when we are a script
|
2000-05-08 07:31:05 +00:00
|
|
|
if ((0 < mPresentationData.scriptLevel) &&
|
|
|
|
!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
|
1999-11-17 00:49:37 +00:00
|
|
|
mLeftSpace /= 2.0f;
|
|
|
|
mRightSpace /= 2.0f;
|
|
|
|
}
|
1999-09-21 02:12:01 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// Now see if there are user-defined attributes that override the dictionary.
|
|
|
|
// XXX If an attribute can be forced to be true when it is false in the
|
1999-10-12 02:12:36 +00:00
|
|
|
// dictionary, then the following code has to change...
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2001-02-02 09:40:53 +00:00
|
|
|
// For each attribute overriden by the user, turn off its bit flag.
|
|
|
|
// symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form
|
2000-04-28 08:55:55 +00:00
|
|
|
nsAutoString kfalse, ktrue;
|
|
|
|
kfalse.AssignWithConversion("false");
|
|
|
|
ktrue.AssignWithConversion("true");
|
1999-10-12 02:12:36 +00:00
|
|
|
if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::stretchy_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
|
|
|
|
}
|
|
|
|
if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::fence_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_FENCE;
|
|
|
|
}
|
|
|
|
if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::accent_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_ACCENT;
|
|
|
|
}
|
|
|
|
if (NS_MATHML_OPERATOR_IS_LARGEOP(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::largeop_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
|
|
|
|
}
|
|
|
|
if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::separator_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
|
|
|
|
}
|
|
|
|
if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
1999-12-10 13:02:23 +00:00
|
|
|
nsMathMLAtoms::movablelimits_, value) && value == kfalse)
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_MOVABLELIMITS;
|
|
|
|
}
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
2000-03-28 09:38:24 +00:00
|
|
|
nsMathMLAtoms::symmetric_, value)) {
|
1999-12-10 13:02:23 +00:00
|
|
|
if (value == kfalse) mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
|
2000-03-28 09:38:24 +00:00
|
|
|
else if (value == ktrue) mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
|
1999-12-10 13:02:23 +00:00
|
|
|
}
|
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// If we are an accent without explicit lspace="." or rspace=".",
|
2000-01-14 08:38:25 +00:00
|
|
|
// ignore our default left/right space
|
2000-01-26 06:49:38 +00:00
|
|
|
|
|
|
|
// Get the value of 'em'
|
|
|
|
nsStyleFont font;
|
|
|
|
mStyleContext->GetStyle(eStyleStruct_Font, font);
|
|
|
|
float em = float(font.mFont.size);
|
|
|
|
|
2000-05-16 13:15:15 +00:00
|
|
|
// lspace = number h-unit | namedspace
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::lspace_, value)) {
|
|
|
|
nsCSSValue cssValue;
|
2000-05-16 13:15:15 +00:00
|
|
|
if (ParseNumericValue(value, cssValue) ||
|
|
|
|
ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
|
2000-03-28 09:38:24 +00:00
|
|
|
{
|
|
|
|
if ((eCSSUnit_Number == cssValue.GetUnit()) &&
|
|
|
|
(0.0f == cssValue.GetFloatValue()))
|
|
|
|
mLeftSpace = 0.0f;
|
|
|
|
else if (cssValue.IsLengthUnit())
|
|
|
|
mLeftSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em;
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) {
|
2000-01-14 08:38:25 +00:00
|
|
|
mLeftSpace = 0.0f;
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
|
2000-05-16 13:15:15 +00:00
|
|
|
// rspace = number h-unit | namedspace
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::rspace_, value)) {
|
|
|
|
nsCSSValue cssValue;
|
2000-05-16 13:15:15 +00:00
|
|
|
if (ParseNumericValue(value, cssValue) ||
|
|
|
|
ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
|
2000-03-28 09:38:24 +00:00
|
|
|
{
|
|
|
|
if ((eCSSUnit_Number == cssValue.GetUnit()) &&
|
|
|
|
(0.0f == cssValue.GetFloatValue()))
|
|
|
|
mRightSpace = 0.0f;
|
|
|
|
else if (cssValue.IsLengthUnit())
|
|
|
|
mRightSpace = float(CalcLength(aPresContext, mStyleContext, cssValue)) / em;
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags)) {
|
2000-01-14 08:38:25 +00:00
|
|
|
mRightSpace = 0.0f;
|
|
|
|
}
|
|
|
|
|
2000-05-16 13:15:15 +00:00
|
|
|
// minsize = number [ v-unit | h-unit ] | namedspace
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::minsize_, value)) {
|
|
|
|
nsCSSValue cssValue;
|
2000-05-16 13:15:15 +00:00
|
|
|
if (ParseNumericValue(value, cssValue) ||
|
|
|
|
ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
|
|
|
|
{
|
2000-01-26 06:49:38 +00:00
|
|
|
nsCSSUnit unit = cssValue.GetUnit();
|
|
|
|
if (eCSSUnit_Number == unit)
|
|
|
|
mMinSize = cssValue.GetFloatValue();
|
|
|
|
else if (eCSSUnit_Percent == unit)
|
|
|
|
mMinSize = cssValue.GetPercentValue();
|
|
|
|
else if (eCSSUnit_Null != unit) {
|
|
|
|
mMinSize = float(CalcLength(aPresContext, mStyleContext, cssValue));
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_MINSIZE_EXPLICIT;
|
|
|
|
}
|
2000-05-08 07:31:05 +00:00
|
|
|
|
|
|
|
if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
|
|
|
|
// see if the multiplicative inheritance should be from <mstyle>
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(nsnull, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::minsize_, value)) {
|
|
|
|
if (ParseNumericValue(value, cssValue)) {
|
|
|
|
if (cssValue.IsLengthUnit()) {
|
|
|
|
mMinSize *= float(CalcLength(aPresContext, mStyleContext, cssValue));
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_MINSIZE_EXPLICIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-16 13:15:15 +00:00
|
|
|
// maxsize = number [ v-unit | h-unit ] | namedspace | infinity
|
2000-01-26 06:49:38 +00:00
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::maxsize_, value)) {
|
|
|
|
nsCSSValue cssValue;
|
2000-05-16 13:15:15 +00:00
|
|
|
if (ParseNumericValue(value, cssValue) ||
|
|
|
|
ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
|
|
|
|
{
|
2000-01-26 06:49:38 +00:00
|
|
|
nsCSSUnit unit = cssValue.GetUnit();
|
|
|
|
if (eCSSUnit_Number == unit)
|
|
|
|
mMaxSize = cssValue.GetFloatValue();
|
|
|
|
else if (eCSSUnit_Percent == unit)
|
|
|
|
mMaxSize = cssValue.GetPercentValue();
|
|
|
|
else if (eCSSUnit_Null != unit) {
|
|
|
|
mMaxSize = float(CalcLength(aPresContext, mStyleContext, cssValue));
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_MAXSIZE_EXPLICIT;
|
|
|
|
}
|
2000-05-08 07:31:05 +00:00
|
|
|
|
|
|
|
if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
|
|
|
|
// see if the multiplicative inheritance should be from <mstyle>
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(nsnull, mPresentationData.mstyle,
|
|
|
|
nsMathMLAtoms::maxsize_, value)) {
|
|
|
|
if (ParseNumericValue(value, cssValue)) {
|
|
|
|
if (cssValue.IsLengthUnit()) {
|
|
|
|
mMaxSize *= float(CalcLength(aPresContext, mStyleContext, cssValue));
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_MAXSIZE_EXPLICIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// 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)))
|
|
|
|
{
|
1999-10-12 02:12:36 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_MUTABLE;
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
2001-02-02 21:29:21 +00:00
|
|
|
|
|
|
|
// See if this is an operator that should be centered to cater for
|
|
|
|
// fonts that are not math-aware
|
|
|
|
if (1 == aData.Length()) {
|
|
|
|
PRUnichar ch = aData[0];
|
|
|
|
if ((ch == '+') || (ch == '=') || (ch == '*') ||
|
|
|
|
(ch == 0x00D7)) { // ×
|
|
|
|
mFlags |= NS_MATHML_OPERATOR_CENTERED;
|
|
|
|
}
|
|
|
|
}
|
1999-09-21 02:12:01 +00:00
|
|
|
}
|
|
|
|
|
1999-10-12 02:12:36 +00:00
|
|
|
// 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
|
1999-11-24 06:03:41 +00:00
|
|
|
nsMathMLmoFrame::Stretch(nsIPresContext* aPresContext,
|
1999-11-17 00:49:37 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
nsStretchDirection aStretchDirection,
|
2000-03-28 09:38:24 +00:00
|
|
|
nsBoundingMetrics& aContainerSize,
|
|
|
|
nsHTMLReflowMetrics& aDesiredStretchSize)
|
1999-10-12 02:12:36 +00:00
|
|
|
{
|
2000-01-07 14:49:46 +00:00
|
|
|
if (NS_MATHML_STRETCH_WAS_DONE(mEmbellishData.flags)) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("WARNING *** it is wrong to fire stretch more than once on a frame...\n");
|
1999-12-10 13:02:23 +00:00
|
|
|
return NS_OK;
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
2000-01-07 14:49:46 +00:00
|
|
|
mEmbellishData.flags |= NS_MATHML_STRETCH_DONE;
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
InitData(aPresContext);
|
1999-10-12 02:12:36 +00:00
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// get the axis height;
|
|
|
|
nsStyleFont font;
|
|
|
|
mStyleContext->GetStyle(eStyleStruct_Font, font);
|
|
|
|
nsCOMPtr<nsIFontMetrics> fm;
|
2000-04-17 04:23:03 +00:00
|
|
|
aRenderingContext.SetFont(font.mFont);
|
|
|
|
aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
|
2000-05-08 07:31:05 +00:00
|
|
|
nscoord fontAscent, fontDescent, axisHeight, height;
|
2000-04-17 04:23:03 +00:00
|
|
|
GetAxisHeight(aRenderingContext, fm, axisHeight);
|
2000-03-28 09:38:24 +00:00
|
|
|
fm->GetMaxAscent(fontAscent);
|
|
|
|
fm->GetMaxDescent(fontDescent);
|
|
|
|
|
2001-02-02 21:29:21 +00:00
|
|
|
// Operators that exist in the dictionary, or those that are to be centered
|
|
|
|
// to cater for fonts that are not math-aware, are handled by the MathMLChar
|
2000-03-28 09:38:24 +00:00
|
|
|
|
2001-02-02 21:29:21 +00:00
|
|
|
if (NS_MATHML_OPERATOR_GET_FORM(mFlags) ||
|
|
|
|
NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
|
2000-03-28 09:38:24 +00:00
|
|
|
nsBoundingMetrics charSize;
|
|
|
|
nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics;
|
|
|
|
nsBoundingMetrics container = initialSize;
|
2000-01-26 06:49:38 +00:00
|
|
|
|
2000-05-08 07:31:05 +00:00
|
|
|
PRBool isVertical = PR_FALSE;
|
2001-02-02 09:40:53 +00:00
|
|
|
PRUint32 stretchHint = NS_STRETCH_NORMAL;
|
2000-05-08 07:31:05 +00:00
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// see if it is okay to stretch
|
|
|
|
if (NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) {
|
2000-01-26 06:49:38 +00:00
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
container = aContainerSize;
|
2000-01-26 06:49:38 +00:00
|
|
|
|
2000-05-08 07:31:05 +00:00
|
|
|
if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) ||
|
|
|
|
(aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT)) &&
|
|
|
|
(mMathMLChar.GetStretchDirection() == NS_STRETCH_DIRECTION_VERTICAL))
|
|
|
|
{
|
|
|
|
isVertical = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2001-02-02 09:40:53 +00:00
|
|
|
// see if we are in display mode, and set largeop or largeopOnly
|
|
|
|
// . largeopOnly is taken if largeop=true and stretchy=false
|
|
|
|
// . largeop is taken if largeop=true and stretchy=true
|
|
|
|
if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags) &&
|
|
|
|
NS_MATHML_OPERATOR_IS_LARGEOP(mFlags)) {
|
|
|
|
stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!)
|
|
|
|
if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
|
|
|
|
stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (isVertical) {
|
|
|
|
// TeX hint. Can impact some sloppy markups missing <mrow></mrow>
|
|
|
|
stretchHint = NS_STRETCH_NEARER;
|
|
|
|
}
|
|
|
|
|
|
|
|
// some adjustments if the operator is symmetric and vertical
|
|
|
|
|
2000-05-08 07:31:05 +00:00
|
|
|
if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags))
|
2000-03-28 09:38:24 +00:00
|
|
|
{
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// 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;
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
|
2000-03-28 09:38:24 +00:00
|
|
|
// 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 =
|
2001-02-02 09:40:53 +00:00
|
|
|
PR_MIN(container.descent, nscoord(initialSize.descent * aspect));
|
2000-03-28 09:38:24 +00:00
|
|
|
// 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));
|
|
|
|
}
|
2000-05-08 07:31:05 +00:00
|
|
|
|
|
|
|
if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags))
|
|
|
|
{
|
|
|
|
// re-adjust to align the char with the bottom of the initial container
|
|
|
|
height = container.ascent + container.descent;
|
2001-02-02 09:40:53 +00:00
|
|
|
container.descent = aContainerSize.descent;
|
2000-05-08 07:31:05 +00:00
|
|
|
container.ascent = height - container.descent;
|
|
|
|
}
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
2000-03-28 09:38:24 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
2000-05-08 07:31:05 +00:00
|
|
|
|
|
|
|
if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags))
|
|
|
|
{
|
|
|
|
// re-adjust to align the char with the bottom of the initial container
|
|
|
|
height = container.ascent + container.descent;
|
2001-02-02 09:40:53 +00:00
|
|
|
container.descent = aContainerSize.descent;
|
2000-05-08 07:31:05 +00:00
|
|
|
container.ascent = height - container.descent;
|
|
|
|
}
|
2000-01-26 06:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-12 02:12:36 +00:00
|
|
|
// let the MathMLChar stretch itself...
|
2000-07-25 00:08:15 +00:00
|
|
|
nsresult res = mMathMLChar.Stretch(aPresContext, aRenderingContext,
|
|
|
|
aStretchDirection, container, charSize, stretchHint);
|
|
|
|
if (NS_FAILED(res)) {
|
2001-02-02 09:40:53 +00:00
|
|
|
// gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed)
|
2000-07-25 00:08:15 +00:00
|
|
|
// clear our 'form' to behave as if the operator wasn't in the dictionary
|
2001-02-02 09:40:53 +00:00
|
|
|
mFlags &= ~NS_MATHML_OPERATOR_FORM;
|
2000-07-25 00:08:15 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// update our bounding metrics... it becomes that of our MathML char
|
|
|
|
mMathMLChar.GetBoundingMetrics(mBoundingMetrics);
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2001-02-02 21:29:21 +00:00
|
|
|
if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags))
|
2000-07-25 00:08:15 +00:00
|
|
|
{
|
|
|
|
// the desired size returned by mMathMLChar maybe different
|
|
|
|
// from the size of the container.
|
|
|
|
// the mMathMLChar.mRect.y calculation is subtle, watch out!!!
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2000-07-25 00:08:15 +00:00
|
|
|
height = mBoundingMetrics.ascent + mBoundingMetrics.descent;
|
2001-02-02 21:29:21 +00:00
|
|
|
if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) ||
|
|
|
|
NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
|
|
|
|
// For symmetric and vertical operators, or for operators that are always
|
|
|
|
// centered ('+', '*', etc) we want to center about the axis of the container
|
2000-07-25 00:08:15 +00:00
|
|
|
mBoundingMetrics.descent = height/2 - axisHeight;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Otherwise, align the char with the bottom of the container
|
|
|
|
mBoundingMetrics.descent = container.descent;
|
|
|
|
}
|
|
|
|
mBoundingMetrics.ascent = height - mBoundingMetrics.descent;
|
2000-05-08 07:31:05 +00:00
|
|
|
}
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2000-07-25 00:08:15 +00:00
|
|
|
// 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;
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2000-07-25 00:08:15 +00:00
|
|
|
nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent;
|
2001-02-02 21:29:21 +00:00
|
|
|
if ((mMathMLChar.GetStretchDirection() == NS_STRETCH_DIRECTION_UNSUPPORTED)
|
|
|
|
&& !NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
|
2000-07-25 00:08:15 +00:00
|
|
|
// reset
|
|
|
|
dy = aDesiredStretchSize.ascent - charSize.ascent;
|
|
|
|
aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics = charSize;
|
2000-05-08 07:31:05 +00:00
|
|
|
}
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2000-07-25 00:08:15 +00:00
|
|
|
mMathMLChar.SetRect(
|
|
|
|
nsRect(0, dy, charSize.width,
|
|
|
|
charSize.ascent + charSize.descent));
|
2001-02-02 09:40:53 +00:00
|
|
|
|
2000-07-25 00:08:15 +00:00
|
|
|
mReference.x = 0;
|
|
|
|
mReference.y = aDesiredStretchSize.ascent;
|
2000-03-28 09:38:24 +00:00
|
|
|
}
|
2000-07-25 00:08:15 +00:00
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
|
|
|
|
|
2001-02-02 21:29:21 +00:00
|
|
|
if (!NS_MATHML_OPERATOR_GET_FORM(mFlags) &&
|
|
|
|
!NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
|
2000-07-25 00:08:15 +00:00
|
|
|
// Place our children using the default method
|
|
|
|
Place(aPresContext, aRenderingContext, PR_TRUE, aDesiredStretchSize);
|
2000-03-28 09:38:24 +00:00
|
|
|
}
|
2000-01-18 04:35:37 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// 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.
|
2000-03-28 09:38:24 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
|
2000-03-28 09:38:24 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
// Get the value of 'em'
|
|
|
|
nscoord em = NSToCoordRound(float(font.mFont.size));
|
|
|
|
|
|
|
|
// Account the spacing
|
2000-03-28 09:38:24 +00:00
|
|
|
aDesiredStretchSize.width += nscoord((mLeftSpace + mRightSpace) * em);
|
2000-01-19 22:36:23 +00:00
|
|
|
mBoundingMetrics.width = aDesiredStretchSize.width;
|
2000-03-28 09:38:24 +00:00
|
|
|
nscoord dx = nscoord(mLeftSpace * em);
|
2000-01-19 22:36:23 +00:00
|
|
|
|
1999-12-10 13:02:23 +00:00
|
|
|
if (0 == dx) return NS_OK;
|
|
|
|
|
|
|
|
// adjust the offsets
|
2000-01-19 22:36:23 +00:00
|
|
|
mBoundingMetrics.leftBearing += dx;
|
|
|
|
mBoundingMetrics.rightBearing += dx;
|
2001-02-02 21:29:21 +00:00
|
|
|
aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics;
|
2000-01-18 04:35:37 +00:00
|
|
|
|
1999-10-12 02:12:36 +00:00
|
|
|
nsRect rect;
|
2000-03-28 09:38:24 +00:00
|
|
|
if (NS_MATHML_OPERATOR_GET_FORM(mFlags)) {
|
1999-12-10 13:02:23 +00:00
|
|
|
mMathMLChar.GetRect(rect);
|
|
|
|
mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y, rect.width, rect.height));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsIFrame* childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
1999-10-12 02:12:36 +00:00
|
|
|
childFrame->GetRect(rect);
|
1999-12-10 13:02:23 +00:00
|
|
|
childFrame->MoveTo(aPresContext, rect.x + dx, rect.y);
|
|
|
|
childFrame->GetNextSibling(&childFrame);
|
1999-10-12 02:12:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-12-10 13:02:23 +00:00
|
|
|
|
2000-01-07 14:49:46 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMathMLmoFrame::Reflow(nsIPresContext* aPresContext,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
|
|
|
return ReflowTokenFor(this, aPresContext, aDesiredSize,
|
|
|
|
aReflowState, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMathMLmoFrame::Place(nsIPresContext* aPresContext,
|
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
PRBool aPlaceOrigin,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize)
|
|
|
|
{
|
|
|
|
return PlaceTokenFor(this, aPresContext, aRenderingContext,
|
|
|
|
aPlaceOrigin, aDesiredSize);
|
|
|
|
}
|
2000-03-28 09:38:24 +00:00
|
|
|
|
|
|
|
// ----------------------
|
|
|
|
// 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;
|
|
|
|
}
|