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
28 * Frederic Wang <fred.wang@free.fr> - extension of <msqrt/> to <menclose/>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
47 #include "nsPresContext.h"
48 #include "nsStyleContext.h"
49 #include "nsStyleConsts.h"
50 #include "nsIRenderingContext.h"
51 #include "nsIFontMetrics.h"
52 #include "nsWhitespaceTokenizer.h"
54 #include "nsMathMLmencloseFrame.h"
55 #include "nsDisplayList.h"
56 #include "gfxContext.h"
59 // <menclose> -- enclose content with a stretching symbol such
60 // as a long division sign. - implementation
63 // Unicode 5.1 assigns U+27CC to LONG DIVISION, but a right parenthesis
64 // renders better with current font support.
65 static const PRUnichar kLongDivChar
= ')';
67 // radical: 'SQUARE ROOT'
68 static const PRUnichar kRadicalChar
= 0x221A;
71 NS_NewMathMLmencloseFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
73 return new (aPresShell
) nsMathMLmencloseFrame(aContext
);
76 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmencloseFrame
)
78 nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext
* aContext
) :
79 nsMathMLContainerFrame(aContext
), mNotationsToDraw(0),
80 mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0)
84 nsMathMLmencloseFrame::~nsMathMLmencloseFrame()
88 nsresult
nsMathMLmencloseFrame::AllocateMathMLChar(nsMencloseNotation mask
)
90 // Is the char already allocated?
91 if ((mask
== NOTATION_LONGDIV
&& mLongDivCharIndex
>= 0) ||
92 (mask
== NOTATION_RADICAL
&& mRadicalCharIndex
>= 0))
95 // No need to track the style context given to our MathML chars.
96 // The Style System will use Get/SetAdditionalStyleContext() to keep it
97 // up-to-date if dynamic changes arise.
98 PRUint32 i
= mMathMLChar
.Length();
101 if (!mMathMLChar
.AppendElement())
102 return NS_ERROR_OUT_OF_MEMORY
;
104 if (mask
== NOTATION_LONGDIV
) {
105 Char
.Assign(kLongDivChar
);
106 mLongDivCharIndex
= i
;
107 } else if (mask
== NOTATION_RADICAL
) {
108 Char
.Assign(kRadicalChar
);
109 mRadicalCharIndex
= i
;
112 nsPresContext
*presContext
= PresContext();
113 mMathMLChar
[i
].SetData(presContext
, Char
);
114 ResolveMathMLCharStyle(presContext
, mContent
, mStyleContext
,
122 * Add a notation to draw, if the argument is the name of a known notation.
123 * @param aNotation string name of a notation
125 nsresult
nsMathMLmencloseFrame::AddNotation(const nsAString
& aNotation
)
129 if (aNotation
.EqualsLiteral("longdiv")) {
130 rv
= AllocateMathMLChar(NOTATION_LONGDIV
);
131 NS_ENSURE_SUCCESS(rv
, rv
);
132 mNotationsToDraw
|= NOTATION_LONGDIV
;
133 } else if (aNotation
.EqualsLiteral("actuarial")) {
134 mNotationsToDraw
|= (NOTATION_RIGHT
| NOTATION_TOP
);
135 } else if (aNotation
.EqualsLiteral("radical")) {
136 rv
= AllocateMathMLChar(NOTATION_RADICAL
);
137 NS_ENSURE_SUCCESS(rv
, rv
);
138 mNotationsToDraw
|= NOTATION_RADICAL
;
139 } else if (aNotation
.EqualsLiteral("box")) {
140 mNotationsToDraw
|= (NOTATION_LEFT
| NOTATION_RIGHT
|
141 NOTATION_TOP
| NOTATION_BOTTOM
);
142 } else if (aNotation
.EqualsLiteral("roundedbox")) {
143 mNotationsToDraw
|= NOTATION_ROUNDEDBOX
;
144 } else if (aNotation
.EqualsLiteral("circle")) {
145 mNotationsToDraw
|= NOTATION_CIRCLE
;
146 } else if (aNotation
.EqualsLiteral("left")) {
147 mNotationsToDraw
|= NOTATION_LEFT
;
148 } else if (aNotation
.EqualsLiteral("right")) {
149 mNotationsToDraw
|= NOTATION_RIGHT
;
150 } else if (aNotation
.EqualsLiteral("top")) {
151 mNotationsToDraw
|= NOTATION_TOP
;
152 } else if (aNotation
.EqualsLiteral("bottom")) {
153 mNotationsToDraw
|= NOTATION_BOTTOM
;
154 } else if (aNotation
.EqualsLiteral("updiagonalstrike")) {
155 mNotationsToDraw
|= NOTATION_UPDIAGONALSTRIKE
;
156 } else if (aNotation
.EqualsLiteral("downdiagonalstrike")) {
157 mNotationsToDraw
|= NOTATION_DOWNDIAGONALSTRIKE
;
158 } else if (aNotation
.EqualsLiteral("verticalstrike")) {
159 mNotationsToDraw
|= NOTATION_VERTICALSTRIKE
;
160 } else if (aNotation
.EqualsLiteral("horizontalstrike")) {
161 mNotationsToDraw
|= NOTATION_HORIZONTALSTRIKE
;
162 } else if (aNotation
.EqualsLiteral("madruwb")) {
163 mNotationsToDraw
|= (NOTATION_RIGHT
| NOTATION_BOTTOM
);
170 * Initialize the list of notations to draw
172 void nsMathMLmencloseFrame::InitNotations()
176 if (mContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::notation_
, value
)) {
177 // parse the notation attribute
178 nsWhitespaceTokenizer
tokenizer(value
);
180 while (tokenizer
.hasMoreTokens())
181 AddNotation(tokenizer
.nextToken());
184 if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV
)))
186 mNotationsToDraw
= NOTATION_LONGDIV
;
191 nsMathMLmencloseFrame::Init(nsIContent
* aContent
,
193 nsIFrame
* aPrevInFlow
)
195 nsresult rv
= nsMathMLContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
196 NS_ENSURE_SUCCESS(rv
, rv
);
204 nsMathMLmencloseFrame::InheritAutomaticData(nsIFrame
* aParent
)
206 // let the base class get the default from our parent
207 nsMathMLContainerFrame::InheritAutomaticData(aParent
);
209 mPresentationData
.flags
|= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY
;
215 nsMathMLmencloseFrame::TransmitAutomaticData()
217 if (IsToDraw(NOTATION_RADICAL
)) {
218 // The TeXBook (Ch 17. p.141) says that \sqrt is cramped
219 UpdatePresentationDataFromChildAt(0, -1,
220 NS_MATHML_COMPRESSED
,
221 NS_MATHML_COMPRESSED
);
228 nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
229 const nsRect
& aDirtyRect
,
230 const nsDisplayListSet
& aLists
)
233 // paint the menclosed content
234 nsresult rv
= nsMathMLContainerFrame::BuildDisplayList(aBuilder
, aDirtyRect
,
237 NS_ENSURE_SUCCESS(rv
, rv
);
239 if (NS_MATHML_HAS_ERROR(mPresentationData
.flags
))
242 nsRect mencloseRect
= nsIFrame::GetRect();
243 mencloseRect
.x
= mencloseRect
.y
= 0;
245 if (IsToDraw(NOTATION_RADICAL
)) {
246 rv
= mMathMLChar
[mRadicalCharIndex
].Display(aBuilder
, this, aLists
);
247 NS_ENSURE_SUCCESS(rv
, rv
);
250 mMathMLChar
[mRadicalCharIndex
].GetRect(rect
);
251 rect
.MoveBy(rect
.width
, 0);
252 rect
.SizeTo(mContentWidth
, mRuleThickness
);
253 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
254 NS_ENSURE_SUCCESS(rv
, rv
);
257 if (IsToDraw(NOTATION_LONGDIV
)) {
258 rv
= mMathMLChar
[mLongDivCharIndex
].Display(aBuilder
, this, aLists
);
259 NS_ENSURE_SUCCESS(rv
, rv
);
262 mMathMLChar
[mLongDivCharIndex
].GetRect(rect
);
263 rect
.SizeTo(rect
.width
+ mContentWidth
, mRuleThickness
);
264 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
265 NS_ENSURE_SUCCESS(rv
, rv
);
268 if (IsToDraw(NOTATION_TOP
)) {
269 nsRect
rect(0, 0, mencloseRect
.width
, mRuleThickness
);
270 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
271 NS_ENSURE_SUCCESS(rv
, rv
);
274 if (IsToDraw(NOTATION_BOTTOM
)) {
275 nsRect
rect(0, mencloseRect
.height
- mRuleThickness
,
276 mencloseRect
.width
, mRuleThickness
);
277 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
278 NS_ENSURE_SUCCESS(rv
, rv
);
281 if (IsToDraw(NOTATION_LEFT
)) {
282 nsRect
rect(0, 0, mRuleThickness
, mencloseRect
.height
);
283 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
284 NS_ENSURE_SUCCESS(rv
, rv
);
287 if (IsToDraw(NOTATION_RIGHT
)) {
288 nsRect
rect(mencloseRect
.width
- mRuleThickness
, 0,
289 mRuleThickness
, mencloseRect
.height
);
290 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
291 NS_ENSURE_SUCCESS(rv
, rv
);
294 if (IsToDraw(NOTATION_ROUNDEDBOX
)) {
295 rv
= DisplayNotation(aBuilder
, this, mencloseRect
, aLists
,
296 mRuleThickness
, NOTATION_ROUNDEDBOX
);
297 NS_ENSURE_SUCCESS(rv
, rv
);
300 if (IsToDraw(NOTATION_CIRCLE
)) {
301 rv
= DisplayNotation(aBuilder
, this, mencloseRect
, aLists
,
302 mRuleThickness
, NOTATION_CIRCLE
);
303 NS_ENSURE_SUCCESS(rv
, rv
);
306 if (IsToDraw(NOTATION_UPDIAGONALSTRIKE
)) {
307 rv
= DisplayNotation(aBuilder
, this, mencloseRect
, aLists
,
308 mRuleThickness
, NOTATION_UPDIAGONALSTRIKE
);
309 NS_ENSURE_SUCCESS(rv
, rv
);
312 if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE
)) {
313 rv
= DisplayNotation(aBuilder
, this, mencloseRect
, aLists
,
314 mRuleThickness
, NOTATION_DOWNDIAGONALSTRIKE
);
315 NS_ENSURE_SUCCESS(rv
, rv
);
318 if (IsToDraw(NOTATION_HORIZONTALSTRIKE
)) {
319 nsRect
rect(0, mencloseRect
.height
/ 2 - mRuleThickness
/ 2,
320 mencloseRect
.width
, mRuleThickness
);
321 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
322 NS_ENSURE_SUCCESS(rv
, rv
);
325 if (IsToDraw(NOTATION_VERTICALSTRIKE
)) {
326 nsRect
rect(mencloseRect
.width
/ 2 - mRuleThickness
/ 2, 0,
327 mRuleThickness
, mencloseRect
.height
);
328 rv
= DisplayBar(aBuilder
, this, rect
, aLists
);
329 NS_ENSURE_SUCCESS(rv
, rv
);
334 /* virtual */ nsresult
335 nsMathMLmencloseFrame::MeasureForWidth(nsIRenderingContext
& aRenderingContext
,
336 nsHTMLReflowMetrics
& aDesiredSize
)
338 return PlaceInternal(aRenderingContext
, PR_FALSE
, aDesiredSize
, PR_TRUE
);
341 /* virtual */ nsresult
342 nsMathMLmencloseFrame::Place(nsIRenderingContext
& aRenderingContext
,
344 nsHTMLReflowMetrics
& aDesiredSize
)
346 return PlaceInternal(aRenderingContext
, aPlaceOrigin
, aDesiredSize
, PR_FALSE
);
349 /* virtual */ nsresult
350 nsMathMLmencloseFrame::PlaceInternal(nsIRenderingContext
& aRenderingContext
,
352 nsHTMLReflowMetrics
& aDesiredSize
,
356 // Measure the size of our content using the base class to format like an
358 nsHTMLReflowMetrics baseSize
;
360 nsMathMLContainerFrame::Place(aRenderingContext
, PR_FALSE
, baseSize
);
362 if (NS_MATHML_HAS_ERROR(mPresentationData
.flags
) || NS_FAILED(rv
)) {
363 DidReflowChildren(GetFirstChild(nsnull
));
367 nsBoundingMetrics bmBase
= baseSize
.mBoundingMetrics
;
368 nscoord dx_left
= 0, dx_right
= 0;
369 nsBoundingMetrics bmLongdivChar
, bmRadicalChar
;
370 nscoord radicalAscent
= 0, radicalDescent
= 0;
371 nscoord longdivAscent
= 0, longdivDescent
= 0;
375 // Thickness of bars and font metrics
376 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
377 nsCOMPtr
<nsIFontMetrics
> fm
;
379 aRenderingContext
.SetFont(GetStyleFont()->mFont
,
380 PresContext()->GetUserFontSet());
381 aRenderingContext
.GetFontMetrics(*getter_AddRefs(fm
));
382 GetRuleThickness(aRenderingContext
, fm
, mRuleThickness
);
383 GetEmHeight(fm
, mEmHeight
);
385 nsBoundingMetrics bmOne
;
386 aRenderingContext
.GetBoundingMetrics(NS_LITERAL_STRING("1").get(), 1, bmOne
);
389 // General rules: the menclose element takes the size of the enclosed content.
390 // We add a padding when needed.
392 // determine padding & psi
393 nscoord padding
= 3 * mRuleThickness
;
394 nscoord delta
= padding
% onePixel
;
396 padding
+= onePixel
- delta
; // round up
398 if (IsToDraw(NOTATION_LONGDIV
) || IsToDraw(NOTATION_RADICAL
)) {
400 // Rule 11, App. G, TeXbook
401 // psi = clearance between rule and content
402 if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData
.flags
))
405 phi
= mRuleThickness
;
406 psi
= mRuleThickness
+ phi
/ 4;
408 delta
= psi
% onePixel
;
410 psi
+= onePixel
- delta
; // round up
413 if (mRuleThickness
< onePixel
)
414 mRuleThickness
= onePixel
;
416 // Set horizontal parameters
417 if (IsToDraw(NOTATION_ROUNDEDBOX
) ||
418 IsToDraw(NOTATION_TOP
) ||
419 IsToDraw(NOTATION_LEFT
) ||
420 IsToDraw(NOTATION_BOTTOM
) ||
421 IsToDraw(NOTATION_CIRCLE
))
424 if (IsToDraw(NOTATION_ROUNDEDBOX
) ||
425 IsToDraw(NOTATION_TOP
) ||
426 IsToDraw(NOTATION_RIGHT
) ||
427 IsToDraw(NOTATION_BOTTOM
) ||
428 IsToDraw(NOTATION_CIRCLE
))
431 // Set vertical parameters
432 if (IsToDraw(NOTATION_RIGHT
) ||
433 IsToDraw(NOTATION_LEFT
) ||
434 IsToDraw(NOTATION_UPDIAGONALSTRIKE
) ||
435 IsToDraw(NOTATION_DOWNDIAGONALSTRIKE
) ||
436 IsToDraw(NOTATION_VERTICALSTRIKE
) ||
437 IsToDraw(NOTATION_CIRCLE
) ||
438 IsToDraw(NOTATION_ROUNDEDBOX
) ||
439 IsToDraw(NOTATION_RADICAL
) ||
440 IsToDraw(NOTATION_LONGDIV
)) {
441 // set a minimal value for the base height
442 bmBase
.ascent
= NS_MAX(bmOne
.ascent
, bmBase
.ascent
);
443 bmBase
.descent
= NS_MAX(0, bmBase
.descent
);
446 mBoundingMetrics
.ascent
= bmBase
.ascent
;
447 mBoundingMetrics
.descent
= bmBase
.descent
;
449 if (IsToDraw(NOTATION_ROUNDEDBOX
) ||
450 IsToDraw(NOTATION_TOP
) ||
451 IsToDraw(NOTATION_LEFT
) ||
452 IsToDraw(NOTATION_RIGHT
) ||
453 IsToDraw(NOTATION_CIRCLE
))
454 mBoundingMetrics
.ascent
+= padding
;
456 if (IsToDraw(NOTATION_ROUNDEDBOX
) ||
457 IsToDraw(NOTATION_LEFT
) ||
458 IsToDraw(NOTATION_RIGHT
) ||
459 IsToDraw(NOTATION_BOTTOM
) ||
460 IsToDraw(NOTATION_CIRCLE
))
461 mBoundingMetrics
.descent
+= padding
;
464 // circle notation: we don't want the ellipse to overlap the enclosed
465 // content. Hence, we need to increase the size of the bounding box by a
466 // factor of at least sqrt(2).
467 if (IsToDraw(NOTATION_CIRCLE
)) {
468 double ratio
= (sqrt(2.0) - 1.0) / 2.0;
471 // Update horizontal parameters
472 padding2
= ratio
* bmBase
.width
;
474 dx_left
= NS_MAX(dx_left
, padding2
);
475 dx_right
= NS_MAX(dx_right
, padding2
);
477 // Update vertical parameters
478 padding2
= ratio
* (bmBase
.ascent
+ bmBase
.descent
);
480 mBoundingMetrics
.ascent
= NS_MAX(mBoundingMetrics
.ascent
,
481 bmBase
.ascent
+ padding2
);
482 mBoundingMetrics
.descent
= NS_MAX(mBoundingMetrics
.descent
,
483 bmBase
.descent
+ padding2
);
488 if (IsToDraw(NOTATION_LONGDIV
)) {
490 nscoord longdiv_width
= mMathMLChar
[mLongDivCharIndex
].
491 GetMaxWidth(PresContext(), aRenderingContext
);
493 // Update horizontal parameters
494 dx_left
= NS_MAX(dx_left
, longdiv_width
);
496 // Stretch the parenthesis to the appropriate height if it is not
498 nsBoundingMetrics contSize
= bmBase
;
499 contSize
.ascent
= mRuleThickness
;
500 contSize
.descent
= bmBase
.ascent
+ bmBase
.descent
+ psi
;
502 // height(longdiv) should be >= height(base) + psi + mRuleThickness
503 mMathMLChar
[mLongDivCharIndex
].Stretch(PresContext(), aRenderingContext
,
504 NS_STRETCH_DIRECTION_VERTICAL
,
505 contSize
, bmLongdivChar
,
507 mMathMLChar
[mLongDivCharIndex
].GetBoundingMetrics(bmLongdivChar
);
509 // Update horizontal parameters
510 dx_left
= NS_MAX(dx_left
, bmLongdivChar
.width
);
512 // Update vertical parameters
513 longdivAscent
= bmBase
.ascent
+ psi
+ mRuleThickness
;
514 longdivDescent
= NS_MAX(bmBase
.descent
,
515 (bmLongdivChar
.ascent
+ bmLongdivChar
.descent
-
518 mBoundingMetrics
.ascent
= NS_MAX(mBoundingMetrics
.ascent
,
520 mBoundingMetrics
.descent
= NS_MAX(mBoundingMetrics
.descent
,
527 if (IsToDraw(NOTATION_RADICAL
)) {
529 nscoord radical_width
= mMathMLChar
[mRadicalCharIndex
].
530 GetMaxWidth(PresContext(), aRenderingContext
);
532 // Update horizontal parameters
533 dx_left
= NS_MAX(dx_left
, radical_width
);
535 // Stretch the radical symbol to the appropriate height if it is not
537 nsBoundingMetrics contSize
= bmBase
;
538 contSize
.ascent
= mRuleThickness
;
539 contSize
.descent
= bmBase
.ascent
+ bmBase
.descent
+ psi
;
541 // height(radical) should be >= height(base) + psi + mRuleThickness
542 mMathMLChar
[mRadicalCharIndex
].Stretch(PresContext(), aRenderingContext
,
543 NS_STRETCH_DIRECTION_VERTICAL
,
544 contSize
, bmRadicalChar
,
546 mMathMLChar
[mRadicalCharIndex
].GetBoundingMetrics(bmRadicalChar
);
548 // Update horizontal parameters
549 dx_left
= NS_MAX(dx_left
, bmRadicalChar
.width
);
551 // Update vertical parameters
552 radicalAscent
= bmBase
.ascent
+ psi
+ mRuleThickness
;
553 radicalDescent
= NS_MAX(bmBase
.descent
,
554 (bmRadicalChar
.ascent
+ bmRadicalChar
.descent
-
557 mBoundingMetrics
.ascent
= NS_MAX(mBoundingMetrics
.ascent
,
559 mBoundingMetrics
.descent
= NS_MAX(mBoundingMetrics
.descent
,
566 if (IsToDraw(NOTATION_CIRCLE
) ||
567 IsToDraw(NOTATION_ROUNDEDBOX
) ||
568 (IsToDraw(NOTATION_LEFT
) && IsToDraw(NOTATION_RIGHT
))) {
569 // center the menclose around the content (horizontally)
570 dx_left
= dx_right
= NS_MAX(dx_left
, dx_right
);
574 // The maximum size is now computed: set the remaining parameters
575 mBoundingMetrics
.width
= dx_left
+ bmBase
.width
+ dx_right
;
577 mBoundingMetrics
.leftBearing
= NS_MIN(0, dx_left
+ bmBase
.leftBearing
);
578 mBoundingMetrics
.rightBearing
=
579 NS_MAX(mBoundingMetrics
.width
, dx_left
+ bmBase
.rightBearing
);
581 aDesiredSize
.width
= mBoundingMetrics
.width
;
583 aDesiredSize
.ascent
= NS_MAX(mBoundingMetrics
.ascent
, baseSize
.ascent
);
584 aDesiredSize
.height
= aDesiredSize
.ascent
+
585 NS_MAX(mBoundingMetrics
.descent
, baseSize
.height
- baseSize
.ascent
);
587 if (IsToDraw(NOTATION_LONGDIV
) || IsToDraw(NOTATION_RADICAL
)) {
588 // get the leading to be left at the top of the resulting frame
589 // this seems more reliable than using fm->GetLeading() on suspicious
591 nscoord leading
= nscoord(0.2f
* mEmHeight
);
592 nscoord desiredSizeAscent
= aDesiredSize
.ascent
;
593 nscoord desiredSizeDescent
= aDesiredSize
.height
- aDesiredSize
.ascent
;
595 if (IsToDraw(NOTATION_LONGDIV
)) {
596 desiredSizeAscent
= NS_MAX(desiredSizeAscent
,
597 longdivAscent
+ leading
);
598 desiredSizeDescent
= NS_MAX(desiredSizeDescent
,
599 longdivDescent
+ mRuleThickness
);
602 if (IsToDraw(NOTATION_RADICAL
)) {
603 desiredSizeAscent
= NS_MAX(desiredSizeAscent
,
604 radicalAscent
+ leading
);
605 desiredSizeDescent
= NS_MAX(desiredSizeDescent
,
606 radicalDescent
+ mRuleThickness
);
609 aDesiredSize
.ascent
= desiredSizeAscent
;
610 aDesiredSize
.height
= desiredSizeAscent
+ desiredSizeDescent
;
613 if (IsToDraw(NOTATION_CIRCLE
) ||
614 IsToDraw(NOTATION_ROUNDEDBOX
) ||
615 (IsToDraw(NOTATION_TOP
) && IsToDraw(NOTATION_BOTTOM
))) {
616 // center the menclose around the content (vertically)
617 nscoord dy
= NS_MAX(aDesiredSize
.ascent
- bmBase
.ascent
,
618 aDesiredSize
.height
- aDesiredSize
.ascent
-
621 aDesiredSize
.ascent
= bmBase
.ascent
+ dy
;
622 aDesiredSize
.height
= aDesiredSize
.ascent
+ bmBase
.descent
+ dy
;
625 // Update mBoundingMetrics ascent/descent
626 if (IsToDraw(NOTATION_TOP
) ||
627 IsToDraw(NOTATION_RIGHT
) ||
628 IsToDraw(NOTATION_LEFT
) ||
629 IsToDraw(NOTATION_UPDIAGONALSTRIKE
) ||
630 IsToDraw(NOTATION_DOWNDIAGONALSTRIKE
) ||
631 IsToDraw(NOTATION_VERTICALSTRIKE
) ||
632 IsToDraw(NOTATION_CIRCLE
) ||
633 IsToDraw(NOTATION_ROUNDEDBOX
))
634 mBoundingMetrics
.ascent
= aDesiredSize
.ascent
;
636 if (IsToDraw(NOTATION_BOTTOM
) ||
637 IsToDraw(NOTATION_RIGHT
) ||
638 IsToDraw(NOTATION_LEFT
) ||
639 IsToDraw(NOTATION_UPDIAGONALSTRIKE
) ||
640 IsToDraw(NOTATION_DOWNDIAGONALSTRIKE
) ||
641 IsToDraw(NOTATION_VERTICALSTRIKE
) ||
642 IsToDraw(NOTATION_CIRCLE
) ||
643 IsToDraw(NOTATION_ROUNDEDBOX
))
644 mBoundingMetrics
.descent
= aDesiredSize
.height
- aDesiredSize
.ascent
;
646 aDesiredSize
.mBoundingMetrics
= mBoundingMetrics
;
649 mReference
.y
= aDesiredSize
.ascent
;
653 // Set position and size of MathMLChars
654 if (IsToDraw(NOTATION_LONGDIV
))
655 mMathMLChar
[mLongDivCharIndex
].SetRect(nsRect(dx_left
-
657 aDesiredSize
.ascent
-
660 bmLongdivChar
.ascent
+
661 bmLongdivChar
.descent
));
663 if (IsToDraw(NOTATION_RADICAL
))
664 mMathMLChar
[mRadicalCharIndex
].SetRect(nsRect(dx_left
-
666 aDesiredSize
.ascent
-
669 bmRadicalChar
.ascent
+
670 bmRadicalChar
.descent
));
672 mContentWidth
= bmBase
.width
;
675 // Finish reflowing child frames
676 PositionRowChildFrames(dx_left
, aDesiredSize
.ascent
);
683 nsMathMLmencloseFrame::FixInterFrameSpacing(nsHTMLReflowMetrics
& aDesiredSize
)
685 nscoord gap
= nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize
);
689 // Move the MathML characters
691 for (PRUint32 i
= 0; i
< mMathMLChar
.Length(); i
++) {
692 mMathMLChar
[i
].GetRect(rect
);
694 mMathMLChar
[i
].SetRect(rect
);
701 nsMathMLmencloseFrame::AttributeChanged(PRInt32 aNameSpaceID
,
705 if (aAttribute
== nsGkAtoms::notation_
) {
706 mNotationsToDraw
= 0;
707 mLongDivCharIndex
= mRadicalCharIndex
= -1;
713 return nsMathMLContainerFrame::
714 AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
718 // the Style System will use these to pass the proper style context to our
721 nsMathMLmencloseFrame::GetAdditionalStyleContext(PRInt32 aIndex
) const
723 PRInt32 len
= mMathMLChar
.Length();
724 if (aIndex
>= 0 && aIndex
< len
)
725 return mMathMLChar
[aIndex
].GetStyleContext();
731 nsMathMLmencloseFrame::SetAdditionalStyleContext(PRInt32 aIndex
,
732 nsStyleContext
* aStyleContext
)
734 PRInt32 len
= mMathMLChar
.Length();
735 if (aIndex
>= 0 && aIndex
< len
)
736 mMathMLChar
[aIndex
].SetStyleContext(aStyleContext
);
739 class nsDisplayNotation
: public nsDisplayItem
742 nsDisplayNotation(nsIFrame
* aFrame
, const nsRect
& aRect
,
743 nscoord aThickness
, nsMencloseNotation aType
)
744 : nsDisplayItem(aFrame
), mRect(aRect
),
745 mThickness(aThickness
), mType(aType
) {
746 MOZ_COUNT_CTOR(nsDisplayNotation
);
748 #ifdef NS_BUILD_REFCNT_LOGGING
749 virtual ~nsDisplayNotation() {
750 MOZ_COUNT_DTOR(nsDisplayNotation
);
754 virtual void Paint(nsDisplayListBuilder
* aBuilder
,
755 nsIRenderingContext
* aCtx
);
756 NS_DISPLAY_DECL_NAME("MathMLMencloseNotation")
761 nsMencloseNotation mType
;
764 void nsDisplayNotation::Paint(nsDisplayListBuilder
* aBuilder
,
765 nsIRenderingContext
* aCtx
)
768 nsPresContext
* presContext
= mFrame
->PresContext();
769 gfxRect rect
= presContext
->
770 AppUnitsToGfxUnits(mRect
+ aBuilder
->ToReferenceFrame(mFrame
));
772 // paint the frame with the current text color
773 aCtx
->SetColor(mFrame
->GetStyleColor()->mColor
);
775 // change line width to mThickness
776 gfxContext
*gfxCtx
= aCtx
->ThebesContext();
777 gfxFloat currentLineWidth
= gfxCtx
->CurrentLineWidth();
778 gfxFloat e
= presContext
->AppUnitsToGfxUnits(mThickness
);
779 gfxCtx
->SetLineWidth(e
);
787 case NOTATION_CIRCLE
:
788 gfxCtx
->Ellipse(rect
.pos
+ rect
.size
/ 2.0, rect
.size
);
791 case NOTATION_ROUNDEDBOX
:
792 gfxCtx
->RoundedRectangle(rect
, gfxCornerSizes(3 * e
), PR_TRUE
);
795 case NOTATION_UPDIAGONALSTRIKE
:
796 gfxCtx
->Line(rect
.BottomLeft(), rect
.TopRight());
799 case NOTATION_DOWNDIAGONALSTRIKE
:
800 gfxCtx
->Line(rect
.TopLeft(), rect
.BottomRight());
804 NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation");
810 // restore previous line width
811 gfxCtx
->SetLineWidth(currentLineWidth
);
815 nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder
* aBuilder
,
816 nsIFrame
* aFrame
, const nsRect
& aRect
,
817 const nsDisplayListSet
& aLists
,
819 nsMencloseNotation aType
)
821 if (!aFrame
->GetStyleVisibility()->IsVisible() || aRect
.IsEmpty() ||
825 return aLists
.Content()->AppendNewToTop(new (aBuilder
)
826 nsDisplayNotation(aFrame
, aRect
,