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 ***** */
43 #include "nsPresContext.h"
44 #include "nsStyleContext.h"
45 #include "nsStyleConsts.h"
46 #include "nsIRenderingContext.h"
47 #include "nsIFontMetrics.h"
49 #include "nsMathMLmsupFrame.h"
52 // <msup> -- attach a superscript to a base - implementation
56 NS_NewMathMLmsupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
58 return new (aPresShell
) nsMathMLmsupFrame(aContext
);
61 nsMathMLmsupFrame::~nsMathMLmsupFrame()
66 nsMathMLmsupFrame::TransmitAutomaticData()
68 // if our base is an embellished operator, its flags bubble to us
69 mPresentationData
.baseFrame
= mFrames
.FirstChild();
70 GetEmbellishDataFrom(mPresentationData
.baseFrame
, mEmbellishData
);
73 // The <msup> element increments scriptlevel by 1, and sets displaystyle to
74 // "false", within superscript, but leaves both attributes unchanged within base.
75 // 2. The TeXbook (Ch 17. p.141) says the superscript *inherits* the compression,
76 // so we don't set the compression flag. Our parent will propagate its own.
77 UpdatePresentationDataFromChildAt(1, -1,
78 ~NS_MATHML_DISPLAYSTYLE
,
79 NS_MATHML_DISPLAYSTYLE
);
84 /* virtual */ nsresult
85 nsMathMLmsupFrame::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 superscriptshift attribute is there
94 nscoord supScriptShift
= 0;
95 GetAttribute(mContent
, mPresentationData
.mstyle
,
96 nsGkAtoms::superscriptshift_
, value
);
97 if (!value
.IsEmpty()) {
99 if (ParseNumericValue(value
, cssValue
) && cssValue
.IsLengthUnit()) {
100 supScriptShift
= CalcLength(PresContext(), mStyleContext
, cssValue
);
104 return nsMathMLmsupFrame::PlaceSuperScript(PresContext(),
113 // exported routine that both mover and msup share.
114 // mover uses this when movablelimits is set.
116 nsMathMLmsupFrame::PlaceSuperScript(nsPresContext
* aPresContext
,
117 nsIRenderingContext
& aRenderingContext
,
119 nsHTMLReflowMetrics
& aDesiredSize
,
120 nsMathMLContainerFrame
* aFrame
,
121 nscoord aUserSupScriptShift
,
122 nscoord aScriptSpace
)
124 // force the scriptSpace to be at least 1 pixel
125 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
126 aScriptSpace
= PR_MAX(onePixel
, aScriptSpace
);
128 ////////////////////////////////////
129 // Get the children's desired sizes
131 nsHTMLReflowMetrics baseSize
;
132 nsHTMLReflowMetrics supScriptSize
;
133 nsBoundingMetrics bmBase
, bmSupScript
;
134 nsIFrame
* supScriptFrame
= nsnull
;
135 nsIFrame
* baseFrame
= aFrame
->GetFirstChild(nsnull
);
137 supScriptFrame
= baseFrame
->GetNextSibling();
138 if (!baseFrame
|| !supScriptFrame
|| supScriptFrame
->GetNextSibling()) {
139 // report an error, encourage people to get their markups in order
140 return aFrame
->ReflowError(aRenderingContext
, aDesiredSize
);
142 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
143 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
, bmSupScript
);
145 // get the supdrop from the supscript font
147 GetSupDropFromChild(supScriptFrame
, supDrop
);
148 // parameter u, Rule 18a, App. G, TeXbook
149 nscoord minSupScriptShift
= bmBase
.ascent
- supDrop
;
154 // get min supscript shift limit from x-height
155 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
157 nsCOMPtr
<nsIFontMetrics
> fm
=
158 aPresContext
->GetMetricsFor(baseFrame
->GetStyleFont()->mFont
);
160 fm
->GetXHeight (xHeight
);
161 nscoord minShiftFromXHeight
= (nscoord
)
162 (bmSupScript
.descent
+ (1.0f
/4.0f
) * xHeight
);
163 nscoord italicCorrection
;
164 GetItalicCorrection(bmBase
, italicCorrection
);
166 // supScriptShift{1,2,3}
167 // = minimum amount to shift the supscript up
168 // = sup{1,2,3} in TeX
169 // supScriptShift1 = superscriptshift attribute * x-height
170 // Note that there are THREE values for supscript shifts depending
171 // on the current style
172 nscoord supScriptShift1
, supScriptShift2
, supScriptShift3
;
173 // Set supScriptShift{1,2,3} default from font
174 GetSupScriptShifts (fm
, supScriptShift1
, supScriptShift2
, supScriptShift3
);
176 if (0 < aUserSupScriptShift
) {
177 // the user has set the superscriptshift attribute
178 float scaler2
= ((float) supScriptShift2
) / supScriptShift1
;
179 float scaler3
= ((float) supScriptShift3
) / supScriptShift1
;
181 PR_MAX(supScriptShift1
, aUserSupScriptShift
);
182 supScriptShift2
= NSToCoordRound(scaler2
* supScriptShift1
);
183 supScriptShift3
= NSToCoordRound(scaler3
* supScriptShift1
);
186 // get sup script shift depending on current script level and display style
187 // Rule 18c, App. G, TeXbook
188 nscoord supScriptShift
;
189 nsPresentationData presentationData
;
190 aFrame
->GetPresentationData (presentationData
);
191 if ( aFrame
->GetStyleFont()->mScriptLevel
== 0 &&
192 NS_MATHML_IS_DISPLAYSTYLE(presentationData
.flags
) &&
193 !NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
194 // Style D in TeXbook
195 supScriptShift
= supScriptShift1
;
197 else if (NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
198 // Style C' in TeXbook = D',T',S',SS'
199 supScriptShift
= supScriptShift3
;
202 // everything else = T,S,SS
203 supScriptShift
= supScriptShift2
;
206 // get actual supscriptshift to be used
207 // Rule 18c, App. G, TeXbook
208 nscoord actualSupScriptShift
=
209 PR_MAX(minSupScriptShift
,PR_MAX(supScriptShift
,minShiftFromXHeight
));
212 nsBoundingMetrics boundingMetrics
;
213 boundingMetrics
.ascent
=
214 PR_MAX(bmBase
.ascent
, (bmSupScript
.ascent
+ actualSupScriptShift
));
215 boundingMetrics
.descent
=
216 PR_MAX(bmBase
.descent
, (bmSupScript
.descent
- actualSupScriptShift
));
218 // leave aScriptSpace after superscript
219 // add italicCorrection between base and superscript
220 // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we
221 // estimate the italic creation ourselves and it isn't the same as TeX
222 italicCorrection
+= onePixel
;
223 boundingMetrics
.width
= bmBase
.width
+ italicCorrection
+
224 bmSupScript
.width
+ aScriptSpace
;
225 boundingMetrics
.leftBearing
= bmBase
.leftBearing
;
226 boundingMetrics
.rightBearing
= bmBase
.width
+ italicCorrection
+
227 bmSupScript
.rightBearing
;
228 aFrame
->SetBoundingMetrics(boundingMetrics
);
231 aDesiredSize
.ascent
=
232 PR_MAX(baseSize
.ascent
, (supScriptSize
.ascent
+ actualSupScriptShift
));
233 aDesiredSize
.height
= aDesiredSize
.ascent
+
234 PR_MAX(baseSize
.height
- baseSize
.ascent
,
235 (supScriptSize
.height
- supScriptSize
.ascent
- actualSupScriptShift
));
236 aDesiredSize
.width
= boundingMetrics
.width
;
237 aDesiredSize
.mBoundingMetrics
= boundingMetrics
;
239 aFrame
->SetReference(nsPoint(0, aDesiredSize
.ascent
));
243 // now place the base ...
244 dx
= 0; dy
= aDesiredSize
.ascent
- baseSize
.ascent
;
245 FinishReflowChild (baseFrame
, aPresContext
, nsnull
, baseSize
, dx
, dy
, 0);
247 dx
= bmBase
.width
+ italicCorrection
;
248 dy
= aDesiredSize
.ascent
- (supScriptSize
.ascent
+ actualSupScriptShift
);
249 FinishReflowChild (supScriptFrame
, aPresContext
, nsnull
, supScriptSize
, dx
, dy
, 0);