Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / mathml / base / src / nsMathMLmfencedFrame.cpp
blob6f617527f205893e9ed17a1be24a982d65fc8821
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 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 #include "nsCOMPtr.h"
43 #include "nsFrame.h"
44 #include "nsPresContext.h"
45 #include "nsStyleContext.h"
46 #include "nsStyleConsts.h"
47 #include "nsIRenderingContext.h"
48 #include "nsIFontMetrics.h"
50 #include "nsMathMLmfencedFrame.h"
53 // <mfenced> -- surround content with a pair of fences
56 nsIFrame*
57 NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
59 return new (aPresShell) nsMathMLmfencedFrame(aContext);
62 nsMathMLmfencedFrame::~nsMathMLmfencedFrame()
64 RemoveFencesAndSeparators();
67 NS_IMETHODIMP
68 nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent)
70 // let the base class get the default from our parent
71 nsMathMLContainerFrame::InheritAutomaticData(aParent);
73 mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
75 return NS_OK;
78 NS_IMETHODIMP
79 nsMathMLmfencedFrame::SetInitialChildList(nsIAtom* aListName,
80 nsIFrame* aChildList)
82 // First, let the base class do its work
83 nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListName, aChildList);
84 if (NS_FAILED(rv)) return rv;
86 // No need to tract the style contexts given to our MathML chars.
87 // The Style System will use Get/SetAdditionalStyleContext() to keep them
88 // up-to-date if dynamic changes arise.
89 return CreateFencesAndSeparators(PresContext());
92 NS_IMETHODIMP
93 nsMathMLmfencedFrame::AttributeChanged(PRInt32 aNameSpaceID,
94 nsIAtom* aAttribute,
95 PRInt32 aModType)
97 RemoveFencesAndSeparators();
98 CreateFencesAndSeparators(PresContext());
100 return nsMathMLContainerFrame::
101 AttributeChanged(aNameSpaceID, aAttribute, aModType);
104 nsresult
105 nsMathMLmfencedFrame::ChildListChanged(PRInt32 aModType)
107 RemoveFencesAndSeparators();
108 CreateFencesAndSeparators(PresContext());
110 return nsMathMLContainerFrame::ChildListChanged(aModType);
113 void
114 nsMathMLmfencedFrame::RemoveFencesAndSeparators()
116 if (mOpenChar) delete mOpenChar;
117 if (mCloseChar) delete mCloseChar;
118 if (mSeparatorsChar) delete[] mSeparatorsChar;
120 mOpenChar = nsnull;
121 mCloseChar = nsnull;
122 mSeparatorsChar = nsnull;
123 mSeparatorsCount = 0;
126 nsresult
127 nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
129 nsAutoString value;
130 PRBool isMutable = PR_FALSE;
132 //////////////
133 // see if the opening fence is there ...
134 if (!GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::open,
135 value)) {
136 value = PRUnichar('('); // default as per the MathML REC
138 else {
139 value.Trim(" ");
142 if (!value.IsEmpty()) {
143 mOpenChar = new nsMathMLChar;
144 if (!mOpenChar) return NS_ERROR_OUT_OF_MEMORY;
145 mOpenChar->SetData(aPresContext, value);
146 isMutable = nsMathMLOperators::IsMutableOperator(value);
147 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar, isMutable);
150 //////////////
151 // see if the closing fence is there ...
152 if(!GetAttribute(mContent, mPresentationData.mstyle,
153 nsGkAtoms::close, value)) {
154 value = PRUnichar(')'); // default as per the MathML REC
156 else {
157 value.Trim(" ");
160 if (!value.IsEmpty()) {
161 mCloseChar = new nsMathMLChar;
162 if (!mCloseChar) return NS_ERROR_OUT_OF_MEMORY;
163 mCloseChar->SetData(aPresContext, value);
164 isMutable = nsMathMLOperators::IsMutableOperator(value);
165 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar, isMutable);
168 //////////////
169 // see if separators are there ...
170 if(!GetAttribute(mContent, mPresentationData.mstyle,
171 nsGkAtoms::separators_, value)) {
172 value = PRUnichar(','); // default as per the MathML REC
174 else {
175 value.Trim(" ");
178 mSeparatorsCount = value.Length();
179 if (0 < mSeparatorsCount) {
180 PRInt32 sepCount = mFrames.GetLength() - 1;
181 if (0 < sepCount) {
182 mSeparatorsChar = new nsMathMLChar[sepCount];
183 if (!mSeparatorsChar) return NS_ERROR_OUT_OF_MEMORY;
184 nsAutoString sepChar;
185 for (PRInt32 i = 0; i < sepCount; i++) {
186 if (i < mSeparatorsCount) {
187 sepChar = value[i];
188 isMutable = nsMathMLOperators::IsMutableOperator(sepChar);
190 else {
191 sepChar = value[mSeparatorsCount-1];
192 // keep the value of isMutable that was set earlier
194 mSeparatorsChar[i].SetData(aPresContext, sepChar);
195 ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i], isMutable);
197 mSeparatorsCount = sepCount;
198 } else {
199 // No separators. Note that sepCount can be -1 here, so don't
200 // set mSeparatorsCount to it.
201 mSeparatorsCount = 0;
204 return NS_OK;
207 NS_IMETHODIMP
208 nsMathMLmfencedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
209 const nsRect& aDirtyRect,
210 const nsDisplayListSet& aLists)
212 /////////////
213 // display the content
214 nsresult rv = nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
215 NS_ENSURE_SUCCESS(rv, rv);
217 ////////////
218 // display fences and separators
219 if (mOpenChar) {
220 rv = mOpenChar->Display(aBuilder, this, aLists);
221 NS_ENSURE_SUCCESS(rv, rv);
224 if (mCloseChar) {
225 rv = mCloseChar->Display(aBuilder, this, aLists);
226 NS_ENSURE_SUCCESS(rv, rv);
229 for (PRInt32 i = 0; i < mSeparatorsCount; i++) {
230 rv = mSeparatorsChar[i].Display(aBuilder, this, aLists);
231 NS_ENSURE_SUCCESS(rv, rv);
233 return NS_OK;
236 NS_IMETHODIMP
237 nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext,
238 nsHTMLReflowMetrics& aDesiredSize,
239 const nsHTMLReflowState& aReflowState,
240 nsReflowStatus& aStatus)
242 return doReflow(aPresContext, aReflowState, aDesiredSize, aStatus, this,
243 mOpenChar, mCloseChar, mSeparatorsChar, mSeparatorsCount);
246 /* virtual */ nscoord
247 nsMathMLmfencedFrame::GetIntrinsicWidth(nsIRenderingContext* aRenderingContext)
249 return doGetIntrinsicWidth(aRenderingContext, this, mOpenChar, mCloseChar,
250 mSeparatorsChar, mSeparatorsCount);
253 // exported routine that both mfenced and mfrac share.
254 // mfrac uses this when its bevelled attribute is set.
255 /*static*/ nsresult
256 nsMathMLmfencedFrame::doReflow(nsPresContext* aPresContext,
257 const nsHTMLReflowState& aReflowState,
258 nsHTMLReflowMetrics& aDesiredSize,
259 nsReflowStatus& aStatus,
260 nsMathMLContainerFrame* aForFrame,
261 nsMathMLChar* aOpenChar,
262 nsMathMLChar* aCloseChar,
263 nsMathMLChar* aSeparatorsChar,
264 PRInt32 aSeparatorsCount)
267 nsresult rv;
268 aDesiredSize.width = aDesiredSize.height = 0;
269 aDesiredSize.ascent = 0;
270 aDesiredSize.mBoundingMetrics.Clear();
272 PRInt32 i;
273 nsCOMPtr<nsIFontMetrics> fm;
274 const nsStyleFont* font = aForFrame->GetStyleFont();
275 aReflowState.rendContext->SetFont(font->mFont, nsnull,
276 aPresContext->GetUserFontSet());
277 aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
278 nscoord axisHeight, em;
279 GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
280 GetEmHeight(fm, em);
281 // leading to be left at the top and the bottom of stretched chars
282 nscoord leading = NSToCoordRound(0.2f * em);
284 /////////////
285 // Reflow children
286 // Asking each child to cache its bounding metrics
288 // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
289 // because we want to stretch our fences, separators and stretchy frames using
290 // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
291 // method here, our stretchy frames will be stretched and placed, and we may
292 // end up stretching our fences/separators with a different aDesiredSize.
293 // XXX The above decision was revisited in bug 121748 and this code can be
294 // refactored to use nsMathMLContainerFrame::Reflow() at some stage.
296 nsReflowStatus childStatus;
297 nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
298 nsIFrame* firstChild = aForFrame->GetFirstChild(nsnull);
299 nsIFrame* childFrame = firstChild;
300 nscoord ascent = 0, descent = 0;
301 if (firstChild || aOpenChar || aCloseChar || aSeparatorsCount > 0) {
302 // We use the ASCII metrics to get our minimum height. This way, if we have
303 // borders or a background, they will fit better with other elements on the line
304 fm->GetMaxAscent(ascent);
305 fm->GetMaxDescent(descent);
307 while (childFrame) {
308 nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags
309 | NS_REFLOW_CALC_BOUNDING_METRICS);
310 nsHTMLReflowState childReflowState(aPresContext, aReflowState,
311 childFrame, availSize);
312 rv = aForFrame->ReflowChild(childFrame, aPresContext, childDesiredSize,
313 childReflowState, childStatus);
314 //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
315 if (NS_FAILED(rv)) {
316 // Call DidReflow() for the child frames we successfully did reflow.
317 aForFrame->DidReflowChildren(firstChild, childFrame);
318 return rv;
321 SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
322 childDesiredSize.mBoundingMetrics);
324 // compute the bounding metrics right now for mfrac
325 nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent;
326 if (descent < childDescent)
327 descent = childDescent;
328 if (ascent < childDesiredSize.ascent)
329 ascent = childDesiredSize.ascent;
330 aDesiredSize.mBoundingMetrics += childDesiredSize.mBoundingMetrics;
332 childFrame = childFrame->GetNextSibling();
335 /////////////
336 // Ask stretchy children to stretch themselves
338 nsBoundingMetrics containerSize;
339 nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;
341 nsPresentationData presentationData;
342 aForFrame->GetPresentationData(presentationData);
343 if (!NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags)) {
344 // case when the call is made for mfrac, we only need to stretch the '/' separator
345 containerSize = aDesiredSize.mBoundingMetrics; // computed earlier
347 else {
348 // case when the call is made for mfenced
349 aForFrame->GetPreferredStretchSize(*aReflowState.rendContext,
350 0, /* i.e., without embellishments */
351 stretchDir, containerSize);
352 childFrame = firstChild;
353 while (childFrame) {
354 nsIMathMLFrame* mathmlChild;
355 childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathmlChild);
356 if (mathmlChild) {
357 nsHTMLReflowMetrics childDesiredSize;
358 // retrieve the metrics that was stored at the previous pass
359 GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
360 childDesiredSize.mBoundingMetrics);
362 mathmlChild->Stretch(*aReflowState.rendContext,
363 stretchDir, containerSize, childDesiredSize);
364 // store the updated metrics
365 SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
366 childDesiredSize.mBoundingMetrics);
368 nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent;
369 if (descent < childDescent)
370 descent = childDescent;
371 if (ascent < childDesiredSize.ascent)
372 ascent = childDesiredSize.ascent;
374 childFrame = childFrame->GetNextSibling();
376 // bug 121748: for surrounding fences & separators, use a size that covers everything
377 aForFrame->GetPreferredStretchSize(*aReflowState.rendContext,
378 STRETCH_CONSIDER_EMBELLISHMENTS,
379 stretchDir, containerSize);
382 //////////////////////////////////////////
383 // Prepare the opening fence, separators, and closing fence, and
384 // adjust the origin of children.
386 // we need to center around the axis
387 if (firstChild) { // do nothing for an empty <mfenced></mfenced>
388 nscoord delta = PR_MAX(containerSize.ascent - axisHeight,
389 containerSize.descent + axisHeight);
390 containerSize.ascent = delta + axisHeight;
391 containerSize.descent = delta - axisHeight;
394 /////////////////
395 // opening fence ...
396 ReflowChar(aPresContext, *aReflowState.rendContext, aOpenChar,
397 NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel,
398 axisHeight, leading, em, containerSize, ascent, descent);
399 /////////////////
400 // separators ...
401 for (i = 0; i < aSeparatorsCount; i++) {
402 ReflowChar(aPresContext, *aReflowState.rendContext, &aSeparatorsChar[i],
403 NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
404 axisHeight, leading, em, containerSize, ascent, descent);
406 /////////////////
407 // closing fence ...
408 ReflowChar(aPresContext, *aReflowState.rendContext, aCloseChar,
409 NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
410 axisHeight, leading, em, containerSize, ascent, descent);
412 //////////////////
413 // Adjust the origins of each child.
414 // and update our bounding metrics
416 i = 0;
417 nscoord dx = 0;
418 nsBoundingMetrics bm;
419 PRBool firstTime = PR_TRUE;
420 if (aOpenChar) {
421 PlaceChar(aOpenChar, ascent, bm, dx);
422 aDesiredSize.mBoundingMetrics = bm;
423 firstTime = PR_FALSE;
426 childFrame = firstChild;
427 while (childFrame) {
428 nsHTMLReflowMetrics childSize;
429 GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
430 if (firstTime) {
431 firstTime = PR_FALSE;
432 aDesiredSize.mBoundingMetrics = bm;
434 else
435 aDesiredSize.mBoundingMetrics += bm;
437 aForFrame->FinishReflowChild(childFrame, aPresContext, nsnull, childSize,
438 dx, ascent - childSize.ascent, 0);
439 dx += childSize.width;
441 if (i < aSeparatorsCount) {
442 PlaceChar(&aSeparatorsChar[i], ascent, bm, dx);
443 aDesiredSize.mBoundingMetrics += bm;
445 i++;
447 childFrame = childFrame->GetNextSibling();
450 if (aCloseChar) {
451 PlaceChar(aCloseChar, ascent, bm, dx);
452 if (firstTime)
453 aDesiredSize.mBoundingMetrics = bm;
454 else
455 aDesiredSize.mBoundingMetrics += bm;
458 aDesiredSize.width = aDesiredSize.mBoundingMetrics.width;
459 aDesiredSize.height = ascent + descent;
460 aDesiredSize.ascent = ascent;
462 aForFrame->SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
463 aForFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
465 // see if we should fix the spacing
466 aForFrame->FixInterFrameSpacing(aDesiredSize);
468 // Finished with these:
469 aForFrame->ClearSavedChildMetrics();
471 // Set our overflow area
472 aForFrame->GatherAndStoreOverflow(&aDesiredSize);
474 aStatus = NS_FRAME_COMPLETE;
475 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
476 return NS_OK;
479 static void
480 GetCharSpacing(nsMathMLChar* aMathMLChar,
481 nsOperatorFlags aForm,
482 PRInt32 aScriptLevel,
483 nscoord em,
484 nscoord& aLeftSpace,
485 nscoord& aRightSpace)
487 nsAutoString data;
488 aMathMLChar->GetData(data);
489 nsOperatorFlags flags = 0;
490 float lspace = 0.0f;
491 float rspace = 0.0f;
492 PRBool found = nsMathMLOperators::LookupOperator(data, aForm,
493 &flags, &lspace, &rspace);
495 // We don't want extra space when we are a script
496 if (found && aScriptLevel > 0) {
497 lspace /= 2.0f;
498 rspace /= 2.0f;
501 aLeftSpace = NSToCoordRound(lspace * em);
502 aRightSpace = NSToCoordRound(rspace * em);
505 // helper functions to perform the common task of formatting our chars
506 /*static*/ nsresult
507 nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext,
508 nsIRenderingContext& aRenderingContext,
509 nsMathMLChar* aMathMLChar,
510 nsOperatorFlags aForm,
511 PRInt32 aScriptLevel,
512 nscoord axisHeight,
513 nscoord leading,
514 nscoord em,
515 nsBoundingMetrics& aContainerSize,
516 nscoord& aAscent,
517 nscoord& aDescent)
519 if (aMathMLChar && 0 < aMathMLChar->Length()) {
520 nscoord leftSpace;
521 nscoord rightSpace;
522 GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
524 // stretch the char to the appropriate height if it is not big enough.
525 nsBoundingMetrics charSize;
526 nsresult res = aMathMLChar->Stretch(aPresContext, aRenderingContext,
527 NS_STRETCH_DIRECTION_VERTICAL,
528 aContainerSize, charSize);
530 if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
531 // has changed... so center the char around the axis
532 nscoord height = charSize.ascent + charSize.descent;
533 charSize.ascent = height/2 + axisHeight;
534 charSize.descent = height - charSize.ascent;
536 else {
537 // either it hasn't changed or stretching the char failed (i.e.,
538 // GetBoundingMetrics failed)
539 leading = 0;
540 if (NS_FAILED(res)) {
541 nsAutoString data;
542 aMathMLChar->GetData(data);
543 nsTextDimensions dimensions;
544 aRenderingContext.GetTextDimensions(data.get(), data.Length(), dimensions);
545 charSize.ascent = dimensions.ascent;
546 charSize.descent = dimensions.descent;
547 charSize.width = dimensions.width;
548 // Set this as the bounding metrics of the MathMLChar to leave
549 // the necessary room to paint the char.
550 aMathMLChar->SetBoundingMetrics(charSize);
554 if (aAscent < charSize.ascent + leading)
555 aAscent = charSize.ascent + leading;
556 if (aDescent < charSize.descent + leading)
557 aDescent = charSize.descent + leading;
559 // account the spacing
560 charSize.width += leftSpace + rightSpace;
562 // x-origin is used to store lspace ...
563 // y-origin is used to stored the ascent ...
564 aMathMLChar->SetRect(nsRect(leftSpace,
565 charSize.ascent, charSize.width,
566 charSize.ascent + charSize.descent));
568 return NS_OK;
571 /*static*/ void
572 nsMathMLmfencedFrame::PlaceChar(nsMathMLChar* aMathMLChar,
573 nscoord aDesiredAscent,
574 nsBoundingMetrics& bm,
575 nscoord& dx)
577 aMathMLChar->GetBoundingMetrics(bm);
579 // the char's x-origin was used to store lspace ...
580 // the char's y-origin was used to store the ascent ...
581 // the char's width was used to store the advance with (with spacing) ...
582 nsRect rect;
583 aMathMLChar->GetRect(rect);
585 nscoord dy = aDesiredAscent - rect.y;
586 if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) {
587 // the stretchy char will be centered around the axis
588 // so we adjust the returned bounding metrics accordingly
589 bm.descent = (bm.ascent + bm.descent) - rect.y;
590 bm.ascent = rect.y;
593 aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height));
595 bm.leftBearing += rect.x;
596 bm.rightBearing += rect.x;
598 // return rect.width since it includes lspace and rspace
599 bm.width = rect.width;
600 dx += rect.width;
603 static nscoord
604 GetMaxCharWidth(nsPresContext* aPresContext,
605 nsIRenderingContext* aRenderingContext,
606 nsMathMLChar* aMathMLChar,
607 nsOperatorFlags aForm,
608 PRInt32 aScriptLevel,
609 nscoord em)
611 nscoord width = aMathMLChar->GetMaxWidth(aPresContext, *aRenderingContext);
613 if (0 < aMathMLChar->Length()) {
614 nscoord leftSpace;
615 nscoord rightSpace;
616 GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
618 width += leftSpace + rightSpace;
621 return width;
624 /* virtual */ nscoord
625 nsMathMLmfencedFrame::doGetIntrinsicWidth(nsIRenderingContext* aRenderingContext,
626 nsMathMLContainerFrame* aForFrame,
627 nsMathMLChar* aOpenChar,
628 nsMathMLChar* aCloseChar,
629 nsMathMLChar* aSeparatorsChar,
630 PRInt32 aSeparatorsCount)
632 nscoord width = 0;
634 nsPresContext* presContext = aForFrame->PresContext();
635 const nsStyleFont* font = aForFrame->GetStyleFont();
636 nsCOMPtr<nsIFontMetrics> fm = presContext->GetMetricsFor(font->mFont);
637 nscoord em;
638 GetEmHeight(fm, em);
640 if (aOpenChar) {
641 width +=
642 GetMaxCharWidth(presContext, aRenderingContext, aOpenChar,
643 NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em);
646 PRInt32 i = 0;
647 nsIFrame* childFrame = aForFrame->GetFirstChild(nsnull);
648 while (childFrame) {
649 // XXX This includes margin while Reflow currently doesn't consider
650 // margin, so we may end up with too much space, but, with stretchy
651 // characters, this is an approximation anyway.
652 width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
653 nsLayoutUtils::PREF_WIDTH);
655 if (i < aSeparatorsCount) {
656 width +=
657 GetMaxCharWidth(presContext, aRenderingContext, &aSeparatorsChar[i],
658 NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em);
660 i++;
662 childFrame = childFrame->GetNextSibling();
665 if (aCloseChar) {
666 width +=
667 GetMaxCharWidth(presContext, aRenderingContext, aCloseChar,
668 NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
671 return width;
674 nscoord
675 nsMathMLmfencedFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
677 nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
678 if (!gap) return 0;
680 nsRect rect;
681 if (mOpenChar) {
682 mOpenChar->GetRect(rect);
683 rect.MoveBy(gap, 0);
684 mOpenChar->SetRect(rect);
686 if (mCloseChar) {
687 mCloseChar->GetRect(rect);
688 rect.MoveBy(gap, 0);
689 mCloseChar->SetRect(rect);
691 for (PRInt32 i = 0; i < mSeparatorsCount; i++) {
692 mSeparatorsChar[i].GetRect(rect);
693 rect.MoveBy(gap, 0);
694 mSeparatorsChar[i].SetRect(rect);
696 return gap;
699 // ----------------------
700 // the Style System will use these to pass the proper style context to our MathMLChar
701 nsStyleContext*
702 nsMathMLmfencedFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
704 PRInt32 openIndex = -1;
705 PRInt32 closeIndex = -1;
706 PRInt32 lastIndex = mSeparatorsCount-1;
708 if (mOpenChar) {
709 lastIndex++;
710 openIndex = lastIndex;
712 if (mCloseChar) {
713 lastIndex++;
714 closeIndex = lastIndex;
716 if (aIndex < 0 || aIndex > lastIndex) {
717 return nsnull;
720 if (aIndex < mSeparatorsCount) {
721 return mSeparatorsChar[aIndex].GetStyleContext();
723 else if (aIndex == openIndex) {
724 return mOpenChar->GetStyleContext();
726 else if (aIndex == closeIndex) {
727 return mCloseChar->GetStyleContext();
729 return nsnull;
732 void
733 nsMathMLmfencedFrame::SetAdditionalStyleContext(PRInt32 aIndex,
734 nsStyleContext* aStyleContext)
736 PRInt32 openIndex = -1;
737 PRInt32 closeIndex = -1;
738 PRInt32 lastIndex = mSeparatorsCount-1;
740 if (mOpenChar) {
741 lastIndex++;
742 openIndex = lastIndex;
744 if (mCloseChar) {
745 lastIndex++;
746 closeIndex = lastIndex;
748 if (aIndex < 0 || aIndex > lastIndex) {
749 return;
752 if (aIndex < mSeparatorsCount) {
753 mSeparatorsChar[aIndex].SetStyleContext(aStyleContext);
755 else if (aIndex == openIndex) {
756 mOpenChar->SetStyleContext(aStyleContext);
758 else if (aIndex == closeIndex) {
759 mCloseChar->SetStyleContext(aStyleContext);