Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / mathml / nsMathMLmencloseFrame.cpp
blob30bf0f796f177285cc2342a58c02ffc5a60b72dd
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
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 ***** */
45 #include "nsCOMPtr.h"
46 #include "nsFrame.h"
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
62 // longdiv:
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;
70 nsIFrame*
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))
93 return NS_OK;
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();
99 nsAutoString Char;
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,
115 &mMathMLChar[i],
116 PR_TRUE);
118 return NS_OK;
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)
127 nsresult rv;
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);
166 return NS_OK;
170 * Initialize the list of notations to draw
172 void nsMathMLmencloseFrame::InitNotations()
174 nsAutoString value;
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());
182 } else {
183 // default: longdiv
184 if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV)))
185 return;
186 mNotationsToDraw = NOTATION_LONGDIV;
190 NS_IMETHODIMP
191 nsMathMLmencloseFrame::Init(nsIContent* aContent,
192 nsIFrame* aParent,
193 nsIFrame* aPrevInFlow)
195 nsresult rv = nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
196 NS_ENSURE_SUCCESS(rv, rv);
198 InitNotations();
200 return NS_OK;
203 NS_IMETHODIMP
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;
211 return NS_OK;
214 NS_IMETHODIMP
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);
224 return NS_OK;
227 NS_IMETHODIMP
228 nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
229 const nsRect& aDirtyRect,
230 const nsDisplayListSet& aLists)
232 /////////////
233 // paint the menclosed content
234 nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect,
235 aLists);
237 NS_ENSURE_SUCCESS(rv, rv);
239 if (NS_MATHML_HAS_ERROR(mPresentationData.flags))
240 return rv;
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);
249 nsRect rect;
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);
261 nsRect rect;
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);
331 return 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,
343 PRBool aPlaceOrigin,
344 nsHTMLReflowMetrics& aDesiredSize)
346 return PlaceInternal(aRenderingContext, aPlaceOrigin, aDesiredSize, PR_FALSE);
349 /* virtual */ nsresult
350 nsMathMLmencloseFrame::PlaceInternal(nsIRenderingContext& aRenderingContext,
351 PRBool aPlaceOrigin,
352 nsHTMLReflowMetrics& aDesiredSize,
353 PRBool aWidthOnly)
355 ///////////////
356 // Measure the size of our content using the base class to format like an
357 // inferred mrow.
358 nsHTMLReflowMetrics baseSize;
359 nsresult rv =
360 nsMathMLContainerFrame::Place(aRenderingContext, PR_FALSE, baseSize);
362 if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
363 DidReflowChildren(GetFirstChild(nsnull));
364 return rv;
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;
372 nscoord psi = 0;
374 ///////////////
375 // Thickness of bars and font metrics
376 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
377 nsCOMPtr<nsIFontMetrics> fm;
378 nscoord mEmHeight;
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);
388 ///////////////
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;
395 if (delta)
396 padding += onePixel - delta; // round up
398 if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
399 nscoord phi;
400 // Rule 11, App. G, TeXbook
401 // psi = clearance between rule and content
402 if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags))
403 fm->GetXHeight(phi);
404 else
405 phi = mRuleThickness;
406 psi = mRuleThickness + phi / 4;
408 delta = psi % onePixel;
409 if (delta)
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))
422 dx_left = padding;
424 if (IsToDraw(NOTATION_ROUNDEDBOX) ||
425 IsToDraw(NOTATION_TOP) ||
426 IsToDraw(NOTATION_RIGHT) ||
427 IsToDraw(NOTATION_BOTTOM) ||
428 IsToDraw(NOTATION_CIRCLE))
429 dx_right = padding;
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;
463 ///////////////
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;
469 nscoord padding2;
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);
486 ///////////////
487 // longdiv notation:
488 if (IsToDraw(NOTATION_LONGDIV)) {
489 if (aWidthOnly) {
490 nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].
491 GetMaxWidth(PresContext(), aRenderingContext);
493 // Update horizontal parameters
494 dx_left = NS_MAX(dx_left, longdiv_width);
495 } else {
496 // Stretch the parenthesis to the appropriate height if it is not
497 // big enough.
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,
506 NS_STRETCH_LARGER);
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 -
516 longdivAscent));
518 mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,
519 longdivAscent);
520 mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,
521 longdivDescent);
525 ///////////////
526 // radical notation:
527 if (IsToDraw(NOTATION_RADICAL)) {
528 if (aWidthOnly) {
529 nscoord radical_width = mMathMLChar[mRadicalCharIndex].
530 GetMaxWidth(PresContext(), aRenderingContext);
532 // Update horizontal parameters
533 dx_left = NS_MAX(dx_left, radical_width);
534 } else {
535 // Stretch the radical symbol to the appropriate height if it is not
536 // big enough.
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,
545 NS_STRETCH_LARGER);
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 -
555 radicalAscent));
557 mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent,
558 radicalAscent);
559 mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent,
560 radicalDescent);
564 ///////////////
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);
573 ///////////////
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
590 // fonts
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 -
619 bmBase.descent);
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;
648 mReference.x = 0;
649 mReference.y = aDesiredSize.ascent;
651 if (aPlaceOrigin) {
652 //////////////////
653 // Set position and size of MathMLChars
654 if (IsToDraw(NOTATION_LONGDIV))
655 mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left -
656 bmLongdivChar.width,
657 aDesiredSize.ascent -
658 longdivAscent,
659 bmLongdivChar.width,
660 bmLongdivChar.ascent +
661 bmLongdivChar.descent));
663 if (IsToDraw(NOTATION_RADICAL))
664 mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx_left -
665 bmRadicalChar.width,
666 aDesiredSize.ascent -
667 radicalAscent,
668 bmRadicalChar.width,
669 bmRadicalChar.ascent +
670 bmRadicalChar.descent));
672 mContentWidth = bmBase.width;
674 //////////////////
675 // Finish reflowing child frames
676 PositionRowChildFrames(dx_left, aDesiredSize.ascent);
679 return NS_OK;
682 nscoord
683 nsMathMLmencloseFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
685 nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
686 if (!gap)
687 return 0;
689 // Move the MathML characters
690 nsRect rect;
691 for (PRUint32 i = 0; i < mMathMLChar.Length(); i++) {
692 mMathMLChar[i].GetRect(rect);
693 rect.MoveBy(gap, 0);
694 mMathMLChar[i].SetRect(rect);
697 return gap;
700 NS_IMETHODIMP
701 nsMathMLmencloseFrame::AttributeChanged(PRInt32 aNameSpaceID,
702 nsIAtom* aAttribute,
703 PRInt32 aModType)
705 if (aAttribute == nsGkAtoms::notation_) {
706 mNotationsToDraw = 0;
707 mLongDivCharIndex = mRadicalCharIndex = -1;
708 mMathMLChar.Clear();
710 InitNotations();
713 return nsMathMLContainerFrame::
714 AttributeChanged(aNameSpaceID, aAttribute, aModType);
717 //////////////////
718 // the Style System will use these to pass the proper style context to our
719 // MathMLChar
720 nsStyleContext*
721 nsMathMLmencloseFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
723 PRInt32 len = mMathMLChar.Length();
724 if (aIndex >= 0 && aIndex < len)
725 return mMathMLChar[aIndex].GetStyleContext();
726 else
727 return nsnull;
730 void
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
741 public:
742 nsDisplayNotation(nsDisplayListBuilder* aBuilder,
743 nsIFrame* aFrame, const nsRect& aRect,
744 nscoord aThickness, nsMencloseNotation aType)
745 : nsDisplayItem(aBuilder, aFrame), mRect(aRect),
746 mThickness(aThickness), mType(aType) {
747 MOZ_COUNT_CTOR(nsDisplayNotation);
749 #ifdef NS_BUILD_REFCNT_LOGGING
750 virtual ~nsDisplayNotation() {
751 MOZ_COUNT_DTOR(nsDisplayNotation);
753 #endif
755 virtual void Paint(nsDisplayListBuilder* aBuilder,
756 nsIRenderingContext* aCtx);
757 NS_DISPLAY_DECL_NAME("MathMLMencloseNotation", TYPE_MATHML_MENCLOSE_NOTATION)
759 private:
760 nsRect mRect;
761 nscoord mThickness;
762 nsMencloseNotation mType;
765 void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
766 nsIRenderingContext* aCtx)
768 // get the gfxRect
769 nsPresContext* presContext = mFrame->PresContext();
770 gfxRect rect = presContext->AppUnitsToGfxUnits(mRect + ToReferenceFrame());
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);
781 rect.Inset(e / 2.0);
783 gfxCtx->NewPath();
785 switch(mType)
787 case NOTATION_CIRCLE:
788 gfxCtx->Ellipse(rect.pos + rect.size / 2.0, rect.size);
789 break;
791 case NOTATION_ROUNDEDBOX:
792 gfxCtx->RoundedRectangle(rect, gfxCornerSizes(3 * e), PR_TRUE);
793 break;
795 case NOTATION_UPDIAGONALSTRIKE:
796 gfxCtx->Line(rect.BottomLeft(), rect.TopRight());
797 break;
799 case NOTATION_DOWNDIAGONALSTRIKE:
800 gfxCtx->Line(rect.TopLeft(), rect.BottomRight());
801 break;
803 default:
804 NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation");
805 break;
808 gfxCtx->Stroke();
810 // restore previous line width
811 gfxCtx->SetLineWidth(currentLineWidth);
814 nsresult
815 nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder* aBuilder,
816 nsIFrame* aFrame, const nsRect& aRect,
817 const nsDisplayListSet& aLists,
818 nscoord aThickness,
819 nsMencloseNotation aType)
821 if (!aFrame->GetStyleVisibility()->IsVisible() || aRect.IsEmpty() ||
822 aThickness <= 0)
823 return NS_OK;
825 return aLists.Content()->AppendNewToTop(new (aBuilder)
826 nsDisplayNotation(aBuilder, aFrame, aRect, aThickness, aType));