Back to index

lightning-sunbird  0.9+nobinonly
nsMathMLmfencedFrame.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla MathML Project.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * The University Of Queensland.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Roger B. Sidje <rbs@maths.uq.edu.au>
00023  *   David J. Fiddes <D.J.Fiddes@hw.ac.uk>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include "nsCOMPtr.h"
00042 #include "nsFrame.h"
00043 #include "nsPresContext.h"
00044 #include "nsUnitConversion.h"
00045 #include "nsStyleContext.h"
00046 #include "nsStyleConsts.h"
00047 #include "nsIRenderingContext.h"
00048 #include "nsIFontMetrics.h"
00049 
00050 #include "nsMathMLmfencedFrame.h"
00051 
00052 //
00053 // <mfenced> -- surround content with a pair of fences
00054 //
00055 
00056 nsresult
00057 NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00058 {
00059   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00060   if (nsnull == aNewFrame) {
00061     return NS_ERROR_NULL_POINTER;
00062   }
00063   nsMathMLmfencedFrame* it = new (aPresShell) nsMathMLmfencedFrame;
00064   if (nsnull == it) {
00065     return NS_ERROR_OUT_OF_MEMORY;
00066   }
00067   *aNewFrame = it;  
00068   return NS_OK;
00069 }
00070 
00071 nsMathMLmfencedFrame::nsMathMLmfencedFrame()
00072 {
00073 }
00074 
00075 nsMathMLmfencedFrame::~nsMathMLmfencedFrame()
00076 {
00077   RemoveFencesAndSeparators();
00078 }
00079 
00080 NS_IMETHODIMP
00081 nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent)
00082 {
00083   // let the base class get the default from our parent
00084   nsMathMLContainerFrame::InheritAutomaticData(aParent);
00085 
00086   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
00087 
00088   return NS_OK;
00089 }
00090 
00091 NS_IMETHODIMP
00092 nsMathMLmfencedFrame::SetInitialChildList(nsPresContext* aPresContext,
00093                                           nsIAtom*        aListName,
00094                                           nsIFrame*       aChildList)
00095 {
00096   // First, let the base class do its work
00097   nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList);
00098   if (NS_FAILED(rv)) return rv;
00099 
00100   // No need to tract the style contexts given to our MathML chars. 
00101   // The Style System will use Get/SetAdditionalStyleContext() to keep them
00102   // up-to-date if dynamic changes arise.
00103   return CreateFencesAndSeparators(aPresContext);
00104 }
00105 
00106 NS_IMETHODIMP
00107 nsMathMLmfencedFrame::AttributeChanged(nsIContent*     aContent,
00108                                        PRInt32         aNameSpaceID,
00109                                        nsIAtom*        aAttribute,
00110                                        PRInt32         aModType)
00111 {
00112   RemoveFencesAndSeparators();
00113   CreateFencesAndSeparators(GetPresContext());
00114 
00115   return nsMathMLContainerFrame::
00116          AttributeChanged(aContent, aNameSpaceID,
00117                           aAttribute, aModType);
00118 }
00119 
00120 nsresult
00121 nsMathMLmfencedFrame::ChildListChanged(PRInt32 aModType)
00122 {
00123   RemoveFencesAndSeparators();
00124   CreateFencesAndSeparators(GetPresContext());
00125 
00126   return nsMathMLContainerFrame::ChildListChanged(aModType);
00127 }
00128 
00129 void
00130 nsMathMLmfencedFrame::RemoveFencesAndSeparators()
00131 {
00132   if (mOpenChar) delete mOpenChar;
00133   if (mCloseChar) delete mCloseChar;
00134   if (mSeparatorsChar) delete[] mSeparatorsChar;
00135 
00136   mOpenChar = nsnull;
00137   mCloseChar = nsnull;
00138   mSeparatorsChar = nsnull;
00139   mSeparatorsCount = 0;
00140 }
00141 
00142 nsresult
00143 nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
00144 {
00145   nsresult rv;
00146   nsAutoString value, data;
00147   PRBool isMutable = PR_FALSE;
00148 
00150   // see if the opening fence is there ...
00151   rv = GetAttribute(mContent, mPresentationData.mstyle,
00152                     nsMathMLAtoms::open_, value);
00153   if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
00154     value.Trim(" ");
00155     data = value;
00156   }
00157   else if (NS_CONTENT_ATTR_NOT_THERE == rv)
00158     data = PRUnichar('('); // default as per the MathML REC
00159   else
00160     data.Truncate();
00161 
00162   if (!data.IsEmpty()) {
00163     mOpenChar = new nsMathMLChar;
00164     if (!mOpenChar) return NS_ERROR_OUT_OF_MEMORY;
00165     mOpenChar->SetData(aPresContext, data);
00166     isMutable = nsMathMLOperators::IsMutableOperator(data);
00167     ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar, isMutable);
00168   }
00169 
00171   // see if the closing fence is there ...
00172   rv = GetAttribute(mContent, mPresentationData.mstyle,
00173                     nsMathMLAtoms::close_, value);
00174   if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
00175     value.Trim(" ");
00176     data = value;
00177   }
00178   else if (NS_CONTENT_ATTR_NOT_THERE == rv)
00179     data = PRUnichar(')'); // default as per the MathML REC
00180   else
00181     data.Truncate();
00182 
00183   if (!data.IsEmpty()) {
00184     mCloseChar = new nsMathMLChar;
00185     if (!mCloseChar) return NS_ERROR_OUT_OF_MEMORY;
00186     mCloseChar->SetData(aPresContext, data);
00187     isMutable = nsMathMLOperators::IsMutableOperator(data);
00188     ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar, isMutable);
00189   }
00190 
00192   // see if separators are there ...
00193   rv = GetAttribute(mContent, mPresentationData.mstyle, 
00194                     nsMathMLAtoms::separators_, value);
00195   if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
00196     value.Trim(" ");
00197     data = value;
00198   }
00199   else if (NS_CONTENT_ATTR_NOT_THERE == rv)
00200     data = PRUnichar(','); // default as per the MathML REC
00201   else
00202     data.Truncate();
00203 
00204   mSeparatorsCount = data.Length();
00205   if (0 < mSeparatorsCount) {
00206     PRInt32 sepCount = mFrames.GetLength() - 1;
00207     if (0 < sepCount) {
00208       mSeparatorsChar = new nsMathMLChar[sepCount];
00209       if (!mSeparatorsChar) return NS_ERROR_OUT_OF_MEMORY;
00210       nsAutoString sepChar;
00211       for (PRInt32 i = 0; i < sepCount; i++) {
00212         if (i < mSeparatorsCount) {
00213           sepChar = data[i];
00214           isMutable = nsMathMLOperators::IsMutableOperator(sepChar);
00215         }
00216         else {
00217           sepChar = data[mSeparatorsCount-1];
00218           // keep the value of isMutable that was set earlier
00219         }
00220         mSeparatorsChar[i].SetData(aPresContext, sepChar);
00221         ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i], isMutable);
00222       }
00223     }
00224     mSeparatorsCount = sepCount;
00225   }
00226   return NS_OK;
00227 }
00228 
00229 NS_IMETHODIMP
00230 nsMathMLmfencedFrame::Paint(nsPresContext*      aPresContext,
00231                             nsIRenderingContext& aRenderingContext,
00232                             const nsRect&        aDirtyRect,
00233                             nsFramePaintLayer    aWhichLayer,
00234                             PRUint32             aFlags)
00235 {
00237   // paint the content
00238   nsresult rv = nsMathMLContainerFrame::Paint(aPresContext, aRenderingContext, 
00239                                               aDirtyRect, aWhichLayer);
00241   // paint fences and separators
00242   if (NS_SUCCEEDED(rv)) {
00243     if (mOpenChar) mOpenChar->Paint(aPresContext, aRenderingContext,
00244                                     aDirtyRect, aWhichLayer, this);
00245     if (mCloseChar) mCloseChar->Paint(aPresContext, aRenderingContext,
00246                                       aDirtyRect, aWhichLayer, this);
00247     for (PRInt32 i = 0; i < mSeparatorsCount; i++) {
00248       mSeparatorsChar[i].Paint(aPresContext, aRenderingContext,
00249                                aDirtyRect, aWhichLayer, this);
00250     }
00251   }
00252   return rv;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsMathMLmfencedFrame::Reflow(nsPresContext*          aPresContext,
00257                              nsHTMLReflowMetrics&     aDesiredSize,
00258                              const nsHTMLReflowState& aReflowState,
00259                              nsReflowStatus&          aStatus)
00260 {
00261   return doReflow(aPresContext, aReflowState, aDesiredSize, aStatus, this,
00262                   mOpenChar, mCloseChar, mSeparatorsChar, mSeparatorsCount);
00263 }
00264 
00265 // exported routine that both mfenced and mfrac share.
00266 // mfrac uses this when its bevelled attribute is set.
00267 /*static*/ nsresult
00268 nsMathMLmfencedFrame::doReflow(nsPresContext*          aPresContext,
00269                                const nsHTMLReflowState& aReflowState,
00270                                nsHTMLReflowMetrics&     aDesiredSize,
00271                                nsReflowStatus&          aStatus,
00272                                nsIFrame*                aForFrame,
00273                                nsMathMLChar*            aOpenChar,
00274                                nsMathMLChar*            aCloseChar,
00275                                nsMathMLChar*            aSeparatorsChar,
00276                                PRInt32                  aSeparatorsCount)
00277 
00278 {
00279   nsresult rv;
00280   aDesiredSize.width = aDesiredSize.height = 0;
00281   aDesiredSize.ascent = aDesiredSize.descent = 0;
00282   aDesiredSize.mBoundingMetrics.Clear();
00283 
00284   nsMathMLContainerFrame* mathMLFrame =
00285     NS_STATIC_CAST(nsMathMLContainerFrame*, aForFrame);
00286 
00287   PRInt32 i;
00288   nsCOMPtr<nsIFontMetrics> fm;
00289   aReflowState.rendContext->SetFont(aForFrame->GetStyleFont()->mFont, nsnull);
00290   aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
00291   nscoord axisHeight, em;
00292   GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
00293   GetEmHeight(fm, em);
00294   // leading to be left at the top and the bottom of stretched chars
00295   nscoord leading = NSToCoordRound(0.2f * em); 
00296 
00298   // Reflow children
00299   // Asking each child to cache its bounding metrics
00300 
00301   // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
00302   // because we want to stretch our fences, separators and stretchy frames using
00303   // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
00304   // method here, our stretchy frames will be stretched and placed, and we may
00305   // end up stretching our fences/separators with a different aDesiredSize.
00306   // XXX The above decision was revisited in bug 121748 and this code can be
00307   // refactored to use nsMathMLContainerFrame::Reflow() at some stage.
00308 
00309   PRInt32 count = 0;
00310   nsReflowStatus childStatus;
00311   nsSize availSize(aReflowState.mComputedWidth, aReflowState.mComputedHeight);
00312   nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mComputeMEW, 
00313                       aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS);
00314   nsIFrame* firstChild = aForFrame->GetFirstChild(nsnull);
00315   nsIFrame* childFrame = firstChild;
00316   if (firstChild || aOpenChar || aCloseChar || aSeparatorsCount > 0) {
00317     // We use the ASCII metrics to get our minimum height. This way, if we have
00318     // borders or a background, they will fit better with other elements on the line
00319     fm->GetMaxAscent(aDesiredSize.ascent);
00320     fm->GetMaxDescent(aDesiredSize.descent);
00321   }
00322   while (childFrame) {
00323     nsReflowReason reason = (childFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)
00324       ? eReflowReason_Initial : aReflowState.reason;
00325     nsHTMLReflowState childReflowState(aPresContext, aReflowState,
00326                                        childFrame, availSize, reason);
00327     rv = mathMLFrame->ReflowChild(childFrame, aPresContext, childDesiredSize,
00328                                   childReflowState, childStatus);
00329     //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
00330     if (NS_FAILED(rv)) return rv;
00331 
00332     // At this stage, the origin points of the children have no use, so we will use the
00333     // origins as placeholders to store the child's ascent and descent. Later on,
00334     // we should set the origins so as to overwrite what we are storing there now.
00335     childFrame->SetRect(nsRect(childDesiredSize.descent, childDesiredSize.ascent,
00336                                childDesiredSize.width, childDesiredSize.height));
00337 
00338     // compute the bounding metrics right now for mfrac
00339     if (aDesiredSize.descent < childDesiredSize.descent)
00340       aDesiredSize.descent = childDesiredSize.descent;
00341     if (aDesiredSize.ascent < childDesiredSize.ascent)
00342       aDesiredSize.ascent = childDesiredSize.ascent;
00343     if (0 == count++)
00344       aDesiredSize.mBoundingMetrics  = childDesiredSize.mBoundingMetrics;
00345     else
00346       aDesiredSize.mBoundingMetrics += childDesiredSize.mBoundingMetrics;
00347 
00348     childFrame = childFrame->GetNextSibling();
00349   }
00350 
00352   // Ask stretchy children to stretch themselves
00353 
00354   nsBoundingMetrics containerSize;
00355   nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;
00356 
00357   nsPresentationData presentationData;
00358   mathMLFrame->GetPresentationData(presentationData);
00359   if (!NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags)) {
00360     // case when the call is made for mfrac, we only need to stretch the '/' separator
00361     containerSize = aDesiredSize.mBoundingMetrics; // computed earlier
00362   }
00363   else {
00364     // case when the call is made for mfenced
00365     mathMLFrame->GetPreferredStretchSize(*aReflowState.rendContext,
00366                                          0, /* i.e., without embellishments */
00367                                          stretchDir, containerSize);
00368     childFrame = firstChild;
00369     while (childFrame) {
00370       nsIMathMLFrame* mathmlChild;
00371       childFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathmlChild);
00372       if (mathmlChild) {
00373         // retrieve the metrics that was stored at the previous pass
00374         GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics);
00375 
00376         mathmlChild->Stretch(*aReflowState.rendContext, 
00377                              stretchDir, containerSize, childDesiredSize);
00378         // store the updated metrics
00379         childFrame->SetRect(nsRect(childDesiredSize.descent, childDesiredSize.ascent,
00380                                    childDesiredSize.width, childDesiredSize.height));
00381 
00382         if (aDesiredSize.descent < childDesiredSize.descent)
00383           aDesiredSize.descent = childDesiredSize.descent;
00384         if (aDesiredSize.ascent < childDesiredSize.ascent)
00385           aDesiredSize.ascent = childDesiredSize.ascent;
00386       }
00387       childFrame = childFrame->GetNextSibling();
00388     }
00389     // bug 121748: for surrounding fences & separators, use a size that covers everything
00390     mathMLFrame->GetPreferredStretchSize(*aReflowState.rendContext,
00391                                          STRETCH_CONSIDER_EMBELLISHMENTS,
00392                                          stretchDir, containerSize);
00393   }
00394   if (aDesiredSize.mComputeMEW) {
00395     aDesiredSize.mMaxElementWidth = childDesiredSize.mMaxElementWidth;
00396   }
00397 
00399   // Prepare the opening fence, separators, and closing fence, and
00400   // adjust the origin of children.
00401 
00402   // we need to center around the axis
00403   if (firstChild) { // do nothing for an empty <mfenced></mfenced>
00404     nscoord delta = PR_MAX(containerSize.ascent - axisHeight, 
00405                            containerSize.descent + axisHeight);
00406     containerSize.ascent = delta + axisHeight;
00407     containerSize.descent = delta - axisHeight;
00408   }
00409 
00411   // opening fence ...
00412   ReflowChar(aPresContext, *aReflowState.rendContext, aOpenChar,
00413              NS_MATHML_OPERATOR_FORM_PREFIX, presentationData.scriptLevel, 
00414              axisHeight, leading, em, containerSize, aDesiredSize);
00416   // separators ...
00417   for (i = 0; i < aSeparatorsCount; i++) {
00418     ReflowChar(aPresContext, *aReflowState.rendContext, &aSeparatorsChar[i],
00419                NS_MATHML_OPERATOR_FORM_INFIX, presentationData.scriptLevel,
00420                axisHeight, leading, em, containerSize, aDesiredSize);
00421   }
00423   // closing fence ...
00424   ReflowChar(aPresContext, *aReflowState.rendContext, aCloseChar,
00425              NS_MATHML_OPERATOR_FORM_POSTFIX, presentationData.scriptLevel,
00426              axisHeight, leading, em, containerSize, aDesiredSize);
00427 
00429   // Adjust the origins of each child.
00430   // and update our bounding metrics
00431 
00432   i = 0;
00433   nscoord dx = 0;
00434   nsBoundingMetrics bm;
00435   PRBool firstTime = PR_TRUE;
00436   if (aOpenChar) {
00437     PlaceChar(aOpenChar, aDesiredSize.ascent, bm, dx);
00438     aDesiredSize.mBoundingMetrics = bm;
00439     firstTime = PR_FALSE;
00440   }
00441 
00442   childFrame = firstChild;
00443   while (childFrame) {
00444     nsHTMLReflowMetrics childSize(nsnull);
00445     GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
00446     if (firstTime) {
00447       firstTime = PR_FALSE;
00448       aDesiredSize.mBoundingMetrics  = bm;
00449     }
00450     else  
00451       aDesiredSize.mBoundingMetrics += bm;
00452 
00453     mathMLFrame->FinishReflowChild(childFrame, aPresContext, nsnull, childSize, 
00454                                    dx, aDesiredSize.ascent - childSize.ascent, 0);
00455     dx += childSize.width;
00456 
00457     if (i < aSeparatorsCount) {
00458       PlaceChar(&aSeparatorsChar[i], aDesiredSize.ascent, bm, dx);
00459       aDesiredSize.mBoundingMetrics += bm;
00460     }
00461     i++;
00462 
00463     childFrame = childFrame->GetNextSibling();
00464   }
00465 
00466   if (aCloseChar) {
00467     PlaceChar(aCloseChar, aDesiredSize.ascent, bm, dx);
00468     if (firstTime)
00469       aDesiredSize.mBoundingMetrics  = bm;
00470     else  
00471       aDesiredSize.mBoundingMetrics += bm;
00472   }
00473 
00474   aDesiredSize.width = aDesiredSize.mBoundingMetrics.width;
00475   aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
00476 
00477   if (aDesiredSize.mComputeMEW) {
00478     aDesiredSize.mMaxElementWidth = aDesiredSize.width;
00479   }
00480 
00481   mathMLFrame->SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
00482   mathMLFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
00483 
00484   // see if we should fix the spacing
00485   mathMLFrame->FixInterFrameSpacing(aDesiredSize);
00486 
00487   aStatus = NS_FRAME_COMPLETE;
00488   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00489   return NS_OK;
00490 }
00491 
00492 // helper functions to perform the common task of formatting our chars
00493 /*static*/ nsresult
00494 nsMathMLmfencedFrame::ReflowChar(nsPresContext*      aPresContext,
00495                                  nsIRenderingContext& aRenderingContext,
00496                                  nsMathMLChar*        aMathMLChar,
00497                                  nsOperatorFlags      aForm,
00498                                  PRInt32              aScriptLevel,
00499                                  nscoord              axisHeight,
00500                                  nscoord              leading,
00501                                  nscoord              em,
00502                                  nsBoundingMetrics&   aContainerSize,
00503                                  nsHTMLReflowMetrics& aDesiredSize)
00504 {
00505   if (aMathMLChar && 0 < aMathMLChar->Length()) {
00506     nsOperatorFlags flags = 0;
00507     float leftSpace = 0.0f;
00508     float rightSpace = 0.0f;
00509 
00510     nsAutoString data;
00511     aMathMLChar->GetData(data);
00512     PRBool found = nsMathMLOperators::LookupOperator(data, aForm,              
00513                                            &flags, &leftSpace, &rightSpace);
00514 
00515     // If we don't want extra space when we are a script
00516     if (found && aScriptLevel > 0) {
00517       leftSpace /= 2.0f;
00518       rightSpace /= 2.0f;
00519     }
00520 
00521     // stretch the char to the appropriate height if it is not big enough.
00522     nsBoundingMetrics charSize;
00523     nsresult res = aMathMLChar->Stretch(aPresContext, aRenderingContext,
00524                                         NS_STRETCH_DIRECTION_VERTICAL,
00525                                         aContainerSize, charSize);
00526 
00527     if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
00528       // has changed... so center the char around the axis
00529       nscoord height = charSize.ascent + charSize.descent;
00530       charSize.ascent = height/2 + axisHeight;
00531       charSize.descent = height - charSize.ascent;
00532     }
00533     else {
00534       // either it hasn't changed or stretching the char failed (i.e.,
00535       // GetBoundingMetrics failed)
00536       leading = 0;
00537       if (NS_FAILED(res)) {
00538         nsTextDimensions dimensions;
00539         aRenderingContext.GetTextDimensions(data.get(), data.Length(), dimensions);
00540         charSize.ascent = dimensions.ascent;
00541         charSize.descent = dimensions.descent;
00542         charSize.width = dimensions.width;
00543         // Set this as the bounding metrics of the MathMLChar to leave
00544         // the necessary room to paint the char.
00545         aMathMLChar->SetBoundingMetrics(charSize);
00546       }
00547     }
00548 
00549     if (aDesiredSize.ascent < charSize.ascent + leading) 
00550       aDesiredSize.ascent = charSize.ascent + leading;
00551     if (aDesiredSize.descent < charSize.descent + leading) 
00552       aDesiredSize.descent = charSize.descent + leading;
00553 
00554     // account the spacing
00555     charSize.width += NSToCoordRound((leftSpace + rightSpace) * em);
00556 
00557     // x-origin is used to store lspace ...
00558     // y-origin is used to stored the ascent ... 
00559     aMathMLChar->SetRect(nsRect(NSToCoordRound(leftSpace * em), 
00560                                 charSize.ascent, charSize.width,
00561                                 charSize.ascent + charSize.descent));
00562   }
00563   return NS_OK;
00564 }
00565 
00566 /*static*/ void
00567 nsMathMLmfencedFrame::PlaceChar(nsMathMLChar*      aMathMLChar,
00568                                 nscoord            aDesiredAscent,
00569                                 nsBoundingMetrics& bm,
00570                                 nscoord&           dx)
00571 {
00572   aMathMLChar->GetBoundingMetrics(bm);
00573 
00574   // the char's x-origin was used to store lspace ...
00575   // the char's y-origin was used to store the ascent ... 
00576   nsRect rect;
00577   aMathMLChar->GetRect(rect);
00578 
00579   nscoord dy = aDesiredAscent - rect.y;
00580   if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) {
00581     // the stretchy char will be centered around the axis
00582     // so we adjust the returned bounding metrics accordingly
00583     bm.descent = (bm.ascent + bm.descent) - rect.y;
00584     bm.ascent = rect.y;
00585   }
00586 
00587   aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height));
00588 
00589   bm.leftBearing += rect.x;
00590   bm.rightBearing += rect.x;
00591 
00592   // return rect.width since it includes lspace and rspace
00593   bm.width = rect.width;
00594   dx += rect.width;
00595 }
00596 
00597 nscoord
00598 nsMathMLmfencedFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
00599 {
00600   nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
00601   if (!gap) return 0;
00602 
00603   nsRect rect;
00604   if (mOpenChar) {
00605     mOpenChar->GetRect(rect);
00606     rect.MoveBy(gap, 0);
00607     mOpenChar->SetRect(rect);
00608   }
00609   if (mCloseChar) {
00610     mCloseChar->GetRect(rect);
00611     rect.MoveBy(gap, 0);
00612     mCloseChar->SetRect(rect);
00613   }
00614   for (PRInt32 i = 0; i < mSeparatorsCount; i++) {
00615     mSeparatorsChar[i].GetRect(rect);
00616     rect.MoveBy(gap, 0);
00617     mSeparatorsChar[i].SetRect(rect);
00618   }
00619   return gap;
00620 }
00621 
00622 // ----------------------
00623 // the Style System will use these to pass the proper style context to our MathMLChar
00624 nsStyleContext*
00625 nsMathMLmfencedFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
00626 {
00627   PRInt32 openIndex = -1;
00628   PRInt32 closeIndex = -1;
00629   PRInt32 lastIndex = mSeparatorsCount-1;
00630 
00631   if (mOpenChar) { 
00632     lastIndex++; 
00633     openIndex = lastIndex; 
00634   }
00635   if (mCloseChar) { 
00636     lastIndex++;
00637     closeIndex = lastIndex;
00638   }
00639   if (aIndex < 0 || aIndex > lastIndex) {
00640     return nsnull;
00641   }
00642 
00643   if (aIndex < mSeparatorsCount) {
00644     return mSeparatorsChar[aIndex].GetStyleContext();
00645   }
00646   else if (aIndex == openIndex) {
00647     return mOpenChar->GetStyleContext();
00648   }
00649   else if (aIndex == closeIndex) {
00650     return mCloseChar->GetStyleContext();
00651   }
00652   return nsnull;
00653 }
00654 
00655 void
00656 nsMathMLmfencedFrame::SetAdditionalStyleContext(PRInt32          aIndex, 
00657                                                 nsStyleContext*  aStyleContext)
00658 {
00659   PRInt32 openIndex = -1;
00660   PRInt32 closeIndex = -1;
00661   PRInt32 lastIndex = mSeparatorsCount-1;
00662 
00663   if (mOpenChar) {
00664     lastIndex++;
00665     openIndex = lastIndex;
00666   }
00667   if (mCloseChar) {
00668     lastIndex++;
00669     closeIndex = lastIndex;
00670   }
00671   if (aIndex < 0 || aIndex > lastIndex) {
00672     return;
00673   }
00674 
00675   if (aIndex < mSeparatorsCount) {
00676     mSeparatorsChar[aIndex].SetStyleContext(aStyleContext);
00677   }
00678   else if (aIndex == openIndex) {
00679     mOpenChar->SetStyleContext(aStyleContext);
00680   }
00681   else if (aIndex == closeIndex) {
00682     mCloseChar->SetStyleContext(aStyleContext);
00683   }
00684 }