Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / mathml / base / src / nsMathMLmsubsupFrame.cpp
bloba18e7dde00258f44ac9c96f2dbf80eb58cd4c58a
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
42 #include "nsCOMPtr.h"
43 #include "nsFrame.h"
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
56 nsIFrame*
57 NS_NewMathMLmsubsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
59 return new (aPresShell) nsMathMLmsubsupFrame(aContext);
62 nsMathMLmsubsupFrame::~nsMathMLmsubsupFrame()
66 NS_IMETHODIMP
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);
73 // 1. The REC says:
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,
83 NS_MATHML_COMPRESSED,
84 NS_MATHML_COMPRESSED);
86 return NS_OK;
89 /* virtual */ nsresult
90 nsMathMLmsubsupFrame::Place(nsIRenderingContext& aRenderingContext,
91 PRBool aPlaceOrigin,
92 nsHTMLReflowMetrics& aDesiredSize)
94 // extra spacing between base and sup/subscript
95 nscoord scriptSpace = 0;
97 // check if the subscriptshift attribute is there
98 nsAutoString value;
99 nscoord subScriptShift = 0;
100 GetAttribute(mContent, mPresentationData.mstyle,
101 nsGkAtoms::subscriptshift_, value);
102 if (!value.IsEmpty()) {
103 nsCSSValue cssValue;
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()) {
113 nsCSSValue cssValue;
114 if (ParseNumericValue(value, cssValue) && cssValue.IsLengthUnit()) {
115 supScriptShift = CalcLength(PresContext(), mStyleContext, cssValue);
119 return nsMathMLmsubsupFrame::PlaceSubSupScript(PresContext(),
120 aRenderingContext,
121 aPlaceOrigin,
122 aDesiredSize,
123 this,
124 subScriptShift,
125 supScriptShift,
126 scriptSpace);
129 // exported routine that both munderover and msubsup share.
130 // munderover uses this when movablelimits is set.
131 nsresult
132 nsMathMLmsubsupFrame::PlaceSubSupScript(nsPresContext* aPresContext,
133 nsIRenderingContext& aRenderingContext,
134 PRBool aPlaceOrigin,
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);
155 if (baseFrame)
156 subScriptFrame = baseFrame->GetNextSibling();
157 if (subScriptFrame)
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
169 nscoord subDrop;
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
175 nscoord supDrop;
176 GetSupDropFromChild(supScriptFrame, supDrop);
177 // parameter u, Rule 18a, App. G, TeXbook
178 nscoord minSupScriptShift = bmBase.ascent - supDrop;
180 //////////////////
181 // Place Children
182 //////////////////
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)
201 nscoord xHeight;
202 fm->GetXHeight (xHeight);
204 nscoord ruleSize;
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;
265 else {
266 // everything else = T,S,SS
267 supScriptShift = supScriptShift2;
270 // get tentative value for superscriptshift
271 // Rule 18c, App. G, TeXbook
272 supScriptShift =
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 //////////////////////////////////////////////////
281 nscoord gap =
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));
293 if (gap > 0) {
294 supScriptShift += gap;
295 subScriptShift -= gap;
298 //////////////////////////////////////////////////
299 // Do the Placing
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);
323 // reflow metrics
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));
337 if (aPlaceOrigin) {
338 nscoord dx, dy;
339 // now place the base ...
340 dx = 0; dy = aDesiredSize.ascent - baseSize.ascent;
341 FinishReflowChild(baseFrame, aPresContext, nsnull,
342 baseSize, dx, dy, 0);
343 // ... and subscript
344 dx = bmBase.width;
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);
355 return NS_OK;