1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla MathML Project.
17 * The Initial Developer of the Original Code is
18 * The University Of Queensland.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
23 * Roger B. Sidje <rbs@maths.uq.edu.au>
24 * David J. Fiddes <D.J.Fiddes@hw.ac.uk>
25 * Shyjan Mahamud <mahamud@cs.cmu.edu> (added TeX rendering rules)
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
44 #include "nsPresContext.h"
45 #include "nsStyleContext.h"
46 #include "nsStyleConsts.h"
47 #include "nsIRenderingContext.h"
48 #include "nsIFontMetrics.h"
50 #include "nsMathMLmsubFrame.h"
53 // <msub> -- attach a subscript to a base - implementation
57 NS_NewMathMLmsubFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
59 return new (aPresShell
) nsMathMLmsubFrame(aContext
);
62 nsMathMLmsubFrame::~nsMathMLmsubFrame()
67 nsMathMLmsubFrame::TransmitAutomaticData()
69 // if our base is an embellished operator, let its state bubble to us
70 mPresentationData
.baseFrame
= mFrames
.FirstChild();
71 GetEmbellishDataFrom(mPresentationData
.baseFrame
, mEmbellishData
);
74 // The <msub> element increments scriptlevel by 1, and sets displaystyle to
75 // "false", within subscript, but leaves both attributes unchanged within base.
76 // 2. The TeXbook (Ch 17. p.141) says the subscript is compressed
77 UpdatePresentationDataFromChildAt(1, -1,
78 ~NS_MATHML_DISPLAYSTYLE
| NS_MATHML_COMPRESSED
,
79 NS_MATHML_DISPLAYSTYLE
| NS_MATHML_COMPRESSED
);
84 /* virtual */ nsresult
85 nsMathMLmsubFrame::Place (nsIRenderingContext
& aRenderingContext
,
87 nsHTMLReflowMetrics
& aDesiredSize
)
89 // extra spacing after sup/subscript
90 nscoord scriptSpace
= PresContext()->PointsToAppUnits(0.5f
); // 0.5pt as in plain TeX
92 // check if the subscriptshift attribute is there
93 nscoord subScriptShift
= 0;
95 GetAttribute(mContent
, mPresentationData
.mstyle
,
96 nsGkAtoms::subscriptshift_
, value
);
97 if (!value
.IsEmpty()) {
99 if (ParseNumericValue(value
, cssValue
) && cssValue
.IsLengthUnit()) {
100 subScriptShift
= CalcLength(PresContext(), mStyleContext
, cssValue
);
104 return nsMathMLmsubFrame::PlaceSubScript(PresContext(),
113 // exported routine that both munder and msub share.
114 // munder uses this when movablelimits is set.
116 nsMathMLmsubFrame::PlaceSubScript (nsPresContext
* aPresContext
,
117 nsIRenderingContext
& aRenderingContext
,
119 nsHTMLReflowMetrics
& aDesiredSize
,
120 nsMathMLContainerFrame
* aFrame
,
121 nscoord aUserSubScriptShift
,
122 nscoord aScriptSpace
)
124 // force the scriptSpace to be atleast 1 pixel
125 aScriptSpace
= PR_MAX(nsPresContext::CSSPixelsToAppUnits(1), aScriptSpace
);
127 ////////////////////////////////////
128 // Get the children's desired sizes
130 nsBoundingMetrics bmBase
, bmSubScript
;
131 nsHTMLReflowMetrics baseSize
;
132 nsHTMLReflowMetrics subScriptSize
;
133 nsIFrame
* baseFrame
= aFrame
->GetFirstChild(nsnull
);
134 nsIFrame
* subScriptFrame
= nsnull
;
136 subScriptFrame
= baseFrame
->GetNextSibling();
137 if (!baseFrame
|| !subScriptFrame
|| subScriptFrame
->GetNextSibling()) {
138 // report an error, encourage people to get their markups in order
139 return aFrame
->ReflowError(aRenderingContext
, aDesiredSize
);
141 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
142 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
, bmSubScript
);
144 // get the subdrop from the subscript font
146 GetSubDropFromChild(subScriptFrame
, subDrop
);
147 // parameter v, Rule 18a, App. G, TeXbook
148 nscoord minSubScriptShift
= bmBase
.descent
+ subDrop
;
153 // get min subscript shift limit from x-height
154 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
156 nsCOMPtr
<nsIFontMetrics
> fm
=
157 aPresContext
->GetMetricsFor(baseFrame
->GetStyleFont()->mFont
);
159 fm
->GetXHeight (xHeight
);
160 nscoord minShiftFromXHeight
= (nscoord
)
161 (bmSubScript
.ascent
- (4.0f
/5.0f
) * xHeight
);
164 // = minimum amount to shift the subscript down set by user or from the font
166 // = subscriptshift attribute * x-height
167 nscoord subScriptShift
, dummy
;
168 // get subScriptShift default from font
169 GetSubScriptShifts (fm
, subScriptShift
, dummy
);
172 PR_MAX(subScriptShift
, aUserSubScriptShift
);
174 // get actual subscriptshift to be used
175 // Rule 18b, App. G, TeXbook
176 nscoord actualSubScriptShift
=
177 PR_MAX(minSubScriptShift
,PR_MAX(subScriptShift
,minShiftFromXHeight
));
178 // get bounding box for base + subscript
179 nsBoundingMetrics boundingMetrics
;
180 boundingMetrics
.ascent
=
181 PR_MAX(bmBase
.ascent
, bmSubScript
.ascent
- actualSubScriptShift
);
182 boundingMetrics
.descent
=
183 PR_MAX(bmBase
.descent
, bmSubScript
.descent
+ actualSubScriptShift
);
185 // add aScriptSpace to the subscript's width
186 boundingMetrics
.width
= bmBase
.width
+ bmSubScript
.width
+ aScriptSpace
;
187 boundingMetrics
.leftBearing
= bmBase
.leftBearing
;
188 boundingMetrics
.rightBearing
= PR_MAX(bmBase
.rightBearing
, bmBase
.width
+
189 PR_MAX(bmSubScript
.width
+ aScriptSpace
, bmSubScript
.rightBearing
));
190 aFrame
->SetBoundingMetrics (boundingMetrics
);
193 aDesiredSize
.ascent
=
194 PR_MAX(baseSize
.ascent
, subScriptSize
.ascent
- actualSubScriptShift
);
195 aDesiredSize
.height
= aDesiredSize
.ascent
+
196 PR_MAX(baseSize
.height
- baseSize
.ascent
,
197 subScriptSize
.height
- subScriptSize
.ascent
+ actualSubScriptShift
);
198 aDesiredSize
.width
= boundingMetrics
.width
;
199 aDesiredSize
.mBoundingMetrics
= boundingMetrics
;
201 aFrame
->SetReference(nsPoint(0, aDesiredSize
.ascent
));
205 // now place the base ...
206 dx
= 0; dy
= aDesiredSize
.ascent
- baseSize
.ascent
;
207 FinishReflowChild (baseFrame
, aPresContext
, nsnull
, baseSize
, dx
, dy
, 0);
210 dy
= aDesiredSize
.ascent
- (subScriptSize
.ascent
- actualSubScriptShift
);
211 FinishReflowChild (subScriptFrame
, aPresContext
, nsnull
, subScriptSize
, dx
, dy
, 0);