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>
26 * Pierre Phaneuf <pp@ludusdesign.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
45 #include "nsPresContext.h"
46 #include "nsStyleContext.h"
47 #include "nsStyleConsts.h"
48 #include "nsINameSpaceManager.h"
49 #include "nsIRenderingContext.h"
50 #include "nsIFontMetrics.h"
52 #include "nsMathMLmoverFrame.h"
53 #include "nsMathMLmsupFrame.h"
56 // <mover> -- attach an overscript to a base - implementation
60 NS_NewMathMLmoverFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
62 return new (aPresShell
) nsMathMLmoverFrame(aContext
);
65 nsMathMLmoverFrame::~nsMathMLmoverFrame()
70 nsMathMLmoverFrame::AttributeChanged(PRInt32 aNameSpaceID
,
74 if (nsGkAtoms::accent_
== aAttribute
) {
75 // When we have automatic data to update within ourselves, we ask our
76 // parent to re-layout its children
77 return ReLayoutChildren(mParent
, NS_FRAME_IS_DIRTY
);
80 return nsMathMLContainerFrame::
81 AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
85 nsMathMLmoverFrame::UpdatePresentationData(PRUint32 aFlagsValues
,
86 PRUint32 aFlagsToUpdate
)
88 nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues
, aFlagsToUpdate
);
89 // disable the stretch-all flag if we are going to act like a superscript
90 if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData
.flags
) &&
91 !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData
.flags
)) {
92 mPresentationData
.flags
&= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY
;
95 mPresentationData
.flags
|= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY
;
101 nsMathMLmoverFrame::UpdatePresentationDataFromChildAt(PRInt32 aFirstIndex
,
103 PRUint32 aFlagsValues
,
104 PRUint32 aFlagsToUpdate
)
106 // mover is special... The REC says:
107 // Within overscript, <mover> always sets displaystyle to "false",
108 // but increments scriptlevel by 1 only when accent is "false".
110 // 1. don't allow displaystyle to change in the overscript
111 // 2. if the value of the accent is changed, we need to recompute the
112 // scriptlevel of the overscript. The problem is that the accent
113 // can change in the <mo> deep down the embellished hierarchy
115 // Do #1 here, never allow displaystyle to be changed in the overscript
117 nsIFrame
* childFrame
= mFrames
.FirstChild();
119 if ((index
>= aFirstIndex
) &&
120 ((aLastIndex
<= 0) || ((aLastIndex
> 0) && (index
<= aLastIndex
)))) {
123 aFlagsToUpdate
&= ~NS_MATHML_DISPLAYSTYLE
;
124 aFlagsValues
&= ~NS_MATHML_DISPLAYSTYLE
;
126 PropagatePresentationDataFor(childFrame
, aFlagsValues
, aFlagsToUpdate
);
129 childFrame
= childFrame
->GetNextSibling();
133 // For #2, changing the accent attribute will trigger a re-build of
134 // all automatic data in the embellished hierarchy
138 nsMathMLmoverFrame::InheritAutomaticData(nsIFrame
* aParent
)
140 // let the base class get the default from our parent
141 nsMathMLContainerFrame::InheritAutomaticData(aParent
);
143 mPresentationData
.flags
|= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY
;
149 nsMathMLmoverFrame::TransmitAutomaticData()
151 // At this stage, all our children are in sync and we can fully
152 // resolve our own mEmbellishData struct
153 //---------------------------------------------------------------------
156 The default value of accent is false, unless overscript
157 is an <mo> element or an embellished operator. If overscript is
158 an <mo> element, the value of its accent attribute is used as
159 the default value of accent. If overscript is an embellished
160 operator, the accent attribute of the <mo> element at its
161 core is used as the default value. As with all attributes, an
162 explicitly given value overrides the default.
164 XXX The winner is the outermost in conflicting settings like these:
165 <mover accent='true'>
167 <mo accent='false'> ... </mo>
171 nsIFrame
* overscriptFrame
= nsnull
;
172 nsIFrame
* baseFrame
= mFrames
.FirstChild();
174 overscriptFrame
= baseFrame
->GetNextSibling();
176 // if our base is an embellished operator, let its state bubble to us (in particular,
177 // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags
178 // are reset to the default values of false if the base frame isn't embellished.
179 mPresentationData
.baseFrame
= baseFrame
;
180 GetEmbellishDataFrom(baseFrame
, mEmbellishData
);
182 // The default value of accent is false, unless the overscript is embellished
183 // and its core <mo> is an accent
184 nsEmbellishData embellishData
;
185 GetEmbellishDataFrom(overscriptFrame
, embellishData
);
186 if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData
.flags
))
187 mEmbellishData
.flags
|= NS_MATHML_EMBELLISH_ACCENTOVER
;
189 mEmbellishData
.flags
&= ~NS_MATHML_EMBELLISH_ACCENTOVER
;
191 // if we have an accent attribute, it overrides what the overscript said
192 static nsIContent::AttrValuesArray strings
[] =
193 {&nsGkAtoms::_true
, &nsGkAtoms::_false
, nsnull
};
194 switch (mContent
->FindAttrValueIn(kNameSpaceID_None
, nsGkAtoms::accent_
,
195 strings
, eCaseMatters
)) {
196 case 0: mEmbellishData
.flags
|= NS_MATHML_EMBELLISH_ACCENTOVER
; break;
197 case 1: mEmbellishData
.flags
&= ~NS_MATHML_EMBELLISH_ACCENTOVER
; break;
200 // disable the stretch-all flag if we are going to act like a superscript
201 if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData
.flags
) &&
202 !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData
.flags
))
203 mPresentationData
.flags
&= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY
;
205 // Now transmit any change that we want to our children so that they
206 // can update their mPresentationData structs
207 //---------------------------------------------------------------------
210 Within overscript, <mover> always sets displaystyle to "false",
211 but increments scriptlevel by 1 only when accent is "false".
213 The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a
214 say it shouldn't be compressed. However, The TeXBook says
215 that math accents and \overline change uncramped styles to their
216 cramped counterparts.
218 SetIncrementScriptLevel(1, !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData
.flags
));
219 PRUint32 compress
= NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData
.flags
)
220 ? NS_MATHML_COMPRESSED
: 0;
221 PropagatePresentationDataFor(overscriptFrame
,
222 ~NS_MATHML_DISPLAYSTYLE
| compress
,
223 NS_MATHML_DISPLAYSTYLE
| compress
);
230 * If the base is an operator with movablelimits="true" (or an embellished
231 operator whose <mo> element core has movablelimits="true"), and
232 displaystyle="false", then overscript is drawn in a superscript
233 position. In this case, the accent attribute is ignored. This is
234 often used for limits on symbols such as ∑.
237 if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
238 !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
239 // place like superscript
242 // place like overscript
246 /* virtual */ nsresult
247 nsMathMLmoverFrame::Place(nsIRenderingContext
& aRenderingContext
,
249 nsHTMLReflowMetrics
& aDesiredSize
)
251 if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData
.flags
) &&
252 !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData
.flags
)) {
253 // place like superscript
254 return nsMathMLmsupFrame::PlaceSuperScript(PresContext(),
258 this, 0, PresContext()->PointsToAppUnits(0.5f
));
261 ////////////////////////////////////
262 // Get the children's desired sizes
264 nsBoundingMetrics bmBase
, bmOver
;
265 nsHTMLReflowMetrics baseSize
;
266 nsHTMLReflowMetrics overSize
;
267 nsIFrame
* overFrame
= nsnull
;
268 nsIFrame
* baseFrame
= mFrames
.FirstChild();
270 overFrame
= baseFrame
->GetNextSibling();
271 if (!baseFrame
|| !overFrame
|| overFrame
->GetNextSibling()) {
272 // report an error, encourage people to get their markups in order
273 return ReflowError(aRenderingContext
, aDesiredSize
);
275 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
276 GetReflowAndBoundingMetricsFor(overFrame
, overSize
, bmOver
);
278 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
283 aRenderingContext
.SetFont(GetStyleFont()->mFont
, nsnull
,
284 PresContext()->GetUserFontSet());
285 nsCOMPtr
<nsIFontMetrics
> fm
;
286 aRenderingContext
.GetFontMetrics(*getter_AddRefs(fm
));
289 fm
->GetXHeight (xHeight
);
291 nscoord ruleThickness
;
292 GetRuleThickness (aRenderingContext
, fm
, ruleThickness
);
294 // there are 2 different types of placement depending on
295 // whether we want an accented overscript or not
297 nscoord correction
= 0;
298 GetItalicCorrection (bmBase
, correction
);
300 nscoord delta1
= 0; // gap between base and overscript
301 nscoord delta2
= 0; // extra space above overscript
302 if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData
.flags
)) {
303 // Rule 13a, App. G, TeXbook
304 nscoord bigOpSpacing1
, bigOpSpacing3
, bigOpSpacing5
, dummy
;
305 GetBigOpSpacings (fm
,
306 bigOpSpacing1
, dummy
,
307 bigOpSpacing3
, dummy
,
309 delta1
= PR_MAX(bigOpSpacing1
, (bigOpSpacing3
- bmOver
.descent
));
310 delta2
= bigOpSpacing5
;
312 // XXX This is not a TeX rule...
313 // delta1 (as computed above) can become really big when bmOver.descent is
314 // negative, e.g., if the content is &OverBar. In such case, we use the height
315 if (bmOver
.descent
< 0)
316 delta1
= PR_MAX(bigOpSpacing1
, (bigOpSpacing3
- (bmOver
.ascent
+ bmOver
.descent
)));
319 // Rule 12, App. G, TeXbook
320 // We are going to modify this rule to make it more general.
321 // The idea behind Rule 12 in the TeXBook is to keep the accent
322 // as close to the base as possible, while ensuring that the
323 // distance between the *baseline* of the accent char and
324 // the *baseline* of the base is atleast x-height.
325 // The idea is that for normal use, we would like all the accents
326 // on a line to line up atleast x-height above the baseline
328 // When the ascent of the base is >= x-height,
329 // the baseline of the accent char is placed just above the base
330 // (specifically, the baseline of the accent char is placed
331 // above the baseline of the base by the ascent of the base).
332 // For ease of implementation,
333 // this assumes that the font-designer designs accents
334 // in such a way that the bottom of the accent is atleast x-height
335 // above its baseline, otherwise there will be collisions
336 // with the base. Also there should be proper padding between
337 // the bottom of the accent char and its baseline.
338 // The above rule may not be obvious from a first
339 // reading of rule 12 in the TeXBook !!!
340 // The mathml <mover> tag can use accent chars that
341 // do not follow this convention. So we modify TeX's rule
342 // so that TeX's rule gets subsumed for accents that follow
344 // while also allowing accents that do not follow the convention :
345 // we try to keep the *bottom* of the accent char atleast x-height
346 // from the baseline of the base char. we also slap on an extra
347 // padding between the accent and base chars.
348 delta1
= ruleThickness
+ onePixel
/2; // we have at least the padding
349 if (bmBase
.ascent
< xHeight
) {
350 // also ensure at least x-height above the baseline of the base
351 delta1
+= xHeight
- bmBase
.ascent
;
353 delta2
= ruleThickness
;
356 if (!(bmOver
.ascent
+ bmOver
.descent
)) delta1
= 0;
358 nscoord dxBase
, dxOver
= 0;
360 // Ad-hoc - This is to override fonts which have ready-made _accent_
361 // glyphs with negative lbearing and rbearing. We want to position
362 // the overscript ourselves
363 nscoord overWidth
= bmOver
.width
;
364 if (!overWidth
&& (bmOver
.rightBearing
- bmOver
.leftBearing
> 0)) {
365 overWidth
= bmOver
.rightBearing
- bmOver
.leftBearing
;
366 dxOver
= -bmOver
.leftBearing
;
369 if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData
.flags
)) {
370 mBoundingMetrics
.width
= bmBase
.width
;
371 dxOver
+= correction
+ (mBoundingMetrics
.width
- overWidth
)/2;
374 mBoundingMetrics
.width
= PR_MAX(bmBase
.width
, overWidth
);
375 dxOver
+= correction
/2 + (mBoundingMetrics
.width
- overWidth
)/2;
377 dxBase
= (mBoundingMetrics
.width
- bmBase
.width
) / 2;
379 mBoundingMetrics
.ascent
=
380 bmOver
.ascent
+ bmOver
.descent
+ delta1
+ bmBase
.ascent
;
381 mBoundingMetrics
.descent
= bmBase
.descent
;
382 mBoundingMetrics
.leftBearing
=
383 PR_MIN(dxBase
+ bmBase
.leftBearing
, dxOver
+ bmOver
.leftBearing
);
384 mBoundingMetrics
.rightBearing
=
385 PR_MAX(dxBase
+ bmBase
.rightBearing
, dxOver
+ bmOver
.rightBearing
);
387 aDesiredSize
.ascent
=
388 PR_MAX(mBoundingMetrics
.ascent
+ delta2
,
389 overSize
.ascent
+ bmOver
.descent
+ delta1
+ bmBase
.ascent
);
390 aDesiredSize
.height
= aDesiredSize
.ascent
+
391 baseSize
.height
- baseSize
.ascent
;
392 aDesiredSize
.width
= mBoundingMetrics
.width
;
393 aDesiredSize
.mBoundingMetrics
= mBoundingMetrics
;
396 mReference
.y
= aDesiredSize
.ascent
;
400 nscoord dy
= aDesiredSize
.ascent
- baseSize
.ascent
;
401 FinishReflowChild (baseFrame
, PresContext(), nsnull
, baseSize
, dxBase
, dy
, 0);
403 dy
= aDesiredSize
.ascent
-
404 mBoundingMetrics
.ascent
+ bmOver
.ascent
- overSize
.ascent
;
405 FinishReflowChild (overFrame
, PresContext(), nsnull
, overSize
, dxOver
, dy
, 0);