2004-02-23 21:29:06 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2004-04-18 14:30:37 +00:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
2001-02-02 14:27:38 +00:00
|
|
|
*
|
2004-04-18 14:30:37 +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/
|
|
|
|
*
|
|
|
|
* 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.
|
2001-02-02 14:27:38 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla MathML Project.
|
|
|
|
*
|
2004-04-18 14:30:37 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* The University Of Queensland.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2001-02-02 14:27:38 +00:00
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
|
|
|
* David J. Fiddes <D.J.Fiddes@hw.ac.uk>
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
2004-04-18 14:30:37 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsHTMLParts.h"
|
|
|
|
#include "nsFrame.h"
|
2004-07-31 23:15:21 +00:00
|
|
|
#include "nsPresContext.h"
|
2001-02-02 14:27:38 +00:00
|
|
|
#include "nsIPresShell.h"
|
2002-11-17 15:37:56 +00:00
|
|
|
#include "nsCSSAnonBoxes.h"
|
2001-02-02 14:27:38 +00:00
|
|
|
#include "nsUnitConversion.h"
|
2003-02-22 00:32:13 +00:00
|
|
|
#include "nsStyleContext.h"
|
2001-02-02 14:27:38 +00:00
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIRenderingContext.h"
|
|
|
|
#include "nsIFontMetrics.h"
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
#include "nsIDOMText.h"
|
2001-02-02 14:27:38 +00:00
|
|
|
#include "nsITextContent.h"
|
2002-02-03 21:06:51 +00:00
|
|
|
#include "nsIDOMMutationEvent.h"
|
2004-02-23 21:29:06 +00:00
|
|
|
#include "nsFrameManager.h"
|
2002-01-09 18:51:30 +00:00
|
|
|
#include "nsStyleChangeList.h"
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
#include "nsMathMLAtoms.h"
|
|
|
|
#include "nsMathMLParts.h"
|
|
|
|
#include "nsMathMLChar.h"
|
|
|
|
#include "nsMathMLContainerFrame.h"
|
2003-02-22 00:32:13 +00:00
|
|
|
#include "nsAutoPtr.h"
|
2004-01-28 00:18:22 +00:00
|
|
|
#include "nsStyleSet.h"
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2003-02-26 01:17:37 +00:00
|
|
|
NS_DEFINE_CID(kInlineFrameCID, NS_INLINE_FRAME_CID);
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
//
|
|
|
|
// nsMathMLContainerFrame implementation
|
|
|
|
//
|
|
|
|
|
|
|
|
// nsISupports
|
|
|
|
// =============================================================================
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_IMPL_ADDREF_INHERITED(nsMathMLContainerFrame, nsMathMLFrame)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsMathMLContainerFrame, nsMathMLFrame)
|
|
|
|
NS_IMPL_QUERY_INTERFACE_INHERITED1(nsMathMLContainerFrame, nsHTMLContainerFrame, nsMathMLFrame)
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
// =============================================================================
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// error handlers
|
2002-01-25 06:48:30 +00:00
|
|
|
// provide a feedback to the user when a frame with bad markup can not be rendered
|
2001-02-02 14:27:38 +00:00
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::ReflowError(nsIRenderingContext& aRenderingContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsHTMLReflowMetrics& aDesiredSize)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// clear all other flags and record that there is an error with this frame
|
|
|
|
mEmbellishData.flags = 0;
|
|
|
|
mPresentationData.flags = NS_MATHML_ERROR;
|
|
|
|
|
|
|
|
///////////////
|
|
|
|
// Set font
|
2003-05-15 03:42:21 +00:00
|
|
|
aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// bounding metrics
|
2004-06-17 00:13:25 +00:00
|
|
|
nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
|
2001-06-30 11:02:25 +00:00
|
|
|
rv = aRenderingContext.GetBoundingMetrics(errorMsg.get(),
|
2001-02-02 14:27:38 +00:00
|
|
|
PRUint32(errorMsg.Length()),
|
|
|
|
mBoundingMetrics);
|
|
|
|
if (NS_FAILED(rv)) {
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_WARNING("GetBoundingMetrics failed");
|
2001-02-02 14:27:38 +00:00
|
|
|
aDesiredSize.width = aDesiredSize.height = 0;
|
|
|
|
aDesiredSize.ascent = aDesiredSize.descent = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reflow metrics
|
|
|
|
nsCOMPtr<nsIFontMetrics> fm;
|
|
|
|
aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
|
|
|
|
fm->GetMaxAscent(aDesiredSize.ascent);
|
|
|
|
fm->GetMaxDescent(aDesiredSize.descent);
|
|
|
|
aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
|
|
|
|
aDesiredSize.width = mBoundingMetrics.width;
|
|
|
|
|
2003-01-09 14:26:32 +00:00
|
|
|
if (aDesiredSize.mComputeMEW) {
|
|
|
|
aDesiredSize.mMaxElementWidth = aDesiredSize.width;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
// Also return our bounding metrics
|
|
|
|
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::PaintError(nsIRenderingContext& aRenderingContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsFramePaintLayer aWhichLayer)
|
|
|
|
{
|
2002-02-07 04:38:08 +00:00
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
|
2001-02-02 14:27:38 +00:00
|
|
|
NS_ASSERTION(NS_MATHML_HAS_ERROR(mPresentationData.flags),
|
|
|
|
"There is nothing wrong with this frame!");
|
|
|
|
// Set color and font ...
|
2003-05-15 03:42:21 +00:00
|
|
|
aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-25 06:48:30 +00:00
|
|
|
aRenderingContext.SetColor(NS_RGB(255,0,0));
|
|
|
|
aRenderingContext.FillRect(0, 0, mRect.width, mRect.height);
|
|
|
|
aRenderingContext.SetColor(NS_RGB(255,255,255));
|
|
|
|
|
2001-10-30 22:58:00 +00:00
|
|
|
nscoord ascent;
|
|
|
|
nsCOMPtr<nsIFontMetrics> fm;
|
|
|
|
aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
|
|
|
|
fm->GetMaxAscent(ascent);
|
|
|
|
|
2004-06-17 00:13:25 +00:00
|
|
|
nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
|
2001-06-30 11:02:25 +00:00
|
|
|
aRenderingContext.DrawString(errorMsg.get(),
|
2001-02-23 16:10:51 +00:00
|
|
|
PRUint32(errorMsg.Length()),
|
2002-01-25 06:48:30 +00:00
|
|
|
0, ascent);
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* /////////////
|
2002-01-10 23:40:40 +00:00
|
|
|
* nsIMathMLFrame - support methods for stretchy elements
|
2001-02-02 14:27:38 +00:00
|
|
|
* =============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// helper method to facilitate getting the reflow and bounding metrics
|
|
|
|
void
|
|
|
|
nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFrame,
|
|
|
|
nsHTMLReflowMetrics& aReflowMetrics,
|
|
|
|
nsBoundingMetrics& aBoundingMetrics)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "null arg");
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
// IMPORTANT: This function is only meant to be called in Place() methods
|
2001-02-02 14:27:38 +00:00
|
|
|
// where it is assumed that the frame's rect is still acting as place holder
|
|
|
|
// for the frame's ascent and descent information
|
2001-02-23 16:10:51 +00:00
|
|
|
|
2003-07-08 11:00:00 +00:00
|
|
|
nsRect rect = aFrame->GetRect();
|
2001-02-23 16:10:51 +00:00
|
|
|
aReflowMetrics.descent = rect.x;
|
|
|
|
aReflowMetrics.ascent = rect.y;
|
|
|
|
aReflowMetrics.width = rect.width;
|
|
|
|
aReflowMetrics.height = rect.height;
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
aBoundingMetrics.Clear();
|
2001-02-23 16:10:51 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-01-10 23:40:40 +00:00
|
|
|
aFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
2001-02-23 16:10:51 +00:00
|
|
|
mathMLFrame->GetBoundingMetrics(aBoundingMetrics);
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
else { // aFrame is not a MathML frame, just return the reflow metrics
|
|
|
|
aBoundingMetrics.descent = aReflowMetrics.descent;
|
|
|
|
aBoundingMetrics.ascent = aReflowMetrics.ascent;
|
|
|
|
aBoundingMetrics.width = aReflowMetrics.width;
|
2001-02-23 16:10:51 +00:00
|
|
|
aBoundingMetrics.rightBearing = aReflowMetrics.width;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-10 23:40:40 +00:00
|
|
|
// helper to get the preferred size that a container frame should use to fire
|
|
|
|
// the stretch on its stretchy child frames.
|
2002-01-02 05:32:33 +00:00
|
|
|
void
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::GetPreferredStretchSize(nsIRenderingContext& aRenderingContext,
|
2002-01-02 05:32:33 +00:00
|
|
|
PRUint32 aOptions,
|
|
|
|
nsStretchDirection aStretchDirection,
|
|
|
|
nsBoundingMetrics& aPreferredStretchSize)
|
|
|
|
{
|
|
|
|
if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) {
|
|
|
|
// when our actual size is ok, just use it
|
|
|
|
aPreferredStretchSize = mBoundingMetrics;
|
|
|
|
}
|
|
|
|
else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
|
|
|
|
// compute our up-to-date size using Place()
|
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
2005-02-07 01:57:50 +00:00
|
|
|
Place(aRenderingContext, PR_FALSE, metrics);
|
2002-01-05 01:15:04 +00:00
|
|
|
aPreferredStretchSize = metrics.mBoundingMetrics;
|
2002-01-02 05:32:33 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// compute a size that doesn't include embellishements
|
|
|
|
NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
|
2002-02-07 04:38:08 +00:00
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags) ||
|
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags),
|
2002-01-02 05:32:33 +00:00
|
|
|
"invalid call to GetPreferredStretchSize");
|
|
|
|
PRBool firstTime = PR_TRUE;
|
|
|
|
nsBoundingMetrics bm, bmChild;
|
|
|
|
// XXXrbs need overloaded FirstChild() and clean integration of <maction> throughout
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = GetFirstChild(nsnull);
|
2002-01-02 05:32:33 +00:00
|
|
|
while (childFrame) {
|
|
|
|
// initializations in case this child happens not to be a MathML frame
|
2003-07-08 11:00:00 +00:00
|
|
|
nsRect rect = childFrame->GetRect();
|
2002-01-02 05:32:33 +00:00
|
|
|
bmChild.ascent = rect.y;
|
|
|
|
bmChild.descent = rect.x;
|
|
|
|
bmChild.width = rect.width;
|
|
|
|
bmChild.rightBearing = rect.width;
|
|
|
|
bmChild.leftBearing = 0;
|
|
|
|
|
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-01-10 23:40:40 +00:00
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
2005-09-06 23:47:01 +00:00
|
|
|
nsEmbellishData embellishData;
|
|
|
|
nsPresentationData presentationData;
|
|
|
|
mathMLFrame->GetEmbellishData(embellishData);
|
|
|
|
mathMLFrame->GetPresentationData(presentationData);
|
|
|
|
if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) &&
|
|
|
|
embellishData.direction == aStretchDirection &&
|
|
|
|
presentationData.baseFrame) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// embellishements are not included, only consider the inner first child itself
|
|
|
|
nsIMathMLFrame* mathMLchildFrame;
|
2005-09-06 23:47:01 +00:00
|
|
|
presentationData.baseFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLchildFrame);
|
2002-01-10 23:40:40 +00:00
|
|
|
if (mathMLchildFrame) {
|
2002-01-02 05:32:33 +00:00
|
|
|
mathMLFrame = mathMLchildFrame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mathMLFrame->GetBoundingMetrics(bmChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = PR_FALSE;
|
|
|
|
bm = bmChild;
|
2002-02-07 04:38:08 +00:00
|
|
|
if (!NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags) &&
|
|
|
|
!NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// we may get here for cases such as <msup><mo>...</mo> ... </msup>
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2002-02-07 04:38:08 +00:00
|
|
|
if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// if we get here, it means this is container that will stack its children
|
|
|
|
// vertically and fire an horizontal stretch on each them. This is the case
|
|
|
|
// for \munder, \mover, \munderover. We just sum-up the size vertically.
|
|
|
|
bm.descent += bmChild.ascent + bmChild.descent;
|
|
|
|
if (bm.leftBearing > bmChild.leftBearing)
|
|
|
|
bm.leftBearing = bmChild.leftBearing;
|
|
|
|
if (bm.rightBearing < bmChild.rightBearing)
|
|
|
|
bm.rightBearing = bmChild.rightBearing;
|
|
|
|
}
|
2002-02-07 04:38:08 +00:00
|
|
|
else if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// just sum-up the sizes horizontally.
|
|
|
|
bm += bmChild;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ERROR("unexpected case in GetPreferredStretchSize");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-01-02 05:32:33 +00:00
|
|
|
}
|
|
|
|
aPreferredStretchSize = bm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::Stretch(nsIRenderingContext& aRenderingContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsStretchDirection aStretchDirection,
|
|
|
|
nsBoundingMetrics& aContainerSize,
|
|
|
|
nsHTMLReflowMetrics& aDesiredStretchSize)
|
|
|
|
{
|
|
|
|
if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
|
|
|
|
|
2002-02-07 04:38:08 +00:00
|
|
|
if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_WARNING("it is wrong to fire stretch more than once on a frame");
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2002-02-07 04:38:08 +00:00
|
|
|
mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_WARNING("it is wrong to fire stretch on a erroneous frame");
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-09-06 23:47:01 +00:00
|
|
|
// Pass the stretch to the base child ...
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2005-09-06 23:47:01 +00:00
|
|
|
nsIFrame* childFrame = mPresentationData.baseFrame;
|
2001-02-02 14:27:38 +00:00
|
|
|
if (childFrame) {
|
2001-02-23 16:10:51 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-01-10 23:40:40 +00:00
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
NS_ASSERTION(mathMLFrame, "Something is wrong somewhere");
|
|
|
|
if (mathMLFrame) {
|
2002-01-02 22:42:52 +00:00
|
|
|
PRBool stretchAll =
|
2002-02-07 04:38:08 +00:00
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
|
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
// And the trick is that the child's rect.x is still holding the descent,
|
2001-02-02 14:27:38 +00:00
|
|
|
// and rect.y is still holding the ascent ...
|
|
|
|
nsHTMLReflowMetrics childSize(aDesiredStretchSize);
|
2001-02-23 16:10:51 +00:00
|
|
|
GetReflowAndBoundingMetricsFor(childFrame, childSize, childSize.mBoundingMetrics);
|
|
|
|
|
2002-01-05 01:15:04 +00:00
|
|
|
// See if we should downsize and confine the stretch to us...
|
|
|
|
// XXX there may be other cases where we can downsize the stretch,
|
|
|
|
// e.g., the first ∑ might appear big in the following situation
|
|
|
|
// <math xmlns='http://www.w3.org/1998/Math/MathML'>
|
|
|
|
// <mstyle>
|
|
|
|
// <msub>
|
|
|
|
// <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
|
|
|
|
// <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
|
|
|
|
// </msub>
|
|
|
|
// </mstyle>
|
|
|
|
// </math>
|
2001-02-02 14:27:38 +00:00
|
|
|
nsBoundingMetrics containerSize = aContainerSize;
|
2001-02-23 16:10:51 +00:00
|
|
|
if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT &&
|
2001-02-02 14:27:38 +00:00
|
|
|
aStretchDirection != mEmbellishData.direction) {
|
2002-01-05 01:15:04 +00:00
|
|
|
if (mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) {
|
|
|
|
containerSize = childSize.mBoundingMetrics;
|
|
|
|
}
|
|
|
|
else {
|
2005-02-07 01:57:50 +00:00
|
|
|
GetPreferredStretchSize(aRenderingContext,
|
2002-01-05 01:15:04 +00:00
|
|
|
stretchAll ? STRETCH_CONSIDER_EMBELLISHMENTS : 0,
|
|
|
|
mEmbellishData.direction, containerSize);
|
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// do the stretching...
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->Stretch(aRenderingContext,
|
2001-02-23 16:10:51 +00:00
|
|
|
mEmbellishData.direction, containerSize, childSize);
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
// store the updated metrics
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetRect(nsRect(childSize.descent, childSize.ascent,
|
2001-02-02 14:27:38 +00:00
|
|
|
childSize.width, childSize.height));
|
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
// Remember the siblings which were _deferred_.
|
|
|
|
// Now that this embellished child may have changed, we need to
|
|
|
|
// fire the stretch on its siblings using our updated size
|
|
|
|
|
2002-01-02 22:42:52 +00:00
|
|
|
if (stretchAll) {
|
2002-01-02 05:32:33 +00:00
|
|
|
|
|
|
|
nsStretchDirection stretchDir =
|
2002-02-07 04:38:08 +00:00
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ?
|
2002-01-02 05:32:33 +00:00
|
|
|
NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL;
|
|
|
|
|
2005-02-07 01:57:50 +00:00
|
|
|
GetPreferredStretchSize(aRenderingContext, STRETCH_CONSIDER_EMBELLISHMENTS,
|
2002-01-02 05:32:33 +00:00
|
|
|
stretchDir, containerSize);
|
|
|
|
|
|
|
|
childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2005-09-06 23:47:01 +00:00
|
|
|
if (childFrame != mPresentationData.baseFrame) {
|
2002-01-10 23:40:40 +00:00
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// retrieve the metrics that was stored at the previous pass
|
|
|
|
GetReflowAndBoundingMetricsFor(childFrame,
|
|
|
|
childSize, childSize.mBoundingMetrics);
|
|
|
|
// do the stretching...
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->Stretch(aRenderingContext, stretchDir,
|
|
|
|
containerSize, childSize);
|
2002-01-02 05:32:33 +00:00
|
|
|
// store the updated metrics
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetRect(nsRect(childSize.descent, childSize.ascent,
|
2002-01-02 05:32:33 +00:00
|
|
|
childSize.width, childSize.height));
|
|
|
|
}
|
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-01-02 05:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// re-position all our children
|
2005-02-07 01:57:50 +00:00
|
|
|
Place(aRenderingContext, PR_TRUE, aDesiredStretchSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2002-02-07 04:38:08 +00:00
|
|
|
nsEmbellishData parentData;
|
|
|
|
GetEmbellishDataFrom(mParent, parentData);
|
|
|
|
// ensure that we are the embellished child, not just a sibling
|
|
|
|
// (need to test coreFrame since <mfrac> resets other things)
|
|
|
|
if (parentData.coreFrame != mEmbellishData.coreFrame) {
|
|
|
|
// (we fetch values from the core since they may use units that depend
|
|
|
|
// on style data, and style changes could have occured in the core since
|
|
|
|
// our last visit there)
|
2001-02-02 14:27:38 +00:00
|
|
|
nsEmbellishData coreData;
|
2002-02-07 04:38:08 +00:00
|
|
|
GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-05 01:15:04 +00:00
|
|
|
mBoundingMetrics.width += coreData.leftSpace + coreData.rightSpace;
|
|
|
|
aDesiredStretchSize.width = mBoundingMetrics.width;
|
|
|
|
aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-05 01:15:04 +00:00
|
|
|
nscoord dx = coreData.leftSpace;
|
2001-02-23 16:10:51 +00:00
|
|
|
if (!dx) return NS_OK;
|
|
|
|
|
2002-01-05 01:15:04 +00:00
|
|
|
mBoundingMetrics.leftBearing += dx;
|
|
|
|
mBoundingMetrics.rightBearing += dx;
|
2001-02-02 14:27:38 +00:00
|
|
|
aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
|
|
|
|
aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
|
|
|
|
|
|
|
|
childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetPosition(childFrame->GetPosition()
|
|
|
|
+ nsPoint(dx, 0));
|
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::FinalizeReflow(nsIRenderingContext& aRenderingContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsHTMLReflowMetrics& aDesiredSize)
|
|
|
|
{
|
|
|
|
// During reflow, we use rect.x and rect.y as placeholders for the child's ascent
|
|
|
|
// and descent in expectation of a stretch command. Hence we need to ensure that
|
|
|
|
// a stretch command will actually be fired later on, after exiting from our
|
|
|
|
// reflow. If the stretch is not fired, the rect.x, and rect.y will remain
|
|
|
|
// with inappropriate data causing children to be improperly positioned.
|
|
|
|
// This helper method checks to see if our parent will fire a stretch command
|
2001-02-23 16:10:51 +00:00
|
|
|
// targeted at us. If not, we go ahead and fire an involutive stretch on
|
2001-02-02 14:27:38 +00:00
|
|
|
// ourselves. This will clear all the rect.x and rect.y, and return our
|
|
|
|
// desired size.
|
|
|
|
|
|
|
|
|
|
|
|
// First, complete the post-reflow hook.
|
|
|
|
// We use the information in our children rectangles to position them.
|
|
|
|
// If placeOrigin==false, then Place() will not touch rect.x, and rect.y.
|
|
|
|
// They will still be holding the ascent and descent for each child.
|
2002-01-05 01:15:04 +00:00
|
|
|
|
|
|
|
// The first clause caters for any non-embellished container.
|
|
|
|
// The second clause is for a container which won't fire stretch even though it is
|
|
|
|
// embellished, e.g., as in <mfrac><mo>...</mo> ... </mfrac>, the test is convoluted
|
|
|
|
// because it excludes the particular case of the core <mo>...</mo> itself.
|
2002-01-06 19:47:24 +00:00
|
|
|
// (<mo> needs to fire stretch on its MathMLChar in any case to initialize it)
|
2002-01-05 01:15:04 +00:00
|
|
|
PRBool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
|
2005-09-06 23:47:01 +00:00
|
|
|
(mEmbellishData.coreFrame != this && !mPresentationData.baseFrame &&
|
2002-01-05 01:15:04 +00:00
|
|
|
mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED);
|
2005-02-07 01:57:50 +00:00
|
|
|
Place(aRenderingContext, placeOrigin, aDesiredSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
if (!placeOrigin) {
|
2001-02-23 16:10:51 +00:00
|
|
|
// This means the rect.x and rect.y of our children were not set!!
|
2001-02-02 14:27:38 +00:00
|
|
|
// Don't go without checking to see if our parent will later fire a Stretch() command
|
|
|
|
// targeted at us. The Stretch() will cause the rect.x and rect.y to clear...
|
|
|
|
PRBool parentWillFireStretch = PR_FALSE;
|
2001-02-23 16:10:51 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-01-10 23:40:40 +00:00
|
|
|
mParent->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
2002-02-07 04:38:08 +00:00
|
|
|
nsEmbellishData embellishData;
|
|
|
|
nsPresentationData presentationData;
|
|
|
|
mathMLFrame->GetEmbellishData(embellishData);
|
|
|
|
mathMLFrame->GetPresentationData(presentationData);
|
|
|
|
if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) ||
|
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) ||
|
|
|
|
(NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)
|
2005-09-06 23:47:01 +00:00
|
|
|
&& presentationData.baseFrame == this))
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
|
|
|
parentWillFireStretch = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!parentWillFireStretch) {
|
|
|
|
// There is nobody who will fire the stretch for us, we do it ourselves!
|
|
|
|
|
2002-01-06 19:47:24 +00:00
|
|
|
PRBool stretchAll =
|
2002-02-07 04:38:08 +00:00
|
|
|
/* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */
|
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
|
2002-01-06 19:47:24 +00:00
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
nsBoundingMetrics defaultSize;
|
2002-01-27 22:10:45 +00:00
|
|
|
if (mEmbellishData.coreFrame == this /* case of a bare <mo>...</mo> itself */
|
2002-01-06 19:47:24 +00:00
|
|
|
|| stretchAll) { /* or <mover><mo>...</mo>...</mover>, or friends */
|
|
|
|
// use our current size as computed earlier by Place()
|
2002-01-05 01:15:04 +00:00
|
|
|
defaultSize = aDesiredSize.mBoundingMetrics;
|
|
|
|
}
|
2002-01-06 19:47:24 +00:00
|
|
|
else { /* case of <msup><mo>...</mo>...</msup> or friends */
|
|
|
|
// compute a size that doesn't include embellishments
|
2005-02-07 01:57:50 +00:00
|
|
|
GetPreferredStretchSize(aRenderingContext, 0, mEmbellishData.direction,
|
|
|
|
defaultSize);
|
2002-01-05 01:15:04 +00:00
|
|
|
}
|
2005-02-07 01:57:50 +00:00
|
|
|
Stretch(aRenderingContext, NS_STRETCH_DIRECTION_DEFAULT, defaultSize,
|
|
|
|
aDesiredSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
2003-01-09 14:26:32 +00:00
|
|
|
if (aDesiredSize.mComputeMEW) {
|
|
|
|
aDesiredSize.mMaxElementWidth = aDesiredSize.width;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
// Also return our bounding metrics
|
|
|
|
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
2001-02-23 16:10:51 +00:00
|
|
|
|
|
|
|
// see if we should fix the spacing
|
2005-02-07 01:57:50 +00:00
|
|
|
FixInterFrameSpacing(aDesiredSize);
|
2001-02-23 16:10:51 +00:00
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* /////////////
|
|
|
|
* nsIMathMLFrame - support methods for scripting elements (nested frames
|
2001-02-23 16:10:51 +00:00
|
|
|
* within msub, msup, msubsup, munder, mover, munderover, mmultiscripts,
|
2001-02-02 14:27:38 +00:00
|
|
|
* mfrac, mroot, mtable).
|
|
|
|
* =============================================================================
|
|
|
|
*/
|
|
|
|
|
2002-01-09 18:51:30 +00:00
|
|
|
// helper to let the update of presentation data pass through
|
|
|
|
// a subtree that may contain non-mathml container frames
|
|
|
|
/* static */ void
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame* aFrame,
|
2002-01-09 18:51:30 +00:00
|
|
|
PRInt32 aScriptLevelIncrement,
|
|
|
|
PRUint32 aFlagsValues,
|
|
|
|
PRUint32 aFlagsToUpdate)
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
2002-01-10 04:42:55 +00:00
|
|
|
if (!aFlagsToUpdate && !aScriptLevelIncrement)
|
|
|
|
return;
|
2002-01-09 18:51:30 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
|
|
|
aFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
|
|
|
// update
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->UpdatePresentationData(aScriptLevelIncrement, aFlagsValues,
|
|
|
|
aFlagsToUpdate);
|
2002-01-10 04:42:55 +00:00
|
|
|
// propagate using the base method to make sure that the control
|
|
|
|
// is passed on to MathML frames that may be overloading the method
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->UpdatePresentationDataFromChildAt(0, -1,
|
|
|
|
aScriptLevelIncrement, aFlagsValues, aFlagsToUpdate);
|
2002-01-09 18:51:30 +00:00
|
|
|
}
|
2002-01-10 04:42:55 +00:00
|
|
|
else {
|
|
|
|
// propagate down the subtrees
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aFrame->GetFirstChild(nsnull);
|
2002-01-10 04:42:55 +00:00
|
|
|
while (childFrame) {
|
2005-02-07 01:57:50 +00:00
|
|
|
PropagatePresentationDataFor(childFrame,
|
2002-01-10 04:42:55 +00:00
|
|
|
aScriptLevelIncrement, aFlagsValues, aFlagsToUpdate);
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-01-10 04:42:55 +00:00
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-14 00:55:53 +00:00
|
|
|
/* static */ void
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame* aParentFrame,
|
2002-01-14 00:55:53 +00:00
|
|
|
PRInt32 aFirstChildIndex,
|
|
|
|
PRInt32 aLastChildIndex,
|
|
|
|
PRInt32 aScriptLevelIncrement,
|
|
|
|
PRUint32 aFlagsValues,
|
|
|
|
PRUint32 aFlagsToUpdate)
|
|
|
|
{
|
|
|
|
if (!aFlagsToUpdate && !aScriptLevelIncrement)
|
|
|
|
return;
|
|
|
|
PRInt32 index = 0;
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aParentFrame->GetFirstChild(nsnull);
|
2002-01-14 00:55:53 +00:00
|
|
|
while (childFrame) {
|
|
|
|
if ((index >= aFirstChildIndex) &&
|
|
|
|
((aLastChildIndex <= 0) || ((aLastChildIndex > 0) &&
|
|
|
|
(index <= aLastChildIndex)))) {
|
2005-02-07 01:57:50 +00:00
|
|
|
PropagatePresentationDataFor(childFrame,
|
2002-01-14 00:55:53 +00:00
|
|
|
aScriptLevelIncrement, aFlagsValues, aFlagsToUpdate);
|
|
|
|
}
|
|
|
|
index++;
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-01-14 00:55:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-09 18:51:30 +00:00
|
|
|
// helper to let the scriptstyle re-resolution pass through
|
|
|
|
// a subtree that may contain non-mathml container frames.
|
|
|
|
// This function is *very* expensive. Unfortunately, there isn't much
|
|
|
|
// to do about it at the moment. For background on the problem @see
|
|
|
|
// http://groups.google.com/groups?selm=3A9192B5.D22B6C38%40maths.uq.edu.au
|
|
|
|
/* static */ void
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::PropagateScriptStyleFor(nsIFrame* aFrame,
|
2002-01-09 18:51:30 +00:00
|
|
|
PRInt32 aParentScriptLevel)
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
2002-01-09 18:51:30 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
|
|
|
aFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
|
|
|
// we will re-resolve our style data based on our current scriptlevel
|
|
|
|
nsPresentationData presentationData;
|
|
|
|
mathMLFrame->GetPresentationData(presentationData);
|
|
|
|
PRInt32 gap = presentationData.scriptLevel - aParentScriptLevel;
|
|
|
|
|
|
|
|
// since we are a MathML frame, our current scriptlevel becomes
|
|
|
|
// the one to use when we will propagate the recursion
|
|
|
|
aParentScriptLevel = presentationData.scriptLevel;
|
|
|
|
|
2003-02-22 00:32:13 +00:00
|
|
|
nsStyleContext* oldStyleContext = aFrame->GetStyleContext();
|
|
|
|
nsStyleContext* parentContext = oldStyleContext->GetParent();
|
2002-01-09 18:51:30 +00:00
|
|
|
|
2003-07-08 11:00:00 +00:00
|
|
|
nsIContent* content = aFrame->GetContent();
|
2002-01-10 04:42:55 +00:00
|
|
|
if (!gap) {
|
2002-01-09 18:51:30 +00:00
|
|
|
// unset any -moz-math-font-size attribute without notifying that we want a reflow
|
2005-09-06 23:47:01 +00:00
|
|
|
content->UnsetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZfontsize, PR_FALSE);
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
2002-01-09 18:51:30 +00:00
|
|
|
else {
|
|
|
|
// By default scriptminsize=8pt and scriptsizemultiplier=0.71
|
|
|
|
nscoord scriptminsize = NSIntPointsToTwips(NS_MATHML_SCRIPTMINSIZE);
|
|
|
|
float scriptsizemultiplier = NS_MATHML_SCRIPTSIZEMULTIPLIER;
|
|
|
|
#if 0
|
|
|
|
// XXX Bug 44201
|
|
|
|
// user-supplied scriptminsize and scriptsizemultiplier that are
|
|
|
|
// restricted to particular elements are not supported because our
|
|
|
|
// css rules are fixed in mathml.css and are applicable to all elements.
|
|
|
|
|
|
|
|
// see if there is a scriptminsize attribute on a <mstyle> that wraps us
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
|
|
|
GetAttribute(nsnull, presentationData.mstyle,
|
|
|
|
nsMathMLAtoms::scriptminsize_, fontsize)) {
|
|
|
|
nsCSSValue cssValue;
|
|
|
|
if (ParseNumericValue(fontsize, cssValue)) {
|
|
|
|
nsCSSUnit unit = cssValue.GetUnit();
|
|
|
|
if (eCSSUnit_Number == unit)
|
|
|
|
scriptminsize = nscoord(float(scriptminsize) * cssValue.GetFloatValue());
|
|
|
|
else if (eCSSUnit_Percent == unit)
|
|
|
|
scriptminsize = nscoord(float(scriptminsize) * cssValue.GetPercentValue());
|
|
|
|
else if (eCSSUnit_Null != unit)
|
2005-02-07 01:57:50 +00:00
|
|
|
scriptminsize = CalcLength(mStyleContext, cssValue);
|
2002-01-09 18:51:30 +00:00
|
|
|
}
|
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
#endif
|
|
|
|
|
2002-01-09 18:51:30 +00:00
|
|
|
// figure out the incremental factor
|
|
|
|
nsAutoString fontsize;
|
|
|
|
if (0 > gap) { // the size is going to be increased
|
|
|
|
if (gap < NS_MATHML_CSS_NEGATIVE_SCRIPTLEVEL_LIMIT)
|
|
|
|
gap = NS_MATHML_CSS_NEGATIVE_SCRIPTLEVEL_LIMIT;
|
|
|
|
gap = -gap;
|
|
|
|
scriptsizemultiplier = 1.0f / scriptsizemultiplier;
|
2004-06-17 00:13:25 +00:00
|
|
|
fontsize.AssignLiteral("-");
|
2002-01-09 18:51:30 +00:00
|
|
|
}
|
|
|
|
else { // the size is going to be decreased
|
|
|
|
if (gap > NS_MATHML_CSS_POSITIVE_SCRIPTLEVEL_LIMIT)
|
|
|
|
gap = NS_MATHML_CSS_POSITIVE_SCRIPTLEVEL_LIMIT;
|
2004-06-17 00:13:25 +00:00
|
|
|
fontsize.AssignLiteral("+");
|
2002-01-09 18:51:30 +00:00
|
|
|
}
|
|
|
|
fontsize.AppendInt(gap, 10);
|
|
|
|
// we want to make sure that the size will stay readable
|
2003-05-15 03:42:21 +00:00
|
|
|
const nsStyleFont* font = parentContext->GetStyleFont();
|
2002-01-09 18:51:30 +00:00
|
|
|
nscoord newFontSize = font->mFont.size;
|
|
|
|
while (0 < gap--) {
|
|
|
|
newFontSize = (nscoord)((float)(newFontSize) * scriptsizemultiplier);
|
|
|
|
}
|
|
|
|
if (newFontSize <= scriptminsize) {
|
2004-06-17 00:13:25 +00:00
|
|
|
fontsize.AssignLiteral("scriptminsize");
|
2002-01-09 18:51:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set the -moz-math-font-size attribute without notifying that we want a reflow
|
2005-09-06 23:47:01 +00:00
|
|
|
content->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZfontsize,
|
2002-01-09 18:51:30 +00:00
|
|
|
fontsize, PR_FALSE);
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-09 18:51:30 +00:00
|
|
|
// now, re-resolve the style contexts in our subtree
|
2005-02-07 01:57:50 +00:00
|
|
|
nsFrameManager *fm = aFrame->GetPresContext()->FrameManager();
|
2004-02-23 21:29:06 +00:00
|
|
|
nsStyleChangeList changeList;
|
|
|
|
fm->ComputeStyleChangeFor(aFrame, &changeList, NS_STYLE_HINT_NONE);
|
2003-01-05 05:05:17 +00:00
|
|
|
#ifdef DEBUG
|
2004-02-23 21:29:06 +00:00
|
|
|
// Use the parent frame to make sure we catch in-flows and such
|
|
|
|
nsIFrame* parentFrame = aFrame->GetParent();
|
|
|
|
fm->DebugVerifyStyleTree(parentFrame ? parentFrame : aFrame);
|
2003-01-05 05:05:17 +00:00
|
|
|
#endif
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
|
2002-01-09 18:51:30 +00:00
|
|
|
// recurse down the subtrees for changes that may arise deep down
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aFrame->GetFirstChild(nsnull);
|
2001-02-23 16:10:51 +00:00
|
|
|
while (childFrame) {
|
2002-01-10 04:42:55 +00:00
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
|
|
|
// propagate using the base method to make sure that the control
|
|
|
|
// is passed on to MathML frames that may be overloading the method
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->ReResolveScriptStyle(aParentScriptLevel);
|
2002-01-10 04:42:55 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-02-07 01:57:50 +00:00
|
|
|
PropagateScriptStyleFor(childFrame, aParentScriptLevel);
|
2002-01-10 04:42:55 +00:00
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* //////////////////
|
|
|
|
* Frame construction
|
|
|
|
* =============================================================================
|
|
|
|
*/
|
|
|
|
|
2002-02-01 15:10:50 +00:00
|
|
|
// We use this to wrap non-MathML frames so that foreign elements (e.g.,
|
|
|
|
// html:img) can mix better with other surrounding MathML markups.
|
|
|
|
// Currently we only wrap nsInlineFrames because problems were observed only
|
|
|
|
// in the presence of such frames. By construction, a foreign frame wrapper
|
|
|
|
// has one and only one child, and the life of the wrapper is bound to the
|
|
|
|
// life of that unique child. Not all child list operations are applicable
|
|
|
|
// with a wrapper. One must either use the parent (or the unique child)
|
|
|
|
// for such operations (@see nsMathMLForeignFrameWrapper).
|
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::WrapForeignFrames()
|
2002-02-01 15:10:50 +00:00
|
|
|
{
|
|
|
|
nsIFrame* next = mFrames.FirstChild();
|
2005-02-07 01:57:50 +00:00
|
|
|
nsPresContext* presContext = GetPresContext();
|
|
|
|
nsFrameManager *frameManager = presContext->FrameManager();
|
2004-01-31 22:41:40 +00:00
|
|
|
|
2002-02-01 15:10:50 +00:00
|
|
|
while (next) {
|
|
|
|
nsIFrame* child = next;
|
2003-07-08 11:00:00 +00:00
|
|
|
next = next->GetNextSibling();
|
2002-02-01 15:10:50 +00:00
|
|
|
nsInlineFrame* inlineFrame;
|
2003-02-26 01:17:37 +00:00
|
|
|
child->QueryInterface(kInlineFrameCID, (void**)&inlineFrame);
|
2002-02-01 15:10:50 +00:00
|
|
|
if (inlineFrame) {
|
|
|
|
// create a new wrapper frame to wrap this child
|
|
|
|
nsIFrame* wrapper;
|
2005-02-07 01:57:50 +00:00
|
|
|
nsresult rv = NS_NewMathMLForeignFrameWrapper(presContext->PresShell(),
|
2003-12-21 05:36:36 +00:00
|
|
|
&wrapper);
|
2002-02-01 15:10:50 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2003-02-22 00:32:13 +00:00
|
|
|
nsRefPtr<nsStyleContext> newStyleContext;
|
2005-02-07 01:57:50 +00:00
|
|
|
newStyleContext = presContext->StyleSet()->
|
2004-01-28 00:18:22 +00:00
|
|
|
ResolvePseudoStyleFor(mContent,
|
|
|
|
nsCSSAnonBoxes::mozAnonymousBlock,
|
|
|
|
mStyleContext);
|
2005-02-07 01:57:50 +00:00
|
|
|
rv = wrapper->Init(presContext, mContent, this, newStyleContext, nsnull);
|
2002-02-01 15:10:50 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
2005-02-07 01:57:50 +00:00
|
|
|
wrapper->Destroy(presContext);
|
2002-02-01 15:10:50 +00:00
|
|
|
return rv;
|
|
|
|
}
|
2005-02-07 01:57:50 +00:00
|
|
|
mFrames.ReplaceFrame(this, child, wrapper, PR_FALSE);
|
2002-02-01 15:10:50 +00:00
|
|
|
child->SetParent(wrapper);
|
|
|
|
child->SetNextSibling(nsnull);
|
2004-01-31 22:41:40 +00:00
|
|
|
frameManager->ReParentStyleContext(child, newStyleContext);
|
2005-02-07 01:57:50 +00:00
|
|
|
wrapper->SetInitialChildList(presContext, nsnull, child);
|
2002-02-01 15:10:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
NS_IMETHODIMP
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMathMLContainerFrame::Paint(nsPresContext* aPresContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect,
|
2001-09-19 12:35:19 +00:00
|
|
|
nsFramePaintLayer aWhichLayer,
|
|
|
|
PRUint32 aFlags)
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
2004-03-08 04:14:07 +00:00
|
|
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// report an error if something wrong was found in this frame
|
|
|
|
if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
|
2005-02-07 01:57:50 +00:00
|
|
|
return PaintError(aRenderingContext, aDirtyRect, aWhichLayer);
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
2004-03-08 04:14:07 +00:00
|
|
|
// Paint inline element backgrounds in the foreground layer (bug 36710).
|
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
|
|
|
|
PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintDecorationsAndChildren(aPresContext, aRenderingContext, aDirtyRect,
|
|
|
|
aWhichLayer, PR_FALSE, aFlags);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
|
2001-02-02 14:27:38 +00:00
|
|
|
// for visual debug
|
|
|
|
// ----------------
|
|
|
|
// if you want to see your bounding box, make sure to properly fill
|
|
|
|
// your mBoundingMetrics and mReference point, and set
|
|
|
|
// mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS
|
|
|
|
// in the Init() of your sub-class
|
|
|
|
|
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer &&
|
|
|
|
NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags))
|
|
|
|
{
|
|
|
|
aRenderingContext.SetColor(NS_RGB(0,0,255));
|
|
|
|
|
|
|
|
nscoord x = mReference.x + mBoundingMetrics.leftBearing;
|
|
|
|
nscoord y = mReference.y - mBoundingMetrics.ascent;
|
|
|
|
nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
|
|
|
|
nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent;
|
|
|
|
|
|
|
|
aRenderingContext.DrawRect(x,y,w,h);
|
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
#endif
|
2004-03-08 04:14:07 +00:00
|
|
|
return NS_OK;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
|
2002-01-10 23:40:40 +00:00
|
|
|
// This method is called in a top-down manner, as we descend the frame tree
|
|
|
|
// during its construction
|
2001-02-02 14:27:38 +00:00
|
|
|
NS_IMETHODIMP
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMathMLContainerFrame::Init(nsPresContext* aPresContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
2003-02-22 00:32:13 +00:00
|
|
|
nsStyleContext* aContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
2002-02-14 12:26:43 +00:00
|
|
|
MapAttributesIntoCSS(aPresContext, aContent);
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
// let the base class do its Init()
|
2002-02-07 04:38:08 +00:00
|
|
|
return nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-02-07 04:38:08 +00:00
|
|
|
// ...We will build our automatic MathML data once the entire <math>...</math>
|
|
|
|
// tree is constructed.
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
2002-01-10 23:40:40 +00:00
|
|
|
// This method is called in a bottom-up manner, as we ascend the frame tree
|
|
|
|
// after its construction
|
2001-02-02 14:27:38 +00:00
|
|
|
NS_IMETHODIMP
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMathMLContainerFrame::SetInitialChildList(nsPresContext* aPresContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aChildList)
|
|
|
|
{
|
|
|
|
// First, let the base class do its job
|
2002-02-07 04:38:08 +00:00
|
|
|
nsresult rv = nsHTMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// Next, since we are an inline frame, and since we are a container, we have to
|
|
|
|
// be very careful with the way we treat our children. Things look okay when
|
|
|
|
// all of our children are only MathML frames. But there are problems if one of
|
|
|
|
// our children happens to be an nsInlineFrame, e.g., from generated content such
|
|
|
|
// as :before { content: open-quote } or :after { content: close-quote }
|
|
|
|
// The code asserts during reflow (in nsLineLayout::BeginSpan)
|
|
|
|
// Also there are problems when our children are hybrid, e.g., from html markups.
|
|
|
|
// In short, the nsInlineFrame class expects a number of *invariants* that are not
|
|
|
|
// met when we mix things.
|
|
|
|
|
2002-02-01 15:10:50 +00:00
|
|
|
// So wrap foreign children in nsMathMLForeignFrameWrapper frames
|
2005-02-07 01:57:50 +00:00
|
|
|
WrapForeignFrames();
|
2002-02-07 04:38:08 +00:00
|
|
|
return rv;
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-02-07 04:38:08 +00:00
|
|
|
// ...We will build our automatic MathML data once the entire <math>...</math>
|
|
|
|
// tree is constructed.
|
2002-02-01 15:10:50 +00:00
|
|
|
}
|
|
|
|
|
2002-02-03 21:06:51 +00:00
|
|
|
// Note that this method re-builds the automatic data in the children -- not
|
2002-02-07 04:38:08 +00:00
|
|
|
// in aParentFrame itself (except for those particular operations that the
|
|
|
|
// parent frame may do in its TransmitAutomaticData()).
|
2002-02-01 15:10:50 +00:00
|
|
|
/* static */ void
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame)
|
2002-02-01 15:10:50 +00:00
|
|
|
{
|
|
|
|
// 1. As we descend the tree, make each child frame inherit data from
|
|
|
|
// the parent
|
|
|
|
// 2. As we ascend the tree, transmit any specific change that we want
|
|
|
|
// down the subtrees
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aParentFrame->GetFirstChild(nsnull);
|
2002-02-01 15:10:50 +00:00
|
|
|
while (childFrame) {
|
|
|
|
nsIMathMLFrame* childMathMLFrame;
|
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&childMathMLFrame);
|
|
|
|
if (childMathMLFrame) {
|
2005-02-07 01:57:50 +00:00
|
|
|
childMathMLFrame->InheritAutomaticData(aParentFrame);
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2005-02-07 01:57:50 +00:00
|
|
|
RebuildAutomaticDataForChildren(childFrame);
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-02-01 15:10:50 +00:00
|
|
|
}
|
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-02-07 04:38:08 +00:00
|
|
|
aParentFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
2002-02-01 15:10:50 +00:00
|
|
|
if (mathMLFrame) {
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->TransmitAutomaticData();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-03 21:06:51 +00:00
|
|
|
/* static */ nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
|
2002-02-03 21:06:51 +00:00
|
|
|
{
|
|
|
|
// walk-up to the first frame that is a MathML frame, stop if we reach <math>
|
|
|
|
PRInt32 parentScriptLevel = 0;
|
2002-02-07 04:38:08 +00:00
|
|
|
nsIFrame* frame = aParentFrame;
|
2002-02-03 21:06:51 +00:00
|
|
|
while (frame) {
|
|
|
|
// stop if it is a MathML frame
|
|
|
|
nsIMathMLFrame* mathMLFrame;
|
|
|
|
frame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
|
|
|
nsPresentationData parentData;
|
2002-02-07 04:38:08 +00:00
|
|
|
mathMLFrame->GetPresentationData(parentData);
|
2002-02-03 21:06:51 +00:00
|
|
|
parentScriptLevel = parentData.scriptLevel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// stop if we reach the root <math> tag
|
2003-07-08 11:00:00 +00:00
|
|
|
nsIContent* content = frame->GetContent();
|
2002-04-02 03:57:56 +00:00
|
|
|
NS_ASSERTION(content, "dangling frame without a content node");
|
|
|
|
if (!content)
|
|
|
|
return NS_ERROR_FAILURE;
|
2003-11-19 01:20:56 +00:00
|
|
|
|
|
|
|
if (content->Tag() == nsMathMLAtoms::math) {
|
2002-02-03 21:06:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// mark the frame dirty, and continue to climb up
|
2003-07-08 11:00:00 +00:00
|
|
|
frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
|
|
|
|
frame = frame->GetParent();
|
2002-02-03 21:06:51 +00:00
|
|
|
}
|
2002-04-02 03:57:56 +00:00
|
|
|
NS_ASSERTION(frame, "bad MathML markup - could not find the top <math> element");
|
|
|
|
if (!frame)
|
|
|
|
return NS_OK;
|
2002-02-03 21:06:51 +00:00
|
|
|
|
|
|
|
// re-sync the presentation data and embellishment data of our children
|
2005-02-07 01:57:50 +00:00
|
|
|
RebuildAutomaticDataForChildren(frame);
|
2002-02-03 21:06:51 +00:00
|
|
|
|
2002-02-07 04:38:08 +00:00
|
|
|
// re-resolve the style data to sync any change of script sizes
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aParentFrame->GetFirstChild(nsnull);
|
2002-02-07 04:38:08 +00:00
|
|
|
while (childFrame) {
|
|
|
|
nsIMathMLFrame* mathMLFrame;
|
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
|
|
|
// propagate using the base method to make sure that the control
|
|
|
|
// is passed on to MathML frames that may be overloading the method
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->ReResolveScriptStyle(parentScriptLevel);
|
2002-02-07 04:38:08 +00:00
|
|
|
}
|
|
|
|
else {
|
2005-02-07 01:57:50 +00:00
|
|
|
PropagateScriptStyleFor(childFrame, parentScriptLevel);
|
2002-02-07 04:38:08 +00:00
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-02-07 04:38:08 +00:00
|
|
|
}
|
2002-02-03 21:06:51 +00:00
|
|
|
|
|
|
|
// Ask our parent frame to reflow us
|
2005-02-07 01:57:50 +00:00
|
|
|
return frame->ReflowDirtyChild(frame->GetPresContext()->PresShell(), nsnull);
|
2002-02-03 21:06:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// There are precise rules governing children of a MathML frame,
|
|
|
|
// and properties such as the scriptlevel depends on those rules.
|
|
|
|
// Hence for things to work, callers must use Append/Insert/etc wisely.
|
|
|
|
|
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::ChildListChanged(PRInt32 aModType)
|
2002-02-03 21:06:51 +00:00
|
|
|
{
|
|
|
|
if (aModType != nsIDOMMutationEvent::REMOVAL) {
|
|
|
|
// wrap any new foreign child that may have crept in
|
2005-02-07 01:57:50 +00:00
|
|
|
WrapForeignFrames();
|
2002-02-03 21:06:51 +00:00
|
|
|
}
|
2005-03-14 05:30:49 +00:00
|
|
|
|
|
|
|
// If this is an embellished frame we need to rebuild the
|
|
|
|
// embellished hierarchy by walking-up to the parent of the
|
|
|
|
// outermost embellished container.
|
|
|
|
nsIFrame* frame = this;
|
|
|
|
if (mEmbellishData.coreFrame) {
|
|
|
|
nsEmbellishData embellishData;
|
|
|
|
for (frame = mParent; frame; frame = frame->GetParent()) {
|
|
|
|
GetEmbellishDataFrom(frame, embellishData);
|
|
|
|
if (embellishData.coreFrame != mEmbellishData.coreFrame)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ReLayoutChildren(frame);
|
2002-02-03 21:06:51 +00:00
|
|
|
}
|
|
|
|
|
2002-01-25 06:48:30 +00:00
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::AppendFrames(nsIAtom* aListName,
|
2002-01-25 06:48:30 +00:00
|
|
|
nsIFrame* aFrameList)
|
|
|
|
{
|
|
|
|
if (aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (aFrameList) {
|
|
|
|
mFrames.AppendFrames(this, aFrameList);
|
2005-02-07 01:57:50 +00:00
|
|
|
return ChildListChanged(nsIDOMMutationEvent::ADDITION);
|
2002-01-25 06:48:30 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::InsertFrames(nsIAtom* aListName,
|
2002-01-25 06:48:30 +00:00
|
|
|
nsIFrame* aPrevFrame,
|
|
|
|
nsIFrame* aFrameList)
|
|
|
|
{
|
|
|
|
if (aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (aFrameList) {
|
|
|
|
// Insert frames after aPrevFrame
|
|
|
|
mFrames.InsertFrames(this, aPrevFrame, aFrameList);
|
2005-02-07 01:57:50 +00:00
|
|
|
return ChildListChanged(nsIDOMMutationEvent::ADDITION);
|
2002-01-25 06:48:30 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::RemoveFrame(nsIAtom* aListName,
|
2002-01-25 06:48:30 +00:00
|
|
|
nsIFrame* aOldFrame)
|
|
|
|
{
|
|
|
|
if (aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
2002-02-01 15:10:50 +00:00
|
|
|
// remove the child frame
|
2005-02-07 01:57:50 +00:00
|
|
|
mFrames.DestroyFrame(GetPresContext(), aOldFrame);
|
|
|
|
return ChildListChanged(nsIDOMMutationEvent::REMOVAL);
|
2002-01-25 06:48:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::ReplaceFrame(nsIAtom* aListName,
|
2002-01-25 06:48:30 +00:00
|
|
|
nsIFrame* aOldFrame,
|
|
|
|
nsIFrame* aNewFrame)
|
|
|
|
{
|
|
|
|
if (aListName || !aOldFrame || !aNewFrame) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
2002-02-01 15:10:50 +00:00
|
|
|
// Replace the old frame with the new frame in the list
|
2005-02-07 01:57:50 +00:00
|
|
|
mFrames.ReplaceFrame(this, aOldFrame, aNewFrame, PR_TRUE);
|
2002-02-01 15:10:50 +00:00
|
|
|
|
2005-02-07 01:57:50 +00:00
|
|
|
return ChildListChanged(nsIDOMMutationEvent::MODIFICATION);
|
2002-01-25 06:48:30 +00:00
|
|
|
}
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_IMETHODIMP
|
2005-09-07 16:49:21 +00:00
|
|
|
nsMathMLContainerFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
2001-02-23 16:10:51 +00:00
|
|
|
nsIAtom* aAttribute,
|
2003-07-11 21:16:12 +00:00
|
|
|
PRInt32 aModType)
|
2001-02-23 16:10:51 +00:00
|
|
|
{
|
2002-05-16 01:11:09 +00:00
|
|
|
if (aAttribute == nsMathMLAtoms::mathcolor_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::color_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::mathsize_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::fontsize_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::fontfamily_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::mathbackground_ ||
|
|
|
|
aAttribute == nsMathMLAtoms::background_) {
|
2004-12-31 03:00:21 +00:00
|
|
|
MapAttributesIntoCSS(GetPresContext(), this);
|
2002-05-16 01:11:09 +00:00
|
|
|
}
|
|
|
|
|
2004-12-31 01:13:27 +00:00
|
|
|
return ReflowDirtyChild(GetPresContext()->PresShell(), nsnull);
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
// We are an inline frame, so we handle dirty request like nsInlineFrame
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsMathMLContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
|
|
|
|
{
|
|
|
|
// The inline container frame does not handle the reflow
|
2001-02-23 16:10:51 +00:00
|
|
|
// request. It passes it up to its parent container.
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// If you don't already have dirty children,
|
|
|
|
if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
|
|
|
|
if (mParent) {
|
2001-02-23 16:10:51 +00:00
|
|
|
// Record that you are dirty and have dirty children
|
2001-02-02 14:27:38 +00:00
|
|
|
mState |= NS_FRAME_IS_DIRTY;
|
2001-02-23 16:10:51 +00:00
|
|
|
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
// Pass the reflow request up to the parent
|
2001-02-02 14:27:38 +00:00
|
|
|
mParent->ReflowDirtyChild(aPresShell, (nsIFrame*) this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ASSERTION(0, "No parent to pass the reflow request up to.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2004-07-31 23:15:21 +00:00
|
|
|
nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
aDesiredSize.width = aDesiredSize.height = 0;
|
|
|
|
aDesiredSize.ascent = aDesiredSize.descent = 0;
|
|
|
|
aDesiredSize.mBoundingMetrics.Clear();
|
|
|
|
|
|
|
|
// See if this is an incremental reflow
|
|
|
|
if (aReflowState.reason == eReflowReason_Incremental) {
|
|
|
|
#ifdef MATHML_NOISY_INCREMENTAL_REFLOW
|
|
|
|
printf("nsMathMLContainerFrame::Reflow:IncrementalReflow received by: ");
|
|
|
|
nsFrame::ListTag(stdout, this);
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////
|
|
|
|
// Reflow children
|
|
|
|
// Asking each child to cache its bounding metrics
|
|
|
|
|
|
|
|
nsReflowStatus childStatus;
|
|
|
|
nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight);
|
2003-01-09 14:26:32 +00:00
|
|
|
nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mComputeMEW,
|
2001-02-02 14:27:38 +00:00
|
|
|
aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS);
|
|
|
|
nsIFrame* childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2001-02-23 16:10:51 +00:00
|
|
|
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
|
|
|
|
childFrame, availSize);
|
|
|
|
rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
|
|
|
|
childReflowState, childStatus);
|
|
|
|
//NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// At this stage, the origin points of the children have no use, so we will use the
|
|
|
|
// origins as placeholders to store the child's ascent and descent. Later on,
|
|
|
|
// we should set the origins so as to overwrite what we are storing there now.
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetRect(nsRect(childDesiredSize.descent, childDesiredSize.ascent,
|
2001-02-23 16:10:51 +00:00
|
|
|
childDesiredSize.width, childDesiredSize.height));
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////
|
2001-02-23 16:10:51 +00:00
|
|
|
// If we are a container which is entitled to stretch its children, then we
|
2001-02-02 14:27:38 +00:00
|
|
|
// ask our stretchy children to stretch themselves
|
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
// The stretching of siblings of an embellished child is _deferred_ until
|
|
|
|
// after finishing the stretching of the embellished child - bug 117652
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) &&
|
2002-02-07 04:38:08 +00:00
|
|
|
(NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
|
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) {
|
2001-02-02 14:27:38 +00:00
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
// get the stretchy direction
|
2001-02-23 16:10:51 +00:00
|
|
|
nsStretchDirection stretchDir =
|
2002-02-07 04:38:08 +00:00
|
|
|
NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)
|
2002-01-02 05:32:33 +00:00
|
|
|
? NS_STRETCH_DIRECTION_VERTICAL
|
|
|
|
: NS_STRETCH_DIRECTION_HORIZONTAL;
|
|
|
|
|
|
|
|
// what size should we use to stretch our stretchy children
|
|
|
|
// We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet
|
|
|
|
// We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to
|
|
|
|
// include them in the caculations of the size of stretchy elements
|
|
|
|
nsBoundingMetrics containerSize;
|
2005-02-07 01:57:50 +00:00
|
|
|
GetPreferredStretchSize(*aReflowState.rendContext, 0, stretchDir,
|
|
|
|
containerSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
// fire the stretch on each child
|
|
|
|
childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2002-01-02 05:32:33 +00:00
|
|
|
nsIMathMLFrame* mathMLFrame;
|
2002-01-10 23:40:40 +00:00
|
|
|
childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
|
|
|
|
if (mathMLFrame) {
|
2002-01-02 05:32:33 +00:00
|
|
|
// retrieve the metrics that was stored at the previous pass
|
|
|
|
GetReflowAndBoundingMetricsFor(childFrame,
|
|
|
|
childDesiredSize, childDesiredSize.mBoundingMetrics);
|
|
|
|
|
2005-02-07 01:57:50 +00:00
|
|
|
mathMLFrame->Stretch(*aReflowState.rendContext, stretchDir,
|
|
|
|
containerSize, childDesiredSize);
|
2002-01-02 05:32:33 +00:00
|
|
|
// store the updated metrics
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetRect(nsRect(childDesiredSize.descent, childDesiredSize.ascent,
|
2002-01-02 05:32:33 +00:00
|
|
|
childDesiredSize.width, childDesiredSize.height));
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-09 14:26:32 +00:00
|
|
|
if (aDesiredSize.mComputeMEW) {
|
|
|
|
aDesiredSize.mMaxElementWidth = childDesiredSize.mMaxElementWidth;
|
|
|
|
}
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
/////////////
|
|
|
|
// Place children now by re-adjusting the origins to align the baselines
|
2005-02-07 01:57:50 +00:00
|
|
|
FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
2002-05-28 22:50:43 +00:00
|
|
|
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For MathML, the 'type' will be used to determine the spacing between frames
|
|
|
|
// Subclasses can override this method to return a 'type' that will give
|
|
|
|
// them a particular spacing
|
2003-10-31 20:19:18 +00:00
|
|
|
nsIAtom*
|
|
|
|
nsMathMLContainerFrame::GetType() const
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
|
|
|
// see if this is an embellished operator (mapped to 'Op' in TeX)
|
2005-09-06 23:47:01 +00:00
|
|
|
if (mEmbellishData.coreFrame) {
|
2003-10-31 20:19:18 +00:00
|
|
|
return mEmbellishData.coreFrame->GetType();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2002-08-16 21:36:31 +00:00
|
|
|
|
2005-09-06 23:47:01 +00:00
|
|
|
// if it has a prescribed base, just fetch the type from there
|
|
|
|
if (mPresentationData.baseFrame) {
|
|
|
|
return mPresentationData.baseFrame->GetType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// everything else is treated as ordinary (mapped to 'Ord' in TeX)
|
|
|
|
return nsMathMLAtoms::ordinaryMathMLFrame;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
2002-01-02 05:32:33 +00:00
|
|
|
enum eMathMLFrameType {
|
2001-02-02 14:27:38 +00:00
|
|
|
eMathMLFrameType_UNKNOWN = -1,
|
|
|
|
eMathMLFrameType_Ordinary,
|
2005-09-06 23:47:01 +00:00
|
|
|
eMathMLFrameType_OperatorOrdinary,
|
2002-08-12 23:30:35 +00:00
|
|
|
eMathMLFrameType_OperatorInvisible,
|
2005-09-06 23:47:01 +00:00
|
|
|
eMathMLFrameType_OperatorUserDefined,
|
|
|
|
eMathMLFrameType_Inner,
|
|
|
|
eMathMLFrameType_ItalicIdentifier,
|
|
|
|
eMathMLFrameType_UprightIdentifier,
|
|
|
|
eMathMLFrameType_COUNT
|
2001-02-02 14:27:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// see spacing table in Chapter 18, TeXBook (p.170)
|
2002-08-12 23:30:35 +00:00
|
|
|
// Our table isn't quite identical to TeX because operators have
|
|
|
|
// built-in values for lspace & rspace in the Operator Dictionary.
|
2005-09-06 23:47:01 +00:00
|
|
|
static PRInt32 kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] =
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
|
|
|
// in units of muspace.
|
|
|
|
// upper half of the byte is set if the
|
|
|
|
// spacing is not to be used for scriptlevel > 0
|
2005-09-06 23:47:01 +00:00
|
|
|
|
|
|
|
/* Ord OpOrd OpInv OpUsr Inner Italic Upright */
|
|
|
|
/*Ord */ {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
|
|
|
|
/*OpOrd*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
|
/*OpInv*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
|
/*OpUsr*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
|
|
|
|
/*Inner*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00},
|
|
|
|
/*Italic*/ {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01},
|
|
|
|
/*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01}
|
2001-02-02 14:27:38 +00:00
|
|
|
};
|
|
|
|
|
2002-08-13 00:52:38 +00:00
|
|
|
#define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_) \
|
2002-08-12 23:30:35 +00:00
|
|
|
/* no space if there is a frame that we know nothing about */ \
|
2002-08-13 00:52:38 +00:00
|
|
|
if (frametype1_ == eMathMLFrameType_UNKNOWN || \
|
|
|
|
frametype2_ == eMathMLFrameType_UNKNOWN) \
|
|
|
|
space_ = 0; \
|
2002-08-12 23:30:35 +00:00
|
|
|
else { \
|
2002-08-13 00:52:38 +00:00
|
|
|
space_ = kInterFrameSpacingTable[frametype1_][frametype2_]; \
|
|
|
|
space_ = (scriptlevel_ > 0 && (space_ & 0xF0)) \
|
2002-08-12 23:30:35 +00:00
|
|
|
? 0 /* spacing is disabled */ \
|
2002-08-13 00:52:38 +00:00
|
|
|
: space_ & 0x0F; \
|
2002-08-12 23:30:35 +00:00
|
|
|
} \
|
|
|
|
|
2002-08-13 00:52:38 +00:00
|
|
|
#define MAP_FRAMETYPE(atomtype_, enumtype_) \
|
|
|
|
if (atomtype_ == nsMathMLAtoms::ordinaryMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_Ordinary; \
|
2005-09-06 23:47:01 +00:00
|
|
|
else if (atomtype_ == nsMathMLAtoms::operatorOrdinaryMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_OperatorOrdinary; \
|
2002-08-13 00:52:38 +00:00
|
|
|
else if (atomtype_ == nsMathMLAtoms::operatorInvisibleMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_OperatorInvisible; \
|
2005-09-06 23:47:01 +00:00
|
|
|
else if (atomtype_ == nsMathMLAtoms::operatorUserDefinedMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_OperatorUserDefined; \
|
|
|
|
else if (atomtype_ == nsMathMLAtoms::innerMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_Inner; \
|
|
|
|
else if (atomtype_ == nsMathMLAtoms::italicIdentifierMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_ItalicIdentifier; \
|
|
|
|
else if (atomtype_ == nsMathMLAtoms::uprightIdentifierMathMLFrame) \
|
|
|
|
enumtype_ = eMathMLFrameType_UprightIdentifier; \
|
2002-08-12 23:30:35 +00:00
|
|
|
else \
|
2002-08-13 00:52:38 +00:00
|
|
|
enumtype_ = eMathMLFrameType_UNKNOWN;
|
2002-08-12 23:30:35 +00:00
|
|
|
|
|
|
|
// This function computes the inter-space between two frames. However,
|
|
|
|
// since invisible operators need special treatment, the inter-space may
|
|
|
|
// be delayed when an invisible operator is encountered. In this case,
|
|
|
|
// the function will carry the inter-space forward until it is determined
|
|
|
|
// that it can be applied properly (i.e., until we encounter a visible
|
|
|
|
// frame where to decide whether to accept or reject the inter-space).
|
|
|
|
// aFromFrameType: remembers the frame when the carry-forward initiated.
|
|
|
|
// aCarrySpace: keeps track of the inter-space that is delayed.
|
|
|
|
// @returns: current inter-space (which is 0 when the true inter-space is
|
|
|
|
// delayed -- and thus has no effect since the frame is invisible anyway).
|
2001-02-02 14:27:38 +00:00
|
|
|
static nscoord
|
2002-08-12 23:30:35 +00:00
|
|
|
GetInterFrameSpacing(PRInt32 aScriptLevel,
|
|
|
|
nsIAtom* aFirstFrameType,
|
|
|
|
nsIAtom* aSecondFrameType,
|
|
|
|
eMathMLFrameType* aFromFrameType, // IN/OUT
|
|
|
|
PRInt32* aCarrySpace) // IN/OUT
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
2002-08-12 23:30:35 +00:00
|
|
|
eMathMLFrameType firstType, secondType;
|
|
|
|
MAP_FRAMETYPE(aFirstFrameType, firstType);
|
|
|
|
MAP_FRAMETYPE(aSecondFrameType, secondType);
|
|
|
|
|
|
|
|
PRInt32 space;
|
|
|
|
GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
|
|
|
|
|
|
|
|
// feedback control to avoid the inter-space to be added when not necessary
|
|
|
|
if (secondType == eMathMLFrameType_OperatorInvisible) {
|
|
|
|
// see if we should start to carry the space forward until we
|
|
|
|
// encounter a visible frame
|
|
|
|
if (*aFromFrameType == eMathMLFrameType_UNKNOWN) {
|
|
|
|
*aFromFrameType = firstType;
|
|
|
|
*aCarrySpace = space;
|
|
|
|
}
|
|
|
|
// keep carrying *aCarrySpace forward, while returning 0 for this stage
|
|
|
|
space = 0;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2002-08-12 23:30:35 +00:00
|
|
|
else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) {
|
|
|
|
// no carry-forward anymore, get the real inter-space between
|
|
|
|
// the two frames of interest
|
2005-09-06 23:47:01 +00:00
|
|
|
|
|
|
|
firstType = *aFromFrameType;
|
|
|
|
|
|
|
|
// But... the invisible operator that we encountered earlier could
|
|
|
|
// be sitting between italic and upright identifiers, e.g.,
|
|
|
|
//
|
|
|
|
// 1. <mi>sin</mi> <mo>⁡</mo> <mi>x</mi>
|
|
|
|
// 2. <mi>x</mi> <mo>&InvisibileTime;</mo> <mi>sin</mi>
|
|
|
|
//
|
|
|
|
// the trick to get the inter-space in either situation
|
|
|
|
// is to promote "<mi>sin</mi><mo>⁡</mo>" and
|
|
|
|
// "<mo>&InvisibileTime;</mo><mi>sin</mi>" to user-defined operators...
|
|
|
|
if (firstType == eMathMLFrameType_UprightIdentifier) {
|
|
|
|
firstType = eMathMLFrameType_OperatorUserDefined;
|
|
|
|
}
|
|
|
|
else if (secondType == eMathMLFrameType_UprightIdentifier) {
|
|
|
|
secondType = eMathMLFrameType_OperatorUserDefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
|
2002-08-12 23:30:35 +00:00
|
|
|
|
|
|
|
// Now, we have two values: the computed space and the space that
|
|
|
|
// has been carried forward until now. Which value do we pick?
|
|
|
|
// If the second type is an operator (e.g., fence), it already has
|
|
|
|
// built-in lspace & rspace, so we let them win. Otherwise we pick
|
|
|
|
// the max between the two values that we have.
|
2005-09-06 23:47:01 +00:00
|
|
|
if (secondType != eMathMLFrameType_OperatorOrdinary &&
|
2002-08-12 23:30:35 +00:00
|
|
|
space < *aCarrySpace)
|
|
|
|
space = *aCarrySpace;
|
|
|
|
|
|
|
|
// reset everything now that the carry-forward is done
|
|
|
|
*aFromFrameType = eMathMLFrameType_UNKNOWN;
|
|
|
|
*aCarrySpace = 0;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2002-08-12 23:30:35 +00:00
|
|
|
|
|
|
|
return space;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::Place(nsIRenderingContext& aRenderingContext,
|
2001-02-02 14:27:38 +00:00
|
|
|
PRBool aPlaceOrigin,
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize)
|
|
|
|
{
|
|
|
|
// these are needed in case this frame is empty (i.e., we don't enter the loop)
|
|
|
|
aDesiredSize.width = aDesiredSize.height = 0;
|
|
|
|
aDesiredSize.ascent = aDesiredSize.descent = 0;
|
|
|
|
mBoundingMetrics.Clear();
|
|
|
|
|
|
|
|
// cache away thinspace
|
2003-05-15 03:42:21 +00:00
|
|
|
const nsStyleFont* font = GetStyleFont();
|
2001-05-31 22:19:43 +00:00
|
|
|
nscoord thinSpace = NSToCoordRound(float(font->mFont.size)*float(3) / float(18));
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
PRInt32 count = 0;
|
2002-08-12 23:30:35 +00:00
|
|
|
PRInt32 carrySpace = 0;
|
|
|
|
eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN;
|
2001-02-02 14:27:38 +00:00
|
|
|
nsHTMLReflowMetrics childSize (nsnull);
|
|
|
|
nsBoundingMetrics bmChild;
|
2001-02-23 16:10:51 +00:00
|
|
|
nscoord leftCorrection = 0, italicCorrection = 0;
|
2003-10-31 20:19:18 +00:00
|
|
|
nsIAtom* prevFrameType = nsnull;
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
nsIFrame* childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2003-10-31 20:19:18 +00:00
|
|
|
nsIAtom* childFrameType = childFrame->GetType();
|
2001-02-23 16:10:51 +00:00
|
|
|
GetReflowAndBoundingMetricsFor(childFrame, childSize, bmChild);
|
|
|
|
GetItalicCorrection(bmChild, leftCorrection, italicCorrection);
|
|
|
|
if (0 == count) {
|
|
|
|
aDesiredSize.ascent = childSize.ascent;
|
|
|
|
aDesiredSize.descent = childSize.descent;
|
|
|
|
mBoundingMetrics = bmChild;
|
|
|
|
// update to include the left correction
|
2002-02-27 01:35:27 +00:00
|
|
|
// but leave <msqrt> alone because the sqrt glyph itself is there first
|
2003-11-19 01:20:56 +00:00
|
|
|
|
|
|
|
if (mContent->Tag() == nsMathMLAtoms::msqrt_)
|
2002-02-27 01:35:27 +00:00
|
|
|
leftCorrection = 0;
|
|
|
|
else
|
|
|
|
mBoundingMetrics.leftBearing += leftCorrection;
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (aDesiredSize.descent < childSize.descent)
|
2001-02-02 14:27:38 +00:00
|
|
|
aDesiredSize.descent = childSize.descent;
|
2001-02-23 16:10:51 +00:00
|
|
|
if (aDesiredSize.ascent < childSize.ascent)
|
|
|
|
aDesiredSize.ascent = childSize.ascent;
|
|
|
|
// add inter frame spacing
|
|
|
|
nscoord space = GetInterFrameSpacing(mPresentationData.scriptLevel,
|
2002-08-12 23:30:35 +00:00
|
|
|
prevFrameType, childFrameType, &fromFrameType, &carrySpace);
|
2001-02-23 16:10:51 +00:00
|
|
|
mBoundingMetrics.width += space * thinSpace;
|
|
|
|
// add the child size
|
|
|
|
mBoundingMetrics += bmChild;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
count++;
|
|
|
|
prevFrameType = childFrameType;
|
|
|
|
// add left correction -- this fixes the problem of the italic 'f'
|
|
|
|
// e.g., <mo>q</mo> <mi>f</mi> <mo>I</mo>
|
|
|
|
mBoundingMetrics.width += leftCorrection;
|
|
|
|
mBoundingMetrics.rightBearing += leftCorrection;
|
|
|
|
// add the italic correction at the end (including the last child).
|
|
|
|
// this gives a nice gap between math and non-math frames, and still
|
|
|
|
// gives the same math inter-spacing in case this frame connects to
|
|
|
|
// another math frame
|
|
|
|
mBoundingMetrics.width += italicCorrection;
|
|
|
|
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
aDesiredSize.width = mBoundingMetrics.width;
|
|
|
|
aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
|
|
|
|
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
|
|
|
|
|
|
|
mReference.x = 0;
|
|
|
|
mReference.y = aDesiredSize.ascent;
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// Place Children
|
|
|
|
|
|
|
|
if (aPlaceOrigin) {
|
|
|
|
count = 0;
|
|
|
|
nscoord dx = 0, dy = 0;
|
|
|
|
italicCorrection = 0;
|
2002-08-12 23:30:35 +00:00
|
|
|
carrySpace = 0;
|
|
|
|
fromFrameType = eMathMLFrameType_UNKNOWN;
|
2001-02-02 14:27:38 +00:00
|
|
|
childFrame = mFrames.FirstChild();
|
|
|
|
while (childFrame) {
|
2003-10-31 20:19:18 +00:00
|
|
|
nsIAtom* childFrameType = childFrame->GetType();
|
2001-02-23 16:10:51 +00:00
|
|
|
GetReflowAndBoundingMetricsFor(childFrame, childSize, bmChild);
|
2002-02-27 01:35:27 +00:00
|
|
|
GetItalicCorrection(bmChild, leftCorrection, italicCorrection);
|
2001-02-23 16:10:51 +00:00
|
|
|
dy = aDesiredSize.ascent - childSize.ascent;
|
2002-02-27 01:35:27 +00:00
|
|
|
if (0 == count) {
|
|
|
|
// for <msqrt>, the sqrt glyph itself is there first
|
2003-11-19 01:20:56 +00:00
|
|
|
|
|
|
|
if (mContent->Tag() == nsMathMLAtoms::msqrt_)
|
2002-02-27 01:35:27 +00:00
|
|
|
leftCorrection = 0;
|
|
|
|
}
|
|
|
|
else {
|
2001-02-23 16:10:51 +00:00
|
|
|
// add inter frame spacing
|
|
|
|
nscoord space = GetInterFrameSpacing(mPresentationData.scriptLevel,
|
2002-08-12 23:30:35 +00:00
|
|
|
prevFrameType, childFrameType, &fromFrameType, &carrySpace);
|
2001-02-23 16:10:51 +00:00
|
|
|
dx += space * thinSpace;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
count++;
|
|
|
|
prevFrameType = childFrameType;
|
|
|
|
// add left correction
|
|
|
|
dx += leftCorrection;
|
2005-02-07 01:57:50 +00:00
|
|
|
FinishReflowChild(childFrame, GetPresContext(), nsnull, childSize,
|
|
|
|
dx, dy, 0);
|
2001-02-23 16:10:51 +00:00
|
|
|
// add child size + italic correction
|
|
|
|
dx += bmChild.width + italicCorrection;
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-08-12 23:30:35 +00:00
|
|
|
// helpers to fix the inter-spacing when <math> is the only parent
|
2001-02-23 16:10:51 +00:00
|
|
|
// e.g., it fixes <math> <mi>f</mi> <mo>q</mo> <mi>f</mi> <mo>I</mo> </math>
|
2002-08-12 23:30:35 +00:00
|
|
|
|
|
|
|
static nscoord
|
2005-02-07 01:57:50 +00:00
|
|
|
GetInterFrameSpacingFor(PRInt32 aScriptLevel,
|
2002-08-12 23:30:35 +00:00
|
|
|
nsIFrame* aParentFrame,
|
|
|
|
nsIFrame* aChildFrame)
|
|
|
|
{
|
2004-01-09 14:20:53 +00:00
|
|
|
nsIFrame* childFrame = aParentFrame->GetFirstChild(nsnull);
|
2002-08-12 23:30:35 +00:00
|
|
|
if (!childFrame || aChildFrame == childFrame)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
PRInt32 carrySpace = 0;
|
|
|
|
eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN;
|
2003-10-31 20:19:18 +00:00
|
|
|
nsIAtom* childFrameType = childFrame->GetType();
|
|
|
|
nsIAtom* prevFrameType = nsnull;
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-08-12 23:30:35 +00:00
|
|
|
while (childFrame) {
|
|
|
|
prevFrameType = childFrameType;
|
2003-10-31 20:19:18 +00:00
|
|
|
childFrameType = childFrame->GetType();
|
2002-08-12 23:30:35 +00:00
|
|
|
nscoord space = GetInterFrameSpacing(aScriptLevel,
|
|
|
|
prevFrameType, childFrameType, &fromFrameType, &carrySpace);
|
|
|
|
if (aChildFrame == childFrame) {
|
|
|
|
// get thinspace
|
2003-02-22 00:32:13 +00:00
|
|
|
nsStyleContext* parentContext = aParentFrame->GetStyleContext();
|
2003-05-15 03:42:21 +00:00
|
|
|
const nsStyleFont* font = parentContext->GetStyleFont();
|
2002-08-12 23:30:35 +00:00
|
|
|
nscoord thinSpace = NSToCoordRound(float(font->mFont.size)*float(3) / float(18));
|
|
|
|
// we are done
|
|
|
|
return space * thinSpace;
|
|
|
|
}
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame = childFrame->GetNextSibling();
|
2002-08-12 23:30:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_NOTREACHED("child not in the childlist of its parent");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
nsresult
|
2005-02-07 01:57:50 +00:00
|
|
|
nsMathMLContainerFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
|
2001-02-23 16:10:51 +00:00
|
|
|
{
|
2003-07-08 11:00:00 +00:00
|
|
|
nsIContent* parentContent = mParent->GetContent();
|
2003-11-19 01:20:56 +00:00
|
|
|
nsIAtom *parentTag = parentContent->Tag();
|
2002-08-12 23:30:35 +00:00
|
|
|
if (parentTag == nsMathMLAtoms::math ||
|
|
|
|
parentTag == nsMathMLAtoms::mtd_) {
|
2005-02-07 01:57:50 +00:00
|
|
|
nscoord gap = GetInterFrameSpacingFor(mPresentationData.scriptLevel,
|
|
|
|
mParent, this);
|
2001-02-23 16:10:51 +00:00
|
|
|
// add our own italic correction
|
2002-08-12 23:30:35 +00:00
|
|
|
nscoord leftCorrection = 0, italicCorrection = 0;
|
2001-02-23 16:10:51 +00:00
|
|
|
GetItalicCorrection(mBoundingMetrics, leftCorrection, italicCorrection);
|
2001-12-18 10:11:42 +00:00
|
|
|
gap += leftCorrection;
|
|
|
|
// see if we should shift our children to account for the correction
|
|
|
|
if (gap) {
|
2002-08-12 23:30:35 +00:00
|
|
|
nsIFrame* childFrame = mFrames.FirstChild();
|
2001-12-18 10:11:42 +00:00
|
|
|
while (childFrame) {
|
2003-07-08 11:00:00 +00:00
|
|
|
childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0));
|
|
|
|
childFrame = childFrame->GetNextSibling();
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
2001-12-18 10:11:42 +00:00
|
|
|
mBoundingMetrics.leftBearing += gap;
|
|
|
|
mBoundingMetrics.rightBearing += gap;
|
|
|
|
mBoundingMetrics.width += gap;
|
|
|
|
aDesiredSize.width += gap;
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
2001-12-18 10:11:42 +00:00
|
|
|
mBoundingMetrics.width += italicCorrection;
|
|
|
|
aDesiredSize.width += italicCorrection;
|
2001-02-23 16:10:51 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
//==========================
|
2002-02-01 15:10:50 +00:00
|
|
|
|
2001-02-02 14:27:38 +00:00
|
|
|
nsresult
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
nsMathMLmathBlockFrame* it = new (aPresShell) nsMathMLmathBlockFrame;
|
2001-02-02 14:27:38 +00:00
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
*aNewFrame = it;
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-02-01 15:10:50 +00:00
|
|
|
//==========================
|
|
|
|
|
2001-02-23 16:10:51 +00:00
|
|
|
nsresult
|
|
|
|
NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
2001-02-02 14:27:38 +00:00
|
|
|
{
|
2001-02-23 16:10:51 +00:00
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
nsMathMLmathInlineFrame* it = new (aPresShell) nsMathMLmathInlineFrame;
|
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2001-02-02 14:27:38 +00:00
|
|
|
}
|
2001-02-23 16:10:51 +00:00
|
|
|
*aNewFrame = it;
|
2001-02-02 14:27:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|