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 "nsMathMLmsubsupFrame.h"
53 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
57 NS_NewMathMLmsubsupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
59 return new (aPresShell
) nsMathMLmsubsupFrame(aContext
);
62 nsMathMLmsubsupFrame::~nsMathMLmsubsupFrame()
67 nsMathMLmsubsupFrame::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 <msubsup> element increments scriptlevel by 1, and sets displaystyle to
75 // "false", within subscript and superscript, but leaves both attributes
76 // unchanged within base.
77 // 2. The TeXbook (Ch 17. p.141) says the superscript inherits the compression
78 // while the subscript is compressed
79 UpdatePresentationDataFromChildAt(1, -1,
80 ~NS_MATHML_DISPLAYSTYLE
,
81 NS_MATHML_DISPLAYSTYLE
);
82 UpdatePresentationDataFromChildAt(1, 1,
84 NS_MATHML_COMPRESSED
);
89 /* virtual */ nsresult
90 nsMathMLmsubsupFrame::Place(nsIRenderingContext
& aRenderingContext
,
92 nsHTMLReflowMetrics
& aDesiredSize
)
94 // extra spacing between base and sup/subscript
95 nscoord scriptSpace
= 0;
97 // check if the subscriptshift attribute is there
99 nscoord subScriptShift
= 0;
100 GetAttribute(mContent
, mPresentationData
.mstyle
,
101 nsGkAtoms::subscriptshift_
, value
);
102 if (!value
.IsEmpty()) {
104 if (ParseNumericValue(value
, cssValue
) && cssValue
.IsLengthUnit()) {
105 subScriptShift
= CalcLength(PresContext(), mStyleContext
, cssValue
);
108 // check if the superscriptshift attribute is there
109 nscoord supScriptShift
= 0;
110 GetAttribute(mContent
, mPresentationData
.mstyle
,
111 nsGkAtoms::superscriptshift_
, value
);
112 if (!value
.IsEmpty()) {
114 if (ParseNumericValue(value
, cssValue
) && cssValue
.IsLengthUnit()) {
115 supScriptShift
= CalcLength(PresContext(), mStyleContext
, cssValue
);
119 return nsMathMLmsubsupFrame::PlaceSubSupScript(PresContext(),
129 // exported routine that both munderover and msubsup share.
130 // munderover uses this when movablelimits is set.
132 nsMathMLmsubsupFrame::PlaceSubSupScript(nsPresContext
* aPresContext
,
133 nsIRenderingContext
& aRenderingContext
,
135 nsHTMLReflowMetrics
& aDesiredSize
,
136 nsMathMLContainerFrame
* aFrame
,
137 nscoord aUserSubScriptShift
,
138 nscoord aUserSupScriptShift
,
139 nscoord aScriptSpace
)
141 // force the scriptSpace to be atleast 1 pixel
142 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
143 aScriptSpace
= PR_MAX(onePixel
, aScriptSpace
);
145 ////////////////////////////////////
146 // Get the children's desired sizes
148 nsHTMLReflowMetrics baseSize
;
149 nsHTMLReflowMetrics subScriptSize
;
150 nsHTMLReflowMetrics supScriptSize
;
151 nsBoundingMetrics bmBase
, bmSubScript
, bmSupScript
;
152 nsIFrame
* subScriptFrame
= nsnull
;
153 nsIFrame
* supScriptFrame
= nsnull
;
154 nsIFrame
* baseFrame
= aFrame
->GetFirstChild(nsnull
);
156 subScriptFrame
= baseFrame
->GetNextSibling();
158 supScriptFrame
= subScriptFrame
->GetNextSibling();
159 if (!baseFrame
|| !subScriptFrame
|| !supScriptFrame
||
160 supScriptFrame
->GetNextSibling()) {
161 // report an error, encourage people to get their markups in order
162 return aFrame
->ReflowError(aRenderingContext
, aDesiredSize
);
164 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
165 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
, bmSubScript
);
166 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
, bmSupScript
);
168 // get the subdrop from the subscript font
170 GetSubDropFromChild(subScriptFrame
, subDrop
);
171 // parameter v, Rule 18a, App. G, TeXbook
172 nscoord minSubScriptShift
= bmBase
.descent
+ subDrop
;
174 // get the supdrop from the supscript font
176 GetSupDropFromChild(supScriptFrame
, supDrop
);
177 // parameter u, Rule 18a, App. G, TeXbook
178 nscoord minSupScriptShift
= bmBase
.ascent
- supDrop
;
184 //////////////////////////////////////////////////
185 // Get subscript shift
186 // slightly different from nsMathMLmsubFrame.cpp
187 //////////////////////////////////////////////////
189 // subScriptShift{1,2}
190 // = minimum amount to shift the subscript down
191 // = sub{1,2} in TeXbook
192 // subScriptShift1 = subscriptshift attribute * x-height
193 nscoord subScriptShift1
, subScriptShift2
;
195 aRenderingContext
.SetFont(baseFrame
->GetStyleFont()->mFont
, nsnull
,
196 aPresContext
->GetUserFontSet());
197 nsCOMPtr
<nsIFontMetrics
> fm
;
198 aRenderingContext
.GetFontMetrics(*getter_AddRefs(fm
));
200 // get x-height (an ex)
202 fm
->GetXHeight (xHeight
);
205 GetRuleThickness (aRenderingContext
, fm
, ruleSize
);
207 // Get subScriptShift{1,2} default from font
208 GetSubScriptShifts (fm
, subScriptShift1
, subScriptShift2
);
210 if (0 < aUserSubScriptShift
) {
211 // the user has set the subscriptshift attribute
212 float scaler
= ((float) subScriptShift2
) / subScriptShift1
;
213 subScriptShift1
= PR_MAX(subScriptShift1
, aUserSubScriptShift
);
214 subScriptShift2
= NSToCoordRound(scaler
* subScriptShift1
);
217 // get a tentative value for subscriptshift
218 // Rule 18d, App. G, TeXbook
219 nscoord subScriptShift
=
220 PR_MAX(minSubScriptShift
,PR_MAX(subScriptShift1
,subScriptShift2
));
222 //////////////////////////////////////////////////
223 // Get supscript shift
224 // same code from nsMathMLmsupFrame.cpp
225 //////////////////////////////////////////////////
227 // get min supscript shift limit from x-height
228 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
229 nscoord minShiftFromXHeight
= (nscoord
)
230 (bmSupScript
.descent
+ (1.0f
/4.0f
) * xHeight
);
232 // supScriptShift{1,2,3}
233 // = minimum amount to shift the supscript up
234 // = sup{1,2,3} in TeX
235 // supScriptShift1 = superscriptshift attribute * x-height
236 // Note that there are THREE values for supscript shifts depending
237 // on the current style
238 nscoord supScriptShift1
, supScriptShift2
, supScriptShift3
;
239 // Set supScriptShift{1,2,3} default from font
240 GetSupScriptShifts (fm
, supScriptShift1
, supScriptShift2
, supScriptShift3
);
241 if (0 < aUserSupScriptShift
) {
242 // the user has set the superscriptshift attribute
243 float scaler2
= ((float) supScriptShift2
) / supScriptShift1
;
244 float scaler3
= ((float) supScriptShift3
) / supScriptShift1
;
245 supScriptShift1
= PR_MAX(supScriptShift1
, aUserSupScriptShift
);
246 supScriptShift2
= NSToCoordRound(scaler2
* supScriptShift1
);
247 supScriptShift3
= NSToCoordRound(scaler3
* supScriptShift1
);
250 // get sup script shift depending on current script level and display style
251 // Rule 18c, App. G, TeXbook
252 nscoord supScriptShift
;
253 nsPresentationData presentationData
;
254 aFrame
->GetPresentationData(presentationData
);
255 if ( aFrame
->GetStyleFont()->mScriptLevel
== 0 &&
256 NS_MATHML_IS_DISPLAYSTYLE(presentationData
.flags
) &&
257 !NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
258 // Style D in TeXbook
259 supScriptShift
= supScriptShift1
;
261 else if (NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
262 // Style C' in TeXbook = D',T',S',SS'
263 supScriptShift
= supScriptShift3
;
266 // everything else = T,S,SS
267 supScriptShift
= supScriptShift2
;
270 // get tentative value for superscriptshift
271 // Rule 18c, App. G, TeXbook
273 PR_MAX(minSupScriptShift
,PR_MAX(supScriptShift
,minShiftFromXHeight
));
275 //////////////////////////////////////////////////
276 // Negotiate between supScriptShift and subScriptShift
277 // so that there will be enough gap between them
278 // Rule 18e, App. G, TeXbook
279 //////////////////////////////////////////////////
282 (supScriptShift
- bmSupScript
.descent
) -
283 (bmSubScript
.ascent
- subScriptShift
);
284 if (gap
< 4.0f
* ruleSize
) {
285 // adjust subScriptShift to get a gap of (4.0 * ruleSize)
286 subScriptShift
+= NSToCoordRound ((4.0f
* ruleSize
) - gap
);
289 // next we want to ensure that the bottom of the superscript
290 // will be > (4/5) * x-height above baseline
291 gap
= NSToCoordRound ((4.0f
/5.0f
) * xHeight
-
292 (supScriptShift
- bmSupScript
.descent
));
294 supScriptShift
+= gap
;
295 subScriptShift
-= gap
;
298 //////////////////////////////////////////////////
300 //////////////////////////////////////////////////
302 // get bounding box for base + subscript + superscript
303 nsBoundingMetrics boundingMetrics
;
304 boundingMetrics
.ascent
=
305 PR_MAX(bmBase
.ascent
, (bmSupScript
.ascent
+ supScriptShift
));
306 boundingMetrics
.descent
=
307 PR_MAX(bmBase
.descent
, (bmSubScript
.descent
+ subScriptShift
));
309 // leave aScriptSpace after both super/subscript
310 // add italicCorrection between base and superscript
311 // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we
312 // estimate the italic creation ourselves and it isn't the same as TeX
313 nscoord italicCorrection
;
314 GetItalicCorrection(bmBase
, italicCorrection
);
315 italicCorrection
+= onePixel
;
316 boundingMetrics
.width
= bmBase
.width
+ aScriptSpace
+
317 PR_MAX((italicCorrection
+ bmSupScript
.width
), bmSubScript
.width
);
318 boundingMetrics
.leftBearing
= bmBase
.leftBearing
;
319 boundingMetrics
.rightBearing
= bmBase
.width
+
320 PR_MAX((italicCorrection
+ bmSupScript
.rightBearing
), bmSubScript
.rightBearing
);
321 aFrame
->SetBoundingMetrics(boundingMetrics
);
324 aDesiredSize
.ascent
=
325 PR_MAX(baseSize
.ascent
,
326 PR_MAX(subScriptSize
.ascent
- subScriptShift
,
327 supScriptSize
.ascent
+ supScriptShift
));
328 aDesiredSize
.height
= aDesiredSize
.ascent
+
329 PR_MAX(baseSize
.height
- baseSize
.ascent
,
330 PR_MAX(subScriptSize
.height
- subScriptSize
.ascent
+ subScriptShift
,
331 supScriptSize
.height
- subScriptSize
.ascent
- supScriptShift
));
332 aDesiredSize
.width
= boundingMetrics
.width
;
333 aDesiredSize
.mBoundingMetrics
= boundingMetrics
;
335 aFrame
->SetReference(nsPoint(0, aDesiredSize
.ascent
));
339 // now place the base ...
340 dx
= 0; dy
= aDesiredSize
.ascent
- baseSize
.ascent
;
341 FinishReflowChild(baseFrame
, aPresContext
, nsnull
,
342 baseSize
, dx
, dy
, 0);
345 dy
= aDesiredSize
.ascent
- (subScriptSize
.ascent
- subScriptShift
);
346 FinishReflowChild(subScriptFrame
, aPresContext
, nsnull
,
347 subScriptSize
, dx
, dy
, 0);
348 // ... and the superscript
349 dx
= bmBase
.width
+ italicCorrection
;
350 dy
= aDesiredSize
.ascent
- (supScriptSize
.ascent
+ supScriptShift
);
351 FinishReflowChild(supScriptFrame
, aPresContext
, nsnull
,
352 supScriptSize
, dx
, dy
, 0);