Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / mathml / base / src / nsMathMLmsqrtFrame.cpp
blob86e0769abd4b900c4acfc6c7df34742bb30237f5
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 * Vilya Harvey <vilya@nag.co.uk>
26 * Shyjan Mahamud <mahamud@cs.cmu.edu>
27 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
44 #include "nsCOMPtr.h"
45 #include "nsFrame.h"
46 #include "nsPresContext.h"
47 #include "nsStyleContext.h"
48 #include "nsStyleConsts.h"
49 #include "nsIRenderingContext.h"
50 #include "nsIFontMetrics.h"
52 #include "nsMathMLmsqrtFrame.h"
55 // <msqrt> and <mroot> -- form a radical - implementation
58 //NOTE:
59 // The code assumes that TeX fonts are picked.
60 // There is no fall-back to draw the branches of the sqrt explicitly
61 // in the case where TeX fonts are not there. In general, there are no
62 // fall-back(s) in MathML when some (freely-downloadable) fonts are missing.
63 // Otherwise, this will add much work and unnecessary complexity to the core
64 // MathML engine. Assuming that authors have the free fonts is part of the
65 // deal. We are not responsible for cases of misconfigurations out there.
67 // additional style context to be used by our MathMLChar.
68 #define NS_SQR_CHAR_STYLE_CONTEXT_INDEX 0
70 static const PRUnichar kSqrChar = PRUnichar(0x221A);
72 nsIFrame*
73 NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
75 return new (aPresShell) nsMathMLmsqrtFrame(aContext);
78 nsMathMLmsqrtFrame::nsMathMLmsqrtFrame(nsStyleContext* aContext) :
79 nsMathMLContainerFrame(aContext),
80 mSqrChar(),
81 mBarRect()
85 nsMathMLmsqrtFrame::~nsMathMLmsqrtFrame()
89 NS_IMETHODIMP
90 nsMathMLmsqrtFrame::Init(nsIContent* aContent,
91 nsIFrame* aParent,
92 nsIFrame* aPrevInFlow)
94 nsresult rv = nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
96 nsPresContext *presContext = PresContext();
98 // No need to tract the style context given to our MathML char.
99 // The Style System will use Get/SetAdditionalStyleContext() to keep it
100 // up-to-date if dynamic changes arise.
101 nsAutoString sqrChar; sqrChar.Assign(kSqrChar);
102 mSqrChar.SetData(presContext, sqrChar);
103 ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mSqrChar, PR_TRUE);
105 return rv;
108 NS_IMETHODIMP
109 nsMathMLmsqrtFrame::InheritAutomaticData(nsIFrame* aParent)
111 // let the base class get the default from our parent
112 nsMathMLContainerFrame::InheritAutomaticData(aParent);
114 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
116 return NS_OK;
120 NS_IMETHODIMP
121 nsMathMLmsqrtFrame::TransmitAutomaticData()
123 // 1. The REC says:
124 // The <msqrt> element leaves both attributes [displaystyle and scriptlevel]
125 // unchanged within all its arguments.
126 // 2. The TeXBook (Ch 17. p.141) says that \sqrt is cramped
127 UpdatePresentationDataFromChildAt(0, -1,
128 NS_MATHML_COMPRESSED,
129 NS_MATHML_COMPRESSED);
131 return NS_OK;
134 NS_IMETHODIMP
135 nsMathMLmsqrtFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
136 const nsRect& aDirtyRect,
137 const nsDisplayListSet& aLists)
139 /////////////
140 // paint the content we are square-rooting
141 nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
142 NS_ENSURE_SUCCESS(rv, rv);
144 /////////////
145 // paint the sqrt symbol
146 if (!NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
147 rv = mSqrChar.Display(aBuilder, this, aLists);
148 NS_ENSURE_SUCCESS(rv, rv);
150 rv = DisplayBar(aBuilder, this, mBarRect, aLists);
151 NS_ENSURE_SUCCESS(rv, rv);
153 #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
154 // for visual debug
155 nsRect rect;
156 mSqrChar.GetRect(rect);
157 nsBoundingMetrics bm;
158 mSqrChar.GetBoundingMetrics(bm);
159 rv = DisplayBoundingMetrics(aBuilder, this, rect.TopLeft(), bm, aLists);
160 #endif
163 return rv;
166 /* virtual */ nsresult
167 nsMathMLmsqrtFrame::Place(nsIRenderingContext& aRenderingContext,
168 PRBool aPlaceOrigin,
169 nsHTMLReflowMetrics& aDesiredSize)
171 ///////////////
172 // Measure the size of our content using the base class to format like an
173 // inferred mrow.
174 nsHTMLReflowMetrics baseSize;
175 nsresult rv =
176 nsMathMLContainerFrame::Place(aRenderingContext, PR_FALSE, baseSize);
177 if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
178 DidReflowChildren(GetFirstChild(nsnull));
179 return rv;
182 nsBoundingMetrics bmSqr, bmBase;
183 bmBase = baseSize.mBoundingMetrics;
185 ////////////
186 // Prepare the radical symbol and the overline bar
188 aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull,
189 PresContext()->GetUserFontSet());
190 nsCOMPtr<nsIFontMetrics> fm;
191 aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
193 // For radical glyphs from TeX fonts and some of the radical glyphs from
194 // Mathematica fonts, the thickness of the overline can be obtained from the
195 // ascent of the glyph. Most fonts however have radical glyphs above the
196 // baseline so no assumption can be made about the meaning of the ascent.
197 nscoord ruleThickness, leading, em;
198 GetRuleThickness(aRenderingContext, fm, ruleThickness);
200 nsBoundingMetrics bmOne;
201 aRenderingContext.GetBoundingMetrics(NS_LITERAL_STRING("1").get(), 1, bmOne);
203 // get the leading to be left at the top of the resulting frame
204 // this seems more reliable than using fm->GetLeading() on suspicious fonts
205 GetEmHeight(fm, em);
206 leading = nscoord(0.2f * em);
208 // Rule 11, App. G, TeXbook
209 // psi = clearance between rule and content
210 nscoord phi = 0, psi = 0;
211 if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags))
212 fm->GetXHeight(phi);
213 else
214 phi = ruleThickness;
215 psi = ruleThickness + phi/4;
217 // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
218 if (bmOne.ascent > bmBase.ascent)
219 psi += bmOne.ascent - bmBase.ascent;
221 // make sure that the rule appears on the screen
222 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
223 if (ruleThickness < onePixel) {
224 ruleThickness = onePixel;
227 // adjust clearance psi to get an exact number of pixels -- this
228 // gives a nicer & uniform look on stacked radicals (bug 130282)
229 nscoord delta = psi % onePixel;
230 if (delta)
231 psi += onePixel - delta; // round up
233 // Stretch the radical symbol to the appropriate height if it is not big enough.
234 nsBoundingMetrics contSize = bmBase;
235 contSize.ascent = ruleThickness;
236 contSize.descent = bmBase.ascent + bmBase.descent + psi;
238 // height(radical) should be >= height(base) + psi + ruleThickness
239 nsBoundingMetrics radicalSize;
240 mSqrChar.Stretch(PresContext(), aRenderingContext,
241 NS_STRETCH_DIRECTION_VERTICAL,
242 contSize, radicalSize,
243 NS_STRETCH_LARGER);
244 // radicalSize have changed at this point, and should match with
245 // the bounding metrics of the char
246 mSqrChar.GetBoundingMetrics(bmSqr);
248 nscoord dx = 0, dy = 0;
249 // place the radical symbol and the radical bar
250 dy = leading; // leave a leading at the top
251 mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent));
252 dx = bmSqr.width;
253 mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness);
255 // Update the desired size for the container.
256 // the baseline will be that of the base.
257 mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness;
258 mBoundingMetrics.descent =
259 PR_MAX(bmBase.descent,
260 (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent));
261 mBoundingMetrics.width = bmSqr.width + bmBase.width;
262 mBoundingMetrics.leftBearing = bmSqr.leftBearing;
263 mBoundingMetrics.rightBearing = bmSqr.width +
264 PR_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule
266 aDesiredSize.ascent = mBoundingMetrics.ascent + leading;
267 aDesiredSize.height = aDesiredSize.ascent +
268 PR_MAX(baseSize.height - baseSize.ascent,
269 mBoundingMetrics.descent + ruleThickness);
270 aDesiredSize.width = mBoundingMetrics.width;
271 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
273 mReference.x = 0;
274 mReference.y = aDesiredSize.ascent;
276 if (aPlaceOrigin) {
277 //////////////////
278 // Finish reflowing child frames, positioning their origins so as to leave
279 // room for the sqrt char and the overline bar.
280 PositionRowChildFrames(radicalSize.width, aDesiredSize.ascent);
283 return NS_OK;
286 /* virtual */ nscoord
287 nsMathMLmsqrtFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext)
289 // The child frames form an mrow
290 nscoord width = nsMathMLContainerFrame::GetIntrinsicWidth(aRenderingContext);
291 // Add the width of the radical symbol
292 width += mSqrChar.GetMaxWidth(PresContext(), *aRenderingContext);
294 return width;
297 /* virtual */ nsresult
298 nsMathMLmsqrtFrame::MeasureChildFrames(nsIRenderingContext& aRenderingContext,
299 nsHTMLReflowMetrics& aDesiredSize)
301 return nsMathMLContainerFrame::Place(aRenderingContext, PR_FALSE,
302 aDesiredSize);
306 nscoord
307 nsMathMLmsqrtFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
309 nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
310 if (!gap) return 0;
312 nsRect rect;
313 mSqrChar.GetRect(rect);
314 rect.MoveBy(gap, 0);
315 mSqrChar.SetRect(rect);
316 mBarRect.MoveBy(gap, 0);
317 return gap;
320 // ----------------------
321 // the Style System will use these to pass the proper style context to our MathMLChar
322 nsStyleContext*
323 nsMathMLmsqrtFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
325 switch (aIndex) {
326 case NS_SQR_CHAR_STYLE_CONTEXT_INDEX:
327 return mSqrChar.GetStyleContext();
328 break;
329 default:
330 return nsnull;
334 void
335 nsMathMLmsqrtFrame::SetAdditionalStyleContext(PRInt32 aIndex,
336 nsStyleContext* aStyleContext)
338 switch (aIndex) {
339 case NS_SQR_CHAR_STYLE_CONTEXT_INDEX:
340 mSqrChar.SetStyleContext(aStyleContext);
341 break;