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 * 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 ***** */
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
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);
73 NS_NewMathMLmsqrtFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
75 return new (aPresShell
) nsMathMLmsqrtFrame(aContext
);
78 nsMathMLmsqrtFrame::nsMathMLmsqrtFrame(nsStyleContext
* aContext
) :
79 nsMathMLContainerFrame(aContext
),
85 nsMathMLmsqrtFrame::~nsMathMLmsqrtFrame()
90 nsMathMLmsqrtFrame::Init(nsIContent
* aContent
,
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
);
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
;
121 nsMathMLmsqrtFrame::TransmitAutomaticData()
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
);
135 nsMathMLmsqrtFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
136 const nsRect
& aDirtyRect
,
137 const nsDisplayListSet
& aLists
)
140 // paint the content we are square-rooting
141 nsresult rv
= nsMathMLContainerFrame::BuildDisplayList(aBuilder
, aDirtyRect
, aLists
);
142 NS_ENSURE_SUCCESS(rv
, rv
);
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)
156 mSqrChar
.GetRect(rect
);
157 nsBoundingMetrics bm
;
158 mSqrChar
.GetBoundingMetrics(bm
);
159 rv
= DisplayBoundingMetrics(aBuilder
, this, rect
.TopLeft(), bm
, aLists
);
166 /* virtual */ nsresult
167 nsMathMLmsqrtFrame::Place(nsIRenderingContext
& aRenderingContext
,
169 nsHTMLReflowMetrics
& aDesiredSize
)
172 // Measure the size of our content using the base class to format like an
174 nsHTMLReflowMetrics baseSize
;
176 nsMathMLContainerFrame::Place(aRenderingContext
, PR_FALSE
, baseSize
);
177 if (NS_MATHML_HAS_ERROR(mPresentationData
.flags
) || NS_FAILED(rv
)) {
178 DidReflowChildren(GetFirstChild(nsnull
));
182 nsBoundingMetrics bmSqr
, bmBase
;
183 bmBase
= baseSize
.mBoundingMetrics
;
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
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
))
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
;
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
,
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
));
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
;
274 mReference
.y
= aDesiredSize
.ascent
;
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
);
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
);
297 /* virtual */ nsresult
298 nsMathMLmsqrtFrame::MeasureChildFrames(nsIRenderingContext
& aRenderingContext
,
299 nsHTMLReflowMetrics
& aDesiredSize
)
301 return nsMathMLContainerFrame::Place(aRenderingContext
, PR_FALSE
,
307 nsMathMLmsqrtFrame::FixInterFrameSpacing(nsHTMLReflowMetrics
& aDesiredSize
)
309 nscoord gap
= nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize
);
313 mSqrChar
.GetRect(rect
);
315 mSqrChar
.SetRect(rect
);
316 mBarRect
.MoveBy(gap
, 0);
320 // ----------------------
321 // the Style System will use these to pass the proper style context to our MathMLChar
323 nsMathMLmsqrtFrame::GetAdditionalStyleContext(PRInt32 aIndex
) const
326 case NS_SQR_CHAR_STYLE_CONTEXT_INDEX
:
327 return mSqrChar
.GetStyleContext();
335 nsMathMLmsqrtFrame::SetAdditionalStyleContext(PRInt32 aIndex
,
336 nsStyleContext
* aStyleContext
)
339 case NS_SQR_CHAR_STYLE_CONTEXT_INDEX
:
340 mSqrChar
.SetStyleContext(aStyleContext
);