Back to index

lightning-sunbird  0.9+nobinonly
nsMathMLmoFrame.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  *   Shyjan Mahamud <mahamud@cs.cmu.edu>
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
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 "nsIDOMText.h"
00051 
00052 #include "nsMathMLmoFrame.h"
00053 
00054 //
00055 // <mo> -- operator, fence, or separator - implementation
00056 //
00057 
00058 // additional style context to be used by our MathMLChar.
00059 #define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX   0
00060 
00061 nsresult
00062 NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00063 {
00064   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00065   if (nsnull == aNewFrame) {
00066     return NS_ERROR_NULL_POINTER;
00067   }
00068   nsMathMLmoFrame* it = new (aPresShell) nsMathMLmoFrame;
00069   if (nsnull == it) {
00070     return NS_ERROR_OUT_OF_MEMORY;
00071   }
00072   *aNewFrame = it;
00073   return NS_OK;
00074 }
00075 
00076 nsMathMLmoFrame::nsMathMLmoFrame()
00077 {
00078 }
00079 
00080 nsMathMLmoFrame::~nsMathMLmoFrame()
00081 {
00082 }
00083 
00084 static const PRUnichar kInvisibleComma = PRUnichar(0x200B); // a.k.a. ZERO WIDTH SPACE
00085 static const PRUnichar kApplyFunction  = PRUnichar(0x2061);
00086 static const PRUnichar kInvisibleTimes = PRUnichar(0x2062);
00087 static const PRUnichar kNullCh         = PRUnichar('\0');
00088 
00089 eMathMLFrameType
00090 nsMathMLmoFrame::GetMathMLFrameType()
00091 {
00092   return NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)
00093     ? eMathMLFrameType_OperatorInvisible
00094     : eMathMLFrameType_OperatorOrdinary;
00095 }
00096 
00097 // since a mouse click implies selection, we cannot just rely on the
00098 // frame's state bit in our child text frame. So we will first check
00099 // its selected state bit, and use this little helper to double check.
00100 PRBool
00101 nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame)
00102 {
00103   NS_ASSERTION(aFrame, "null arg");
00104   if (!aFrame)
00105     return PR_FALSE;
00106 
00107   PRBool isSelected = PR_FALSE;
00108   aFrame->GetSelected(&isSelected);
00109   if (!isSelected)
00110     return PR_FALSE;
00111 
00112   SelectionDetails* details = nsnull;
00113   nsIPresShell *shell = GetPresContext()->GetPresShell();
00114   if (shell) {
00115     nsCOMPtr<nsIFrameSelection> frameSelection;
00116     nsCOMPtr<nsISelectionController> selCon;
00117     nsresult rv = GetSelectionController(GetPresContext(),
00118                                          getter_AddRefs(selCon));
00119     if (NS_SUCCEEDED(rv) && selCon)
00120       frameSelection = do_QueryInterface(selCon);
00121     if (!frameSelection)
00122       frameSelection = shell->FrameSelection();
00123 
00124     frameSelection->LookUpSelection(aFrame->GetContent(),
00125                                 0, 1, &details, PR_TRUE);
00126   }
00127   if (!details)
00128     return PR_FALSE;
00129 
00130   while (details) {
00131     SelectionDetails* next = details->mNext;
00132     delete details;
00133     details = next;
00134   }
00135   return PR_TRUE;
00136 }
00137 
00138 NS_IMETHODIMP
00139 nsMathMLmoFrame::Paint(nsPresContext*      aPresContext,
00140                        nsIRenderingContext& aRenderingContext,
00141                        const nsRect&        aDirtyRect,
00142                        nsFramePaintLayer    aWhichLayer,
00143                        PRUint32             aFlags)
00144 {
00145   nsresult rv = NS_OK;
00146   PRBool useMathMLChar =
00147     (NS_MATHML_OPERATOR_GET_FORM(mFlags) &&
00148      NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) ||
00149     NS_MATHML_OPERATOR_IS_CENTERED(mFlags) ||
00150     NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags);
00151 
00152   if (!useMathMLChar || NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00153     // let the base class paint the background, border, outline
00154     rv = nsMathMLTokenFrame::Paint(aPresContext, aRenderingContext,
00155                                    aDirtyRect, aWhichLayer);
00156   }
00157   if (useMathMLChar) {
00158     // make our char selected if our inner child text frame is selected
00159     PRBool isSelected = PR_FALSE;
00160     nsRect selectedRect;
00161     nsIFrame* firstChild = mFrames.FirstChild();
00162     if (IsFrameInSelection(firstChild)) {
00163       selectedRect = firstChild->GetRect();
00164       isSelected = PR_TRUE;
00165     }
00166     rv = mMathMLChar.Paint(aPresContext, aRenderingContext, aDirtyRect,
00167                            aWhichLayer, this, isSelected ? &selectedRect : nsnull);
00168 #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
00169     // for visual debug
00170     if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer &&
00171         NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags)) {
00172       aRenderingContext.SetColor(NS_RGB(0,255,255));
00173       nscoord x = mReference.x + mBoundingMetrics.leftBearing;
00174       nscoord y = mReference.y - mBoundingMetrics.ascent;
00175       nscoord w = mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
00176       nscoord h = mBoundingMetrics.ascent + mBoundingMetrics.descent;
00177       aRenderingContext.DrawRect(x,y,w,h);
00178     }
00179 #endif
00180   }
00181   return rv;
00182 }
00183 
00184 // get the text that we enclose and setup our nsMathMLChar
00185 void
00186 nsMathMLmoFrame::ProcessTextData(nsPresContext* aPresContext)
00187 {
00188   mFlags = 0;
00189 
00190   // kids can be comment-nodes, attribute-nodes, text-nodes...
00191   // we use the DOM to ensure that we only look at text-nodes...
00192   nsAutoString data;
00193   PRUint32 numKids = mContent->GetChildCount();
00194   for (PRUint32 kid = 0; kid < numKids; ++kid) {
00195     nsCOMPtr<nsIDOMText> kidText(do_QueryInterface(mContent->GetChildAt(kid)));
00196     if (kidText) {
00197       nsAutoString kidData;
00198       kidText->GetData(kidData);
00199       data += kidData;
00200     }
00201   }
00202   PRInt32 length = data.Length();
00203   PRUnichar ch = (length == 0) ? kNullCh : data[0];
00204 
00205   if ((length == 1) && 
00206       (ch == kInvisibleComma || 
00207        ch == kApplyFunction  || 
00208        ch == kInvisibleTimes)) {
00209     mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
00210   }
00211 
00212   // don't bother doing anything special if we don't have a
00213   // single child with a visible text content
00214   if (NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags) || mFrames.GetLength() != 1) {
00215     data.Truncate(); // empty data to reset the char
00216     mMathMLChar.SetData(aPresContext, data);
00217     ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mMathMLChar, PR_FALSE);
00218     return;
00219   }
00220 
00221   // special... in math mode, the usual minus sign '-' looks too short, so
00222   // what we do here is to remap <mo>-</mo> to the official Unicode minus
00223   // sign (U+2212) which looks much better. For background on this, see
00224   // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1
00225   if (1 == length && ch == '-') {
00226     data = PRUnichar(0x2212);
00227     mFlags |= NS_MATHML_OPERATOR_CENTERED;
00228   }
00229 
00230   // cache the special bits: mutable, accent, movablelimits, centered.
00231   // we need to do this in anticipation of other requirements, and these
00232   // bits don't change. Do not reset these bits unless the text gets changed.
00233 
00234   // lookup all the forms under which the operator is listed in the dictionary,
00235   // and record whether the operator has accent="true" or movablelimits="true"
00236   nsOperatorFlags flags[4];
00237   float lspace[4], rspace[4];
00238   nsMathMLOperators::LookupOperators(data, flags, lspace, rspace);
00239   nsOperatorFlags allFlags =
00240     flags[NS_MATHML_OPERATOR_FORM_INFIX] |
00241     flags[NS_MATHML_OPERATOR_FORM_POSTFIX] |
00242     flags[NS_MATHML_OPERATOR_FORM_PREFIX];
00243 
00244   mFlags |= allFlags & NS_MATHML_OPERATOR_ACCENT;
00245   mFlags |= allFlags & NS_MATHML_OPERATOR_MOVABLELIMITS;
00246 
00247   PRBool isMutable =
00248     NS_MATHML_OPERATOR_IS_STRETCHY(allFlags) ||
00249     NS_MATHML_OPERATOR_IS_LARGEOP(allFlags);
00250   if (isMutable)
00251     mFlags |= NS_MATHML_OPERATOR_MUTABLE;
00252 
00253   // see if this is an operator that should be centered to cater for 
00254   // fonts that are not math-aware
00255   if (1 == length) {
00256     if ((ch == '+') || (ch == '=') || (ch == '*') ||
00257         (ch == 0x2264) || // &le;
00258         (ch == 0x2265) || // &ge;
00259         (ch == 0x00D7)) { // &times;
00260       mFlags |= NS_MATHML_OPERATOR_CENTERED;
00261     }
00262   }
00263 
00264   // cache the operator
00265   mMathMLChar.SetData(aPresContext, data);
00266   ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mMathMLChar, isMutable);
00267 
00268   // cache the native direction -- beware of bug 133429...
00269   // mEmbellishData.direction must always retain our native direction, whereas
00270   // mMathMLChar.GetStretchDirection() may change later, when Stretch() is called
00271   mEmbellishData.direction = mMathMLChar.GetStretchDirection();
00272 }
00273 
00274 // get our 'form' and lookup in the Operator Dictionary to fetch 
00275 // our default data that may come from there. Then complete our setup
00276 // using attributes that we may have. To stay in sync, this function is
00277 // called very often. We depend on many things that may change around us.
00278 // However, we re-use unchanged values.
00279 void
00280 nsMathMLmoFrame::ProcessOperatorData()
00281 {
00282   // if we have been here before, we will just use our cached form
00283   nsOperatorFlags form = NS_MATHML_OPERATOR_GET_FORM(mFlags);
00284   nsAutoString value;
00285 
00286   // special bits are always kept in mFlags.
00287   // remember the mutable bit from ProcessTextData().
00288   // Some chars are listed under different forms in the dictionary,
00289   // and there could be a form under which the char is mutable.
00290   // If the char is the core of an embellished container, we will keep
00291   // it mutable irrespective of the form of the embellished container.
00292   // Also remember the other special bits that we want to carry forward.
00293   mFlags &= NS_MATHML_OPERATOR_MUTABLE |
00294             NS_MATHML_OPERATOR_ACCENT | 
00295             NS_MATHML_OPERATOR_MOVABLELIMITS |
00296             NS_MATHML_OPERATOR_CENTERED |
00297             NS_MATHML_OPERATOR_INVISIBLE;
00298 
00299   if (!mEmbellishData.coreFrame) {
00300     // i.e., we haven't been here before, the default form is infix
00301     form = NS_MATHML_OPERATOR_FORM_INFIX;
00302 
00303     // reset everything so that we don't keep outdated values around
00304     // in case of dynamic changes
00305     mEmbellishData.flags = 0;
00306     mEmbellishData.coreFrame = nsnull;
00307     mEmbellishData.leftSpace = 0;
00308     mEmbellishData.rightSpace = 0;
00309     if (mMathMLChar.Length() != 1)
00310       mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;  
00311     // else... retain the native direction obtained in ProcessTextData()
00312 
00313     if (!mFrames.FirstChild()) {
00314       return;
00315     }
00316 
00317     mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR;
00318     mEmbellishData.coreFrame = this;
00319 
00320     // there are two particular things that we also need to record so that if our
00321     // parent is <mover>, <munder>, or <munderover>, they will treat us properly:
00322     // 1) do we have accent="true"
00323     // 2) do we have movablelimits="true"
00324 
00325     // they need the extra information to decide how to treat their scripts/limits
00326     // (note: <mover>, <munder>, or <munderover> need not necessarily be our
00327     // direct parent -- case of embellished operators)
00328 
00329     // default values from the Operator Dictionary were obtained in ProcessTextData()
00330     // and these special bits are always kept in mFlags
00331     if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags))
00332       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
00333     if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags))
00334       mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
00335 
00336     // see if the accent attribute is there
00337     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00338                      nsMathMLAtoms::accent_, value)) {
00339       if (value.EqualsLiteral("true"))
00340         mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
00341       else if (value.EqualsLiteral("false"))
00342         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT;
00343     }
00344     // see if the movablelimits attribute is there
00345     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00346                      nsMathMLAtoms::movablelimits_, value)) {
00347       if (value.EqualsLiteral("true"))
00348         mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
00349       else if (value.EqualsLiteral("false"))
00350         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS;
00351     }
00352 
00353      // ---------------------------------------------------------------------
00354      // we will be called again to re-sync the rest of our state next time...
00355      // (nobody needs the other values below at this stage)
00356      mFlags |= form;
00357      return;
00358   }
00359 
00360   nsPresContext* presContext = GetPresContext();
00361 
00362   // beware of bug 133814 - there is a two-way dependency in the
00363   // embellished hierarchy: our embellished ancestors need to set
00364   // their flags based on some of our state (set above), and here we
00365   // need to re-sync our 'form' depending on our outermost embellished
00366   // container. A null form here means that an earlier attempt to stretch
00367   // our mMathMLChar failed, in which case we don't bother re-stretching again
00368   if (form) {
00369     // get our outermost embellished container and its parent. 
00370     // (we ensure that we are the core, not just a sibling of the core)
00371     nsIFrame* embellishAncestor = this;
00372     nsEmbellishData embellishData;
00373     nsIFrame* parentAncestor = this;
00374     do {
00375       embellishAncestor = parentAncestor;
00376       parentAncestor = embellishAncestor->GetParent();
00377       GetEmbellishDataFrom(parentAncestor, embellishData);
00378     } while (embellishData.coreFrame == this);
00379 
00380     // flag if we have an embellished ancestor
00381     if (embellishAncestor != this)
00382       mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
00383     else
00384       mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
00385 
00386     // find the position of our outermost embellished container w.r.t
00387     // its siblings (frames are singly-linked together).
00388     nsFrameList frameList(parentAncestor->GetFirstChild(nsnull));
00389 
00390     nsIFrame* nextSibling = embellishAncestor->GetNextSibling();
00391     nsIFrame* prevSibling = frameList.GetPrevSiblingFor(embellishAncestor);
00392 
00393     // flag to distinguish from a real infix
00394     if (!prevSibling && !nextSibling)
00395       mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
00396     else
00397       mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
00398 
00399     // find our form
00400     form = NS_MATHML_OPERATOR_FORM_INFIX;
00401     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00402                      nsMathMLAtoms::form_, value)) {
00403       if (value.EqualsLiteral("prefix"))
00404         form = NS_MATHML_OPERATOR_FORM_PREFIX;
00405       else if (value.EqualsLiteral("postfix"))
00406         form = NS_MATHML_OPERATOR_FORM_POSTFIX;
00407     }
00408     else {
00409       // set our form flag depending on the position
00410       if (!prevSibling && nextSibling)
00411         form = NS_MATHML_OPERATOR_FORM_PREFIX;
00412       else if (prevSibling && !nextSibling)
00413         form = NS_MATHML_OPERATOR_FORM_POSTFIX;
00414     }
00415     mFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the old form bits
00416     mFlags |= form;
00417 
00418     // lookup the operator dictionary
00419     float lspace = 0.0f;
00420     float rspace = 0.0f;
00421     nsAutoString data;
00422     mMathMLChar.GetData(data);
00423     PRBool found = nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace);
00424     if (found && (lspace || rspace)) {
00425       // cache the default values of lspace & rspace that we get from the dictionary.
00426       // since these values are relative to the 'em' unit, convert to twips now
00427       nscoord em;
00428       nsCOMPtr<nsIFontMetrics> fm =
00429        presContext->GetMetricsFor(GetStyleFont()->mFont);
00430       GetEmHeight(fm, em);
00431 
00432       mEmbellishData.leftSpace = NSToCoordRound(lspace * em);
00433       mEmbellishData.rightSpace = NSToCoordRound(rspace * em);
00434 
00435       // tuning if we don't want too much extra space when we are a script.
00436       // (with its fonts, TeX sets lspace=0 & rspace=0 as soon as scriptlevel>0.
00437       // Our fonts can be anything, so...)
00438       if (mPresentationData.scriptLevel > 0) {
00439         if (NS_MATHML_OPERATOR_EMBELLISH_IS_ISOLATED(mFlags)) {
00440           // could be an isolated accent or script, e.g., x^{+}, just zero out
00441           mEmbellishData.leftSpace = 0;
00442           mEmbellishData.rightSpace  = 0;
00443         }
00444         else if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
00445           mEmbellishData.leftSpace /= 2;
00446           mEmbellishData.rightSpace  /= 2;
00447         }
00448       }
00449     }
00450   }
00451 
00452   // If we are an accent without explicit lspace="." or rspace=".",
00453   // we will ignore our default left/right space
00454 
00455   // lspace = number h-unit | namedspace
00456   nscoord leftSpace = mEmbellishData.leftSpace;
00457   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00458                    nsMathMLAtoms::lspace_, value)) {
00459     nsCSSValue cssValue;
00460     if (ParseNumericValue(value, cssValue) ||
00461         ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
00462     {
00463       if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
00464         leftSpace = 0;
00465       else if (cssValue.IsLengthUnit())
00466         leftSpace = CalcLength(presContext, mStyleContext, cssValue);
00467       mFlags |= NS_MATHML_OPERATOR_LEFTSPACE_ATTR;
00468     }
00469   }
00470 
00471   // rspace = number h-unit | namedspace
00472   nscoord rightSpace = mEmbellishData.rightSpace;
00473   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00474                    nsMathMLAtoms::rspace_, value)) {
00475     nsCSSValue cssValue;
00476     if (ParseNumericValue(value, cssValue) ||
00477         ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
00478     {
00479       if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
00480         rightSpace = 0;
00481       else if (cssValue.IsLengthUnit())
00482         rightSpace = CalcLength(presContext, mStyleContext, cssValue);
00483       mFlags |= NS_MATHML_OPERATOR_RIGHTSPACE_ATTR;
00484     }
00485   }
00486 
00487   // little extra tuning to round lspace & rspace to at least a pixel so that
00488   // operators don't look as if they are colliding with their operands
00489   if (leftSpace || rightSpace) {
00490     nscoord onePixel = presContext->IntScaledPixelsToTwips(1);
00491     if (leftSpace && leftSpace < onePixel)
00492       leftSpace = onePixel;
00493     if (rightSpace && rightSpace < onePixel)
00494       rightSpace = onePixel;
00495   }
00496 
00497   // the values that we get from our attributes override the dictionary
00498   mEmbellishData.leftSpace = leftSpace;
00499   mEmbellishData.rightSpace = rightSpace;
00500 
00501   // Now see if there are user-defined attributes that override the dictionary.
00502   // XXX If an attribute can be forced to be true when it is false in the
00503   // dictionary, then the following code has to change...
00504 
00505   // For each attribute overriden by the user, turn off its bit flag.
00506   // symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form
00507   // special: accent and movablelimits are handled in ProcessEmbellishData()
00508   // don't process them here
00509 
00510   nsAutoString kfalse, ktrue;
00511   kfalse.AssignLiteral("false");
00512   ktrue.AssignLiteral("true");
00513 
00514   if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
00515     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00516                      nsMathMLAtoms::stretchy_, value) && value == kfalse)
00517       mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
00518   }
00519   if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
00520     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00521                      nsMathMLAtoms::fence_, value) && value == kfalse)
00522       mFlags &= ~NS_MATHML_OPERATOR_FENCE;
00523   }
00524   if (NS_MATHML_OPERATOR_IS_LARGEOP(mFlags)) {
00525     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00526                      nsMathMLAtoms::largeop_, value) && value == kfalse)
00527       mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
00528   }
00529   if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
00530     if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00531                      nsMathMLAtoms::separator_, value) && value == kfalse)
00532       mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
00533   }
00534   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00535                    nsMathMLAtoms::symmetric_, value)) {
00536    if (value == kfalse)
00537      mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
00538    else if (value == ktrue)
00539      mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
00540   }
00541 
00542   // minsize = number [ v-unit | h-unit ] | namedspace
00543   mMinSize = float(NS_UNCONSTRAINEDSIZE);
00544   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00545                    nsMathMLAtoms::minsize_, value)) {
00546     nsCSSValue cssValue;
00547     if (ParseNumericValue(value, cssValue) ||
00548         ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
00549     {
00550       nsCSSUnit unit = cssValue.GetUnit();
00551       if (eCSSUnit_Number == unit)
00552         mMinSize = cssValue.GetFloatValue();
00553       else if (eCSSUnit_Percent == unit)
00554         mMinSize = cssValue.GetPercentValue();
00555       else if (eCSSUnit_Null != unit) {
00556         mMinSize = float(CalcLength(presContext, mStyleContext, cssValue));
00557         mFlags |= NS_MATHML_OPERATOR_MINSIZE_EXPLICIT;
00558       }
00559 
00560       if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
00561         // see if the multiplicative inheritance should be from <mstyle>
00562         if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(nsnull, mPresentationData.mstyle,
00563                          nsMathMLAtoms::minsize_, value)) {
00564           if (ParseNumericValue(value, cssValue)) {
00565             if (cssValue.IsLengthUnit()) {
00566               mMinSize *= float(CalcLength(presContext, mStyleContext, cssValue));
00567               mFlags |= NS_MATHML_OPERATOR_MINSIZE_EXPLICIT;
00568             }
00569           }
00570         }
00571       }
00572     }
00573   }
00574 
00575   // maxsize = number [ v-unit | h-unit ] | namedspace | infinity
00576   mMaxSize = float(NS_UNCONSTRAINEDSIZE);
00577   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00578                    nsMathMLAtoms::maxsize_, value)) {
00579     nsCSSValue cssValue;
00580     if (ParseNumericValue(value, cssValue) ||
00581         ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
00582     {
00583       nsCSSUnit unit = cssValue.GetUnit();
00584       if (eCSSUnit_Number == unit)
00585         mMaxSize = cssValue.GetFloatValue();
00586       else if (eCSSUnit_Percent == unit)
00587         mMaxSize = cssValue.GetPercentValue();
00588       else if (eCSSUnit_Null != unit) {
00589         mMaxSize = float(CalcLength(presContext, mStyleContext, cssValue));
00590         mFlags |= NS_MATHML_OPERATOR_MAXSIZE_EXPLICIT;
00591       }
00592 
00593       if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
00594         // see if the multiplicative inheritance should be from <mstyle>
00595         if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(nsnull, mPresentationData.mstyle,
00596                          nsMathMLAtoms::maxsize_, value)) {
00597           if (ParseNumericValue(value, cssValue)) {
00598             if (cssValue.IsLengthUnit()) {
00599               mMaxSize *= float(CalcLength(presContext, mStyleContext, cssValue));
00600               mFlags |= NS_MATHML_OPERATOR_MAXSIZE_EXPLICIT;
00601             }
00602           }
00603         }
00604       }
00605     }
00606   }
00607 }
00608 
00609 // NOTE: aDesiredStretchSize is an IN/OUT parameter
00610 //       On input  - it contains our current size
00611 //       On output - the same size or the new size that we want
00612 NS_IMETHODIMP
00613 nsMathMLmoFrame::Stretch(nsIRenderingContext& aRenderingContext,
00614                          nsStretchDirection   aStretchDirection,
00615                          nsBoundingMetrics&   aContainerSize,
00616                          nsHTMLReflowMetrics& aDesiredStretchSize)
00617 {
00618   if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
00619     NS_WARNING("it is wrong to fire stretch more than once on a frame");
00620     return NS_OK;
00621   }
00622   mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
00623 
00624   nsIFrame* firstChild = mFrames.FirstChild();
00625 
00626   // get the axis height;
00627   nsCOMPtr<nsIFontMetrics> fm;
00628   aRenderingContext.SetFont(GetStyleFont()->mFont, nsnull);
00629   aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
00630   nscoord axisHeight, height;
00631   GetAxisHeight(aRenderingContext, fm, axisHeight);
00632 
00633   // get the leading to be left at the top and the bottom of the stretched char
00634   // this seems more reliable than using fm->GetLeading() on suspicious fonts               
00635   nscoord em;
00636   GetEmHeight(fm, em);
00637   nscoord leading = NSToCoordRound(0.2f * em);
00638 
00639   // Operators that are stretchy, or those that are to be centered
00640   // to cater for fonts that are not math-aware, are handled by the MathMLChar
00641   // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time)
00642   PRBool useMathMLChar =
00643     (NS_MATHML_OPERATOR_GET_FORM(mFlags) &&
00644      NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) ||
00645     NS_MATHML_OPERATOR_IS_CENTERED(mFlags) ||
00646     NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags);
00647 
00648   nsBoundingMetrics charSize;
00649   if (useMathMLChar) {
00650     nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics;
00651     nsBoundingMetrics container = initialSize;
00652 
00653     PRBool isVertical = PR_FALSE;
00654     PRUint32 stretchHint = NS_STRETCH_NORMAL;
00655 
00656     // see if it is okay to stretch, starting from what the Operator Dictionary said
00657     PRBool isMutable = NS_MATHML_OPERATOR_IS_MUTABLE(mFlags);
00658     // if the stretchy and largeop attributes have been disabled,
00659     // the operator is not mutable
00660     if (!NS_MATHML_OPERATOR_IS_STRETCHY(mFlags) &&
00661         !NS_MATHML_OPERATOR_IS_LARGEOP(mFlags))
00662       isMutable = PR_FALSE;
00663 
00664     if (isMutable) {
00665 
00666       container = aContainerSize;
00667 
00668       if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) ||
00669            (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT))  &&
00670           (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL))
00671       {
00672         isVertical = PR_TRUE;
00673       }
00674 
00675       // set the largeop or largeopOnly flags to suitably cover all the
00676       // 8 possible cases depending on whether displaystyle, largeop,
00677       // stretchy are true or false (see bug 69325).
00678       // . largeopOnly is taken if largeop=true and stretchy=false
00679       // . largeop is taken if largeop=true and stretchy=true
00680       if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags) &&
00681           NS_MATHML_OPERATOR_IS_LARGEOP(mFlags)) {
00682         stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!)
00683         if (NS_MATHML_OPERATOR_IS_STRETCHY(mFlags)) {
00684           stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER;
00685         }
00686       }
00687       else if (isVertical) {
00688         // TeX hint. Can impact some sloppy markups missing <mrow></mrow>
00689         stretchHint = NS_STRETCH_NEARER;
00690       }
00691 
00692       // some adjustments if the operator is symmetric and vertical
00693 
00694       if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
00695         // we need to center about the axis
00696         nscoord delta = PR_MAX(container.ascent - axisHeight,
00697                                container.descent + axisHeight);
00698         container.ascent = delta + axisHeight;
00699         container.descent = delta - axisHeight;
00700 
00701         // get ready in case we encounter user-desired min-max size
00702         delta = PR_MAX(initialSize.ascent - axisHeight,
00703                        initialSize.descent + axisHeight);
00704         initialSize.ascent = delta + axisHeight;
00705         initialSize.descent = delta - axisHeight;
00706       }
00707 
00708       // check for user-desired min-max size
00709 
00710       if (mMaxSize != float(NS_UNCONSTRAINEDSIZE) && mMaxSize > 0.0f) {
00711         // if we are here, there is a user defined maxsize ...
00712         if (NS_MATHML_OPERATOR_MAXSIZE_IS_EXPLICIT(mFlags)) {
00713           // there is an explicit value like maxsize="20pt"
00714           // try to maintain the aspect ratio of the char
00715           float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent);
00716           container.ascent =
00717             PR_MIN(container.ascent, nscoord(initialSize.ascent * aspect));
00718           container.descent =
00719             PR_MIN(container.descent, nscoord(initialSize.descent * aspect));
00720           // below we use a type cast instead of a conversion to avoid a VC++ bug
00721           // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP
00722           container.width =
00723             PR_MIN(container.width, (nscoord)mMaxSize);
00724         }
00725         else { // multiplicative value
00726           container.ascent =
00727             PR_MIN(container.ascent, nscoord(initialSize.ascent * mMaxSize));
00728           container.descent =
00729             PR_MIN(container.descent, nscoord(initialSize.descent * mMaxSize));
00730           container.width =
00731             PR_MIN(container.width, nscoord(initialSize.width * mMaxSize));
00732         }
00733 
00734         if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
00735           // re-adjust to align the char with the bottom of the initial container
00736           height = container.ascent + container.descent;
00737           container.descent = aContainerSize.descent;
00738           container.ascent = height - container.descent;
00739         }
00740       }
00741 
00742       if (mMinSize != float(NS_UNCONSTRAINEDSIZE) && mMinSize > 0.0f) {
00743         // if we are here, there is a user defined minsize ...
00744         if (NS_MATHML_OPERATOR_MINSIZE_IS_EXPLICIT(mFlags)) {
00745           // there is an explicit value like minsize="20pt"
00746           // try to maintain the aspect ratio of the char
00747           float aspect = mMinSize / float(initialSize.ascent + initialSize.descent);
00748           container.ascent =
00749             PR_MAX(container.ascent, nscoord(initialSize.ascent * aspect));
00750           container.descent =
00751             PR_MAX(container.descent, nscoord(initialSize.descent * aspect));
00752           container.width =
00753             PR_MAX(container.width, (nscoord)mMinSize);
00754         }
00755         else { // multiplicative value
00756           container.ascent =
00757             PR_MAX(container.ascent, nscoord(initialSize.ascent * mMinSize));
00758           container.descent =
00759             PR_MAX(container.descent, nscoord(initialSize.descent * mMinSize));
00760           container.width =
00761             PR_MAX(container.width, nscoord(initialSize.width * mMinSize));
00762         }
00763 
00764         if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
00765           // re-adjust to align the char with the bottom of the initial container
00766           height = container.ascent + container.descent;
00767           container.descent = aContainerSize.descent;
00768           container.ascent = height - container.descent;
00769         }
00770       }
00771     }
00772 
00773     // let the MathMLChar stretch itself...
00774     nsresult res = mMathMLChar.Stretch(GetPresContext(), aRenderingContext,
00775                                        aStretchDirection, container, charSize, stretchHint);
00776     if (NS_FAILED(res)) {
00777       // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed)
00778       // clear our 'form' to behave as if the operator wasn't in the dictionary
00779       mFlags &= ~NS_MATHML_OPERATOR_FORM;
00780       useMathMLChar = PR_FALSE;
00781     }
00782     else {
00783       // update our bounding metrics... it becomes that of our MathML char
00784       mBoundingMetrics = charSize;
00785 
00786       // if the returned direction is 'unsupported', the char didn't actually change. 
00787       // So we do the centering only if necessary
00788       if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED ||
00789           NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
00790 
00791         if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
00792           // the desired size returned by mMathMLChar maybe different
00793           // from the size of the container.
00794           // the mMathMLChar.mRect.y calculation is subtle, watch out!!!
00795 
00796           height = mBoundingMetrics.ascent + mBoundingMetrics.descent;
00797           if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) ||
00798               NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
00799             // For symmetric and vertical operators, or for operators that are always
00800             // centered ('+', '*', etc) we want to center about the axis of the container
00801             mBoundingMetrics.descent = height/2 - axisHeight;
00802           }
00803           else {
00804             // Otherwise, align the char with the bottom of the container
00805             mBoundingMetrics.descent = container.descent;
00806           }
00807           mBoundingMetrics.ascent = height - mBoundingMetrics.descent;
00808         }
00809       }
00810     }
00811   }
00812 
00813   // Place our children using the default method
00814   // This will allow our child text frame to get its DidReflow()
00815   Place(aRenderingContext, PR_TRUE, aDesiredStretchSize);
00816 
00817   // Fixup for the final height.
00818   // On one hand, our stretchy height can sometimes be shorter than surrounding
00819   // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading|
00820   // that is smaller than the ASCII's ascent, hence when painting the background
00821   // later, it won't look uniform along the line.
00822   // On the other hand, sometimes we may leave too much gap when our glyph happens
00823   // to come from a font with tall glyphs. For example, since CMEX10 has very tall
00824   // glyphs, its natural font metrics are large, even if we pick a small glyph
00825   // whose size is comparable to the size of a normal ASCII glyph.
00826   // So to avoid uneven spacing in either of these two cases, we use the height
00827   // of the ASCII font as a reference and try to match it if possible.
00828 
00829   // special case for accents... keep them short to improve mouse operations...
00830   // an accent can only be the non-first child of <mover>, <munder>, <munderover>
00831   PRBool isAccent =
00832     NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags);
00833   if (isAccent) {
00834     nsEmbellishData parentData;
00835     GetEmbellishDataFrom(mParent, parentData);
00836     isAccent =
00837        (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) ||
00838         NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) &&
00839        parentData.coreFrame != this;
00840   }
00841   if (isAccent && firstChild) {
00842     // see bug 188467 for what is going on here
00843     nscoord dy = aDesiredStretchSize.ascent - (mBoundingMetrics.ascent + leading);
00844     aDesiredStretchSize.ascent = mBoundingMetrics.ascent + leading;
00845     aDesiredStretchSize.descent = mBoundingMetrics.descent;
00846 
00847     firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy));
00848   }
00849   else if (useMathMLChar) {
00850     nscoord ascent, descent;
00851     fm->GetMaxAscent(ascent);
00852     fm->GetMaxDescent(descent);
00853     aDesiredStretchSize.ascent = PR_MAX(mBoundingMetrics.ascent + leading, ascent);
00854     aDesiredStretchSize.descent = PR_MAX(mBoundingMetrics.descent + leading, descent);
00855   }
00856   aDesiredStretchSize.height = aDesiredStretchSize.ascent + aDesiredStretchSize.descent;
00857   aDesiredStretchSize.width = mBoundingMetrics.width;
00858   aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics;
00859   mReference.x = 0;
00860   mReference.y = aDesiredStretchSize.ascent;
00861   // Place our mMathMLChar, its origin is in our coordinate system
00862   if (useMathMLChar) {
00863     nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent;
00864     mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent));
00865   }
00866 
00867   // Before we leave... there is a last item in the check-list:
00868   // If our parent is not embellished, it means we are the outermost embellished
00869   // container and so we put the spacing, otherwise we don't include the spacing,
00870   // the outermost embellished container will take care of it.
00871 
00872   if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
00873 
00874     // Account the spacing if we are not an accent with explicit attributes
00875     nscoord leftSpace = mEmbellishData.leftSpace;
00876     if (isAccent && !NS_MATHML_OPERATOR_HAS_LEFTSPACE_ATTR(mFlags)) {
00877       leftSpace = 0;
00878     }
00879     nscoord rightSpace = mEmbellishData.rightSpace;
00880     if (isAccent && !NS_MATHML_OPERATOR_HAS_RIGHTSPACE_ATTR(mFlags)) {
00881       rightSpace = 0;
00882     }
00883 
00884     mBoundingMetrics.width += leftSpace + rightSpace;
00885     aDesiredStretchSize.width = mBoundingMetrics.width;
00886     aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
00887 
00888     if (leftSpace) {
00889       // adjust the offsets
00890       mBoundingMetrics.leftBearing += leftSpace;
00891       mBoundingMetrics.rightBearing += leftSpace;
00892       aDesiredStretchSize.mBoundingMetrics.leftBearing += leftSpace;
00893       aDesiredStretchSize.mBoundingMetrics.rightBearing += leftSpace;
00894 
00895       if (useMathMLChar) {
00896        nsRect rect;
00897         mMathMLChar.GetRect(rect);
00898         mMathMLChar.SetRect(nsRect(rect.x + leftSpace, rect.y, rect.width, rect.height));
00899       }
00900       else {
00901         nsIFrame* childFrame = firstChild;
00902         while (childFrame) {
00903           childFrame->SetPosition(childFrame->GetPosition()
00904                               + nsPoint(leftSpace, 0));
00905           childFrame = childFrame->GetNextSibling();
00906         }
00907       }
00908     }
00909   }
00910 
00911   if (mFrames.GetLength() != 1)
00912     return NS_OK;
00913 
00914   nsRect rect = firstChild->GetRect();
00915   if (useMathMLChar) {
00916     // even though our child text frame is not doing the rendering, we make it play
00917     // nice with other operations that the MathMLChar doesn't handle (e.g., caret)
00918     // use our whole height (i.e., with the leading that isn't part of the MathMLChar)
00919     mMathMLChar.GetRect(rect);
00920     rect.y = 0;
00921   }
00922   rect.height = aDesiredStretchSize.height;
00923   firstChild->SetRect(rect);
00924   return NS_OK;
00925 }
00926 
00927 NS_IMETHODIMP
00928 nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent)
00929 {
00930   // retain our native direction, it only changes if our text content changes
00931   nsStretchDirection direction = mEmbellishData.direction;
00932   nsMathMLTokenFrame::InheritAutomaticData(aParent);
00933   mEmbellishData.direction = direction;
00934   return NS_OK;
00935 }
00936 
00937 NS_IMETHODIMP
00938 nsMathMLmoFrame::TransmitAutomaticData()
00939 {
00940   // this will cause us to re-sync our flags from scratch
00941   // but our returned 'form' is still not final (bug 133429), it will
00942   // be recomputed to its final value during the next call in Reflow()
00943   mEmbellishData.coreFrame = nsnull;
00944   ProcessOperatorData();
00945   return NS_OK;
00946 }
00947 
00948 NS_IMETHODIMP
00949 nsMathMLmoFrame::Reflow(nsPresContext*          aPresContext,
00950                         nsHTMLReflowMetrics&     aDesiredSize,
00951                         const nsHTMLReflowState& aReflowState,
00952                         nsReflowStatus&          aStatus)
00953 {
00954   // certain values use units that depend on our style context, so
00955   // it is safer to just process the whole lot here
00956   ProcessOperatorData();
00957 
00958   // play safe by not passing invisible operators to the font subsystem because
00959   // some platforms risk selecting strange glyphs for them and give bad inter-space
00960   if (NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)) {
00961     // return empty space for now, but this is not yet final since there
00962     // can be lspace and rspace attributes that reclaim some room.
00963     // These will be dealt with later in Stretch().
00964     aDesiredSize.width = 0;
00965     aDesiredSize.height = 0;
00966     aDesiredSize.ascent = 0;
00967     aDesiredSize.descent = 0;
00968     if (aDesiredSize.mComputeMEW) {
00969       aDesiredSize.mMaxElementWidth = 0;
00970     }
00971     aDesiredSize.mBoundingMetrics.Clear();
00972     aStatus = NS_FRAME_COMPLETE;
00973 
00974     NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00975     return NS_OK;
00976   }
00977 
00978   return nsMathMLTokenFrame::Reflow(aPresContext, aDesiredSize,
00979                                     aReflowState, aStatus);
00980 }
00981 
00982 NS_IMETHODIMP
00983 nsMathMLmoFrame::ReflowDirtyChild(nsIPresShell* aPresShell,
00984                                   nsIFrame*     aChild)
00985 {
00986   // if we get this, it means it was called by the nsTextFrame beneath us, and 
00987   // this means something changed in the text content. So blow away everything
00988   // an re-build the automatic data from the parent of our outermost embellished
00989   // container (we ensure that we are the core, not just a sibling of the core)
00990 
00991   ProcessTextData(GetPresContext());
00992 
00993   nsIFrame* target = this;
00994   nsEmbellishData embellishData;
00995   do {
00996     target = target->GetParent();
00997     GetEmbellishDataFrom(target, embellishData);
00998   } while (embellishData.coreFrame == this);
00999 
01000   // we have automatic data to update in the children of the target frame
01001   return ReLayoutChildren(target);
01002 }
01003 
01004 NS_IMETHODIMP
01005 nsMathMLmoFrame::AttributeChanged(nsIContent*     aContent,
01006                                   PRInt32         aNameSpaceID,
01007                                   nsIAtom*        aAttribute,
01008                                   PRInt32         aModType)
01009 {
01010   // check if this is an attribute that can affect the embellished hierarchy
01011   // in a significant way and re-layout the entire hierarchy.
01012   if (nsMathMLAtoms::accent_ == aAttribute ||
01013       nsMathMLAtoms::movablelimits_ == aAttribute) {
01014 
01015     // set the target as the parent of our outermost embellished container
01016     // (we ensure that we are the core, not just a sibling of the core)
01017     nsIFrame* target = this;
01018     nsEmbellishData embellishData;
01019     do {
01020       target = target->GetParent();
01021       GetEmbellishDataFrom(target, embellishData);
01022     } while (embellishData.coreFrame == this);
01023 
01024     // we have automatic data to update in the children of the target frame
01025     return ReLayoutChildren(target);
01026   }
01027 
01028   return nsMathMLTokenFrame::
01029          AttributeChanged(aContent, aNameSpaceID,
01030                           aAttribute, aModType);
01031 }
01032 
01033 // ----------------------
01034 // No need to tract the style context given to our MathML char. 
01035 // the Style System will use these to pass the proper style context to our MathMLChar
01036 nsStyleContext*
01037 nsMathMLmoFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
01038 {
01039   switch (aIndex) {
01040   case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
01041     return mMathMLChar.GetStyleContext();
01042   default:
01043     return nsnull;
01044   }
01045 }
01046 
01047 void
01048 nsMathMLmoFrame::SetAdditionalStyleContext(PRInt32          aIndex,
01049                                            nsStyleContext*  aStyleContext)
01050 {
01051   switch (aIndex) {
01052   case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
01053     mMathMLChar.SetStyleContext(aStyleContext);
01054     break;
01055   }
01056 }