LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmoFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 507 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "gfxContext.h"
       7             : #include "nsMathMLmoFrame.h"
       8             : #include "nsPresContext.h"
       9             : #include "nsContentUtils.h"
      10             : #include "nsFrameSelection.h"
      11             : #include "nsMathMLElement.h"
      12             : #include <algorithm>
      13             : 
      14             : //
      15             : // <mo> -- operator, fence, or separator - implementation
      16             : //
      17             : 
      18             : // additional style context to be used by our MathMLChar.
      19             : #define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX   0
      20             : 
      21             : nsIFrame*
      22           0 : NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
      23             : {
      24           0 :   return new (aPresShell) nsMathMLmoFrame(aContext);
      25             : }
      26             : 
      27           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmoFrame)
      28             : 
      29           0 : nsMathMLmoFrame::~nsMathMLmoFrame()
      30             : {
      31           0 : }
      32             : 
      33             : static const char16_t kApplyFunction  = char16_t(0x2061);
      34             : static const char16_t kInvisibleTimes = char16_t(0x2062);
      35             : static const char16_t kInvisibleSeparator = char16_t(0x2063);
      36             : static const char16_t kInvisiblePlus = char16_t(0x2064);
      37             : 
      38             : eMathMLFrameType
      39           0 : nsMathMLmoFrame::GetMathMLFrameType()
      40             : {
      41           0 :   return NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)
      42           0 :     ? eMathMLFrameType_OperatorInvisible
      43           0 :     : eMathMLFrameType_OperatorOrdinary;
      44             : }
      45             : 
      46             : // since a mouse click implies selection, we cannot just rely on the
      47             : // frame's state bit in our child text frame. So we will first check
      48             : // its selected state bit, and use this little helper to double check.
      49             : bool
      50           0 : nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame)
      51             : {
      52           0 :   NS_ASSERTION(aFrame, "null arg");
      53           0 :   if (!aFrame || !aFrame->IsSelected())
      54           0 :     return false;
      55             : 
      56           0 :   const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection();
      57             :   UniquePtr<SelectionDetails> details =
      58           0 :     frameSelection->LookUpSelection(aFrame->GetContent(), 0, 1, true);
      59             : 
      60           0 :   return details != nullptr;
      61             : }
      62             : 
      63             : bool
      64           0 : nsMathMLmoFrame::UseMathMLChar()
      65             : {
      66           0 :   return (NS_MATHML_OPERATOR_GET_FORM(mFlags) &&
      67           0 :           NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) ||
      68           0 :     NS_MATHML_OPERATOR_IS_CENTERED(mFlags);
      69             : }
      70             : 
      71             : void
      72           0 : nsMathMLmoFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
      73             :                                   const nsRect&           aDirtyRect,
      74             :                                   const nsDisplayListSet& aLists)
      75             : {
      76           0 :   bool useMathMLChar = UseMathMLChar();
      77             : 
      78           0 :   if (!useMathMLChar) {
      79             :     // let the base class do everything
      80           0 :     nsMathMLTokenFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
      81             :   } else {
      82           0 :     DisplayBorderBackgroundOutline(aBuilder, aLists);
      83             : 
      84             :     // make our char selected if our inner child text frame is selected
      85           0 :     bool isSelected = false;
      86           0 :     nsRect selectedRect;
      87           0 :     nsIFrame* firstChild = mFrames.FirstChild();
      88           0 :     if (IsFrameInSelection(firstChild)) {
      89           0 :       mMathMLChar.GetRect(selectedRect);
      90             :       // add a one pixel border (it renders better for operators like minus)
      91           0 :       selectedRect.Inflate(nsPresContext::CSSPixelsToAppUnits(1));
      92           0 :       isSelected = true;
      93             :     }
      94           0 :     mMathMLChar.Display(aBuilder, this, aLists, 0, isSelected ? &selectedRect : nullptr);
      95             : 
      96             : #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
      97             :     // for visual debug
      98             :     DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
      99             : #endif
     100             :   }
     101           0 : }
     102             : 
     103             : // get the text that we enclose and setup our nsMathMLChar
     104             : void
     105           0 : nsMathMLmoFrame::ProcessTextData()
     106             : {
     107           0 :   mFlags = 0;
     108             : 
     109           0 :   nsAutoString data;
     110           0 :   nsContentUtils::GetNodeTextContent(mContent, false, data);
     111             : 
     112           0 :   data.CompressWhitespace();
     113           0 :   int32_t length = data.Length();
     114           0 :   char16_t ch = (length == 0) ? char16_t('\0') : data[0];
     115             : 
     116           0 :   if ((length == 1) &&
     117           0 :       (ch == kApplyFunction  ||
     118           0 :        ch == kInvisibleSeparator ||
     119           0 :        ch == kInvisiblePlus ||
     120             :        ch == kInvisibleTimes)) {
     121           0 :     mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
     122             :   }
     123             : 
     124             :   // don't bother doing anything special if we don't have a single child
     125           0 :   nsPresContext* presContext = PresContext();
     126           0 :   if (mFrames.GetLength() != 1) {
     127           0 :     data.Truncate(); // empty data to reset the char
     128           0 :     mMathMLChar.SetData(data);
     129           0 :     ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar);
     130           0 :     return;
     131             :   }
     132             : 
     133             :   // special... in math mode, the usual minus sign '-' looks too short, so
     134             :   // what we do here is to remap <mo>-</mo> to the official Unicode minus
     135             :   // sign (U+2212) which looks much better. For background on this, see
     136             :   // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1
     137           0 :   if (1 == length && ch == '-') {
     138           0 :     ch = 0x2212;
     139           0 :     data = ch;
     140             :   }
     141             : 
     142             :   // cache the special bits: mutable, accent, movablelimits, centered.
     143             :   // we need to do this in anticipation of other requirements, and these
     144             :   // bits don't change. Do not reset these bits unless the text gets changed.
     145             : 
     146             :   // lookup all the forms under which the operator is listed in the dictionary,
     147             :   // and record whether the operator has accent="true" or movablelimits="true"
     148             :   nsOperatorFlags flags[4];
     149             :   float lspace[4], rspace[4];
     150           0 :   nsMathMLOperators::LookupOperators(data, flags, lspace, rspace);
     151             :   nsOperatorFlags allFlags =
     152           0 :     flags[NS_MATHML_OPERATOR_FORM_INFIX] |
     153           0 :     flags[NS_MATHML_OPERATOR_FORM_POSTFIX] |
     154           0 :     flags[NS_MATHML_OPERATOR_FORM_PREFIX];
     155             : 
     156           0 :   mFlags |= allFlags & NS_MATHML_OPERATOR_ACCENT;
     157           0 :   mFlags |= allFlags & NS_MATHML_OPERATOR_MOVABLELIMITS;
     158             : 
     159             :   // see if this is an operator that should be centered to cater for
     160             :   // fonts that are not math-aware
     161           0 :   if (1 == length) {
     162           0 :     if ((ch == '+') || (ch == '=') || (ch == '*') ||
     163           0 :         (ch == 0x2212) || // &minus;
     164           0 :         (ch == 0x2264) || // &le;
     165           0 :         (ch == 0x2265) || // &ge;
     166             :         (ch == 0x00D7)) { // &times;
     167           0 :       mFlags |= NS_MATHML_OPERATOR_CENTERED;
     168             :     }
     169             :   }
     170             : 
     171             :   // cache the operator
     172           0 :   mMathMLChar.SetData(data);
     173             : 
     174             :   // cache the native direction -- beware of bug 133429...
     175             :   // mEmbellishData.direction must always retain our native direction, whereas
     176             :   // mMathMLChar.GetStretchDirection() may change later, when Stretch() is called
     177           0 :   mEmbellishData.direction = mMathMLChar.GetStretchDirection();
     178             : 
     179             :   bool isMutable =
     180           0 :     NS_MATHML_OPERATOR_IS_LARGEOP(allFlags) ||
     181           0 :     (mEmbellishData.direction != NS_STRETCH_DIRECTION_UNSUPPORTED);
     182           0 :   if (isMutable)
     183           0 :     mFlags |= NS_MATHML_OPERATOR_MUTABLE;
     184             : 
     185           0 :   ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar);
     186             : }
     187             : 
     188             : // get our 'form' and lookup in the Operator Dictionary to fetch
     189             : // our default data that may come from there. Then complete our setup
     190             : // using attributes that we may have. To stay in sync, this function is
     191             : // called very often. We depend on many things that may change around us.
     192             : // However, we re-use unchanged values.
     193             : void
     194           0 : nsMathMLmoFrame::ProcessOperatorData()
     195             : {
     196             :   // if we have been here before, we will just use our cached form
     197           0 :   nsOperatorFlags form = NS_MATHML_OPERATOR_GET_FORM(mFlags);
     198           0 :   nsAutoString value;
     199           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     200             : 
     201             :   // special bits are always kept in mFlags.
     202             :   // remember the mutable bit from ProcessTextData().
     203             :   // Some chars are listed under different forms in the dictionary,
     204             :   // and there could be a form under which the char is mutable.
     205             :   // If the char is the core of an embellished container, we will keep
     206             :   // it mutable irrespective of the form of the embellished container.
     207             :   // Also remember the other special bits that we want to carry forward.
     208           0 :   mFlags &= NS_MATHML_OPERATOR_MUTABLE |
     209             :             NS_MATHML_OPERATOR_ACCENT |
     210             :             NS_MATHML_OPERATOR_MOVABLELIMITS |
     211             :             NS_MATHML_OPERATOR_CENTERED |
     212           0 :             NS_MATHML_OPERATOR_INVISIBLE;
     213             : 
     214           0 :   if (!mEmbellishData.coreFrame) {
     215             :     // i.e., we haven't been here before, the default form is infix
     216           0 :     form = NS_MATHML_OPERATOR_FORM_INFIX;
     217             : 
     218             :     // reset everything so that we don't keep outdated values around
     219             :     // in case of dynamic changes
     220           0 :     mEmbellishData.flags = 0;
     221           0 :     mEmbellishData.coreFrame = nullptr;
     222           0 :     mEmbellishData.leadingSpace = 0;
     223           0 :     mEmbellishData.trailingSpace = 0;
     224           0 :     if (mMathMLChar.Length() != 1)
     225           0 :       mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
     226             :     // else... retain the native direction obtained in ProcessTextData()
     227             : 
     228           0 :     if (!mFrames.FirstChild()) {
     229           0 :       return;
     230             :     }
     231             : 
     232           0 :     mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR;
     233           0 :     mEmbellishData.coreFrame = this;
     234             : 
     235             :     // there are two particular things that we also need to record so that if our
     236             :     // parent is <mover>, <munder>, or <munderover>, they will treat us properly:
     237             :     // 1) do we have accent="true"
     238             :     // 2) do we have movablelimits="true"
     239             : 
     240             :     // they need the extra information to decide how to treat their scripts/limits
     241             :     // (note: <mover>, <munder>, or <munderover> need not necessarily be our
     242             :     // direct parent -- case of embellished operators)
     243             : 
     244             :     // default values from the Operator Dictionary were obtained in ProcessTextData()
     245             :     // and these special bits are always kept in mFlags
     246           0 :     if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags))
     247           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
     248           0 :     if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags))
     249           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
     250             : 
     251             :     // see if the accent attribute is there
     252           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value);
     253           0 :     if (value.EqualsLiteral("true"))
     254           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
     255           0 :     else if (value.EqualsLiteral("false"))
     256           0 :       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT;
     257             : 
     258             :     // see if the movablelimits attribute is there
     259           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::movablelimits_, value);
     260           0 :     if (value.EqualsLiteral("true"))
     261           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
     262           0 :     else if (value.EqualsLiteral("false"))
     263           0 :       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS;
     264             : 
     265             :      // ---------------------------------------------------------------------
     266             :      // we will be called again to re-sync the rest of our state next time...
     267             :      // (nobody needs the other values below at this stage)
     268           0 :      mFlags |= form;
     269           0 :      return;
     270             :   }
     271             : 
     272           0 :   nsPresContext* presContext = PresContext();
     273             : 
     274             :   // beware of bug 133814 - there is a two-way dependency in the
     275             :   // embellished hierarchy: our embellished ancestors need to set
     276             :   // their flags based on some of our state (set above), and here we
     277             :   // need to re-sync our 'form' depending on our outermost embellished
     278             :   // container. A null form here means that an earlier attempt to stretch
     279             :   // our mMathMLChar failed, in which case we don't bother re-stretching again
     280           0 :   if (form) {
     281             :     // get our outermost embellished container and its parent.
     282             :     // (we ensure that we are the core, not just a sibling of the core)
     283           0 :     nsIFrame* embellishAncestor = this;
     284           0 :     nsEmbellishData embellishData;
     285           0 :     nsIFrame* parentAncestor = this;
     286           0 :     do {
     287           0 :       embellishAncestor = parentAncestor;
     288           0 :       parentAncestor = embellishAncestor->GetParent();
     289           0 :       GetEmbellishDataFrom(parentAncestor, embellishData);
     290           0 :     } while (embellishData.coreFrame == this);
     291             : 
     292             :     // flag if we have an embellished ancestor
     293           0 :     if (embellishAncestor != this)
     294           0 :       mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
     295             :     else
     296           0 :       mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
     297             : 
     298             :     // find the position of our outermost embellished container w.r.t
     299             :     // its siblings.
     300             : 
     301           0 :     nsIFrame* nextSibling = embellishAncestor->GetNextSibling();
     302           0 :     nsIFrame* prevSibling = embellishAncestor->GetPrevSibling();
     303             : 
     304             :     // flag to distinguish from a real infix.  Set for (embellished) operators
     305             :     // that live in (inferred) mrows.
     306           0 :     nsIMathMLFrame* mathAncestor = do_QueryFrame(parentAncestor);
     307           0 :     bool zeroSpacing = false;
     308           0 :     if (mathAncestor) {
     309           0 :       zeroSpacing =  !mathAncestor->IsMrowLike();
     310             :     } else {
     311           0 :       nsMathMLmathBlockFrame* blockFrame = do_QueryFrame(parentAncestor);
     312           0 :       if (blockFrame) {
     313           0 :         zeroSpacing = !blockFrame->IsMrowLike();
     314             :       }
     315             :     }
     316           0 :     if (zeroSpacing) {
     317           0 :       mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
     318             :     } else {
     319           0 :       mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
     320             :     }
     321             : 
     322             :     // find our form
     323           0 :     form = NS_MATHML_OPERATOR_FORM_INFIX;
     324           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::form, value);
     325           0 :     if (!value.IsEmpty()) {
     326           0 :       if (value.EqualsLiteral("prefix"))
     327           0 :         form = NS_MATHML_OPERATOR_FORM_PREFIX;
     328           0 :       else if (value.EqualsLiteral("postfix"))
     329           0 :         form = NS_MATHML_OPERATOR_FORM_POSTFIX;
     330             :     }
     331             :     else {
     332             :       // set our form flag depending on the position
     333           0 :       if (!prevSibling && nextSibling)
     334           0 :         form = NS_MATHML_OPERATOR_FORM_PREFIX;
     335           0 :       else if (prevSibling && !nextSibling)
     336           0 :         form = NS_MATHML_OPERATOR_FORM_POSTFIX;
     337             :     }
     338           0 :     mFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the old form bits
     339           0 :     mFlags |= form;
     340             : 
     341             :     // Use the default value suggested by the MathML REC.
     342             :     // http://www.w3.org/TR/MathML/chapter3.html#presm.mo.attrs
     343             :     // thickmathspace = 5/18em
     344           0 :     float lspace = 5.0f/18.0f;
     345           0 :     float rspace = 5.0f/18.0f;
     346             :     // lookup the operator dictionary
     347           0 :     nsAutoString data;
     348           0 :     mMathMLChar.GetData(data);
     349           0 :     nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace);
     350             :     // Spacing is zero if our outermost embellished operator is not in an
     351             :     // inferred mrow.
     352           0 :     if (!NS_MATHML_OPERATOR_EMBELLISH_IS_ISOLATED(mFlags) &&
     353           0 :         (lspace || rspace)) {
     354             :       // Cache the default values of lspace and rspace.
     355             :       // since these values are relative to the 'em' unit, convert to twips now
     356             :       nscoord em;
     357             :       RefPtr<nsFontMetrics> fm =
     358           0 :         nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     359           0 :       GetEmHeight(fm, em);
     360             : 
     361           0 :       mEmbellishData.leadingSpace = NSToCoordRound(lspace * em);
     362           0 :       mEmbellishData.trailingSpace = NSToCoordRound(rspace * em);
     363             : 
     364             :       // tuning if we don't want too much extra space when we are a script.
     365             :       // (with its fonts, TeX sets lspace=0 & rspace=0 as soon as scriptlevel>0.
     366             :       // Our fonts can be anything, so...)
     367           0 :       if (StyleFont()->mScriptLevel > 0 &&
     368           0 :           !NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
     369           0 :         mEmbellishData.leadingSpace /= 2;
     370           0 :         mEmbellishData.trailingSpace /= 2;
     371             :       }
     372             :     }
     373             :   }
     374             : 
     375             :   // If we are an accent without explicit lspace="." or rspace=".",
     376             :   // we will ignore our default leading/trailing space
     377             : 
     378             :   // lspace
     379             :   //
     380             :   // "Specifies the leading space appearing before the operator"
     381             :   //
     382             :   // values: length
     383             :   // default: set by dictionary (thickmathspace)
     384             :   //
     385             :   // XXXfredw Support for negative and relative values is not implemented
     386             :   // (bug 805926).
     387             :   // Relative values will give a multiple of the current leading space,
     388             :   // which is not necessarily the default one.
     389             :   //
     390           0 :   nscoord leadingSpace = mEmbellishData.leadingSpace;
     391           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::lspace_, value);
     392           0 :   if (!value.IsEmpty()) {
     393           0 :     nsCSSValue cssValue;
     394           0 :     if (nsMathMLElement::ParseNumericValue(value, cssValue, 0,
     395           0 :                                            mContent->OwnerDoc())) {
     396           0 :       if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
     397           0 :         leadingSpace = 0;
     398           0 :       else if (cssValue.IsLengthUnit())
     399           0 :         leadingSpace = CalcLength(presContext, mStyleContext, cssValue,
     400           0 :                                   fontSizeInflation);
     401           0 :       mFlags |= NS_MATHML_OPERATOR_LSPACE_ATTR;
     402             :     }
     403             :   }
     404             : 
     405             :   // rspace
     406             :   //
     407             :   // "Specifies the trailing space appearing after the operator"
     408             :   //
     409             :   // values: length
     410             :   // default: set by dictionary (thickmathspace)
     411             :   //
     412             :   // XXXfredw Support for negative and relative values is not implemented
     413             :   // (bug 805926).
     414             :   // Relative values will give a multiple of the current leading space,
     415             :   // which is not necessarily the default one.
     416             :   //
     417           0 :   nscoord trailingSpace = mEmbellishData.trailingSpace;
     418           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rspace_, value);
     419           0 :   if (!value.IsEmpty()) {
     420           0 :     nsCSSValue cssValue;
     421           0 :     if (nsMathMLElement::ParseNumericValue(value, cssValue, 0,
     422           0 :                                            mContent->OwnerDoc())) {
     423           0 :       if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
     424           0 :         trailingSpace = 0;
     425           0 :       else if (cssValue.IsLengthUnit())
     426           0 :         trailingSpace = CalcLength(presContext, mStyleContext, cssValue,
     427           0 :                                    fontSizeInflation);
     428           0 :       mFlags |= NS_MATHML_OPERATOR_RSPACE_ATTR;
     429             :     }
     430             :   }
     431             : 
     432             :   // little extra tuning to round lspace & rspace to at least a pixel so that
     433             :   // operators don't look as if they are colliding with their operands
     434           0 :   if (leadingSpace || trailingSpace) {
     435           0 :     nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     436           0 :     if (leadingSpace && leadingSpace < onePixel)
     437           0 :       leadingSpace = onePixel;
     438           0 :     if (trailingSpace && trailingSpace < onePixel)
     439           0 :       trailingSpace = onePixel;
     440             :   }
     441             : 
     442             :   // the values that we get from our attributes override the dictionary
     443           0 :   mEmbellishData.leadingSpace = leadingSpace;
     444           0 :   mEmbellishData.trailingSpace = trailingSpace;
     445             : 
     446             :   // Now see if there are user-defined attributes that override the dictionary.
     447             :   // XXX Bug 1197771 - forcing an attribute to true when it is false in the
     448             :   // dictionary can cause conflicts in the rest of the stretching algorithms
     449             :   // (e.g. all largeops are assumed to have a vertical direction)
     450             : 
     451             :   // For each attribute overriden by the user, turn off its bit flag.
     452             :   // symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form
     453             :   // special: accent and movablelimits are handled above,
     454             :   // don't process them here
     455             : 
     456           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::stretchy_, value);
     457           0 :   if (value.EqualsLiteral("false")) {
     458           0 :     mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
     459           0 :   } else if (value.EqualsLiteral("true")) {
     460           0 :     mFlags |= NS_MATHML_OPERATOR_STRETCHY;
     461             :   }
     462           0 :   if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
     463           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::fence_, value);
     464           0 :     if (value.EqualsLiteral("false"))
     465           0 :       mFlags &= ~NS_MATHML_OPERATOR_FENCE;
     466             :     else
     467           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_FENCE;
     468             :   }
     469           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::largeop_, value);
     470           0 :   if (value.EqualsLiteral("false")) {
     471           0 :     mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
     472           0 :   } else if (value.EqualsLiteral("true")) {
     473           0 :     mFlags |= NS_MATHML_OPERATOR_LARGEOP;
     474             :   }
     475           0 :   if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
     476           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separator_, value);
     477           0 :     if (value.EqualsLiteral("false"))
     478           0 :       mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
     479             :     else
     480           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_SEPARATOR;
     481             :   }
     482           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::symmetric_, value);
     483           0 :   if (value.EqualsLiteral("false"))
     484           0 :     mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
     485           0 :   else if (value.EqualsLiteral("true"))
     486           0 :     mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
     487             : 
     488             : 
     489             :   // minsize
     490             :   //
     491             :   // "Specifies the minimum size of the operator when stretchy"
     492             :   //
     493             :   // values: length
     494             :   // default: set by dictionary (1em)
     495             :   //
     496             :   // We don't allow negative values.
     497             :   // Note: Contrary to other "length" values, unitless and percentage do not
     498             :   // give a multiple of the defaut value but a multiple of the operator at
     499             :   // normal size.
     500             :   //
     501           0 :   mMinSize = 0;
     502           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::minsize_, value);
     503           0 :   if (!value.IsEmpty()) {
     504           0 :     nsCSSValue cssValue;
     505           0 :     if (nsMathMLElement::ParseNumericValue(value, cssValue,
     506             :                                            nsMathMLElement::
     507             :                                            PARSE_ALLOW_UNITLESS,
     508           0 :                                            mContent->OwnerDoc())) {
     509           0 :       nsCSSUnit unit = cssValue.GetUnit();
     510           0 :       if (eCSSUnit_Number == unit)
     511           0 :         mMinSize = cssValue.GetFloatValue();
     512           0 :       else if (eCSSUnit_Percent == unit)
     513           0 :         mMinSize = cssValue.GetPercentValue();
     514           0 :       else if (eCSSUnit_Null != unit) {
     515           0 :         mMinSize = float(CalcLength(presContext, mStyleContext, cssValue,
     516             :                                     fontSizeInflation));
     517           0 :         mFlags |= NS_MATHML_OPERATOR_MINSIZE_ABSOLUTE;
     518             :       }
     519             :     }
     520             :   }
     521             : 
     522             :   // maxsize
     523             :   //
     524             :   // "Specifies the maximum size of the operator when stretchy"
     525             :   //
     526             :   // values: length | "infinity"
     527             :   // default: set by dictionary (infinity)
     528             :   //
     529             :   // We don't allow negative values.
     530             :   // Note: Contrary to other "length" values, unitless and percentage do not
     531             :   // give a multiple of the defaut value but a multiple of the operator at
     532             :   // normal size.
     533             :   //
     534           0 :   mMaxSize = NS_MATHML_OPERATOR_SIZE_INFINITY;
     535           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::maxsize_, value);
     536           0 :   if (!value.IsEmpty()) {
     537           0 :     nsCSSValue cssValue;
     538           0 :     if (nsMathMLElement::ParseNumericValue(value, cssValue,
     539             :                                            nsMathMLElement::
     540             :                                            PARSE_ALLOW_UNITLESS,
     541           0 :                                            mContent->OwnerDoc())) {
     542           0 :       nsCSSUnit unit = cssValue.GetUnit();
     543           0 :       if (eCSSUnit_Number == unit)
     544           0 :         mMaxSize = cssValue.GetFloatValue();
     545           0 :       else if (eCSSUnit_Percent == unit)
     546           0 :         mMaxSize = cssValue.GetPercentValue();
     547           0 :       else if (eCSSUnit_Null != unit) {
     548           0 :         mMaxSize = float(CalcLength(presContext, mStyleContext, cssValue,
     549             :                                     fontSizeInflation));
     550           0 :         mFlags |= NS_MATHML_OPERATOR_MAXSIZE_ABSOLUTE;
     551             :       }
     552             :     }
     553             :   }
     554             : }
     555             : 
     556             : static uint32_t
     557           0 : GetStretchHint(nsOperatorFlags aFlags, nsPresentationData aPresentationData,
     558             :                bool aIsVertical, const nsStyleFont* aStyleFont)
     559             : {
     560           0 :   uint32_t stretchHint = NS_STRETCH_NONE;
     561             :   // See if it is okay to stretch,
     562             :   // starting from what the Operator Dictionary said
     563           0 :   if (NS_MATHML_OPERATOR_IS_MUTABLE(aFlags)) {
     564             :     // set the largeop or largeopOnly flags to suitably cover all the
     565             :     // 8 possible cases depending on whether displaystyle, largeop,
     566             :     // stretchy are true or false (see bug 69325).
     567             :     // . largeopOnly is taken if largeop=true and stretchy=false
     568             :     // . largeop is taken if largeop=true and stretchy=true
     569           0 :     if (aStyleFont->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
     570           0 :         NS_MATHML_OPERATOR_IS_LARGEOP(aFlags)) {
     571           0 :       stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!)
     572           0 :       if (NS_MATHML_OPERATOR_IS_INTEGRAL(aFlags)) {
     573           0 :         stretchHint |= NS_STRETCH_INTEGRAL;
     574             :       }
     575           0 :       if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) {
     576           0 :         stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER;
     577             :       }
     578             :     }
     579           0 :     else if(NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) {
     580           0 :       if (aIsVertical) {
     581             :         // TeX hint. Can impact some sloppy markups missing <mrow></mrow>
     582           0 :         stretchHint = NS_STRETCH_NEARER;
     583             :       }
     584             :       else {
     585           0 :         stretchHint = NS_STRETCH_NORMAL;
     586             :       }
     587             :     }
     588             :     // else if the stretchy and largeop attributes have been disabled,
     589             :     // the operator is not mutable
     590             :   }
     591           0 :   return stretchHint;
     592             : }
     593             : 
     594             : // NOTE: aDesiredStretchSize is an IN/OUT parameter
     595             : //       On input  - it contains our current size
     596             : //       On output - the same size or the new size that we want
     597             : NS_IMETHODIMP
     598           0 : nsMathMLmoFrame::Stretch(DrawTarget*          aDrawTarget,
     599             :                          nsStretchDirection   aStretchDirection,
     600             :                          nsBoundingMetrics&   aContainerSize,
     601             :                          ReflowOutput& aDesiredStretchSize)
     602             : {
     603           0 :   if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
     604           0 :     NS_WARNING("it is wrong to fire stretch more than once on a frame");
     605           0 :     return NS_OK;
     606             :   }
     607           0 :   mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
     608             : 
     609           0 :   nsIFrame* firstChild = mFrames.FirstChild();
     610             : 
     611             :   // get the axis height;
     612           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     613             :   RefPtr<nsFontMetrics> fm =
     614           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     615             :   nscoord axisHeight, height;
     616           0 :   GetAxisHeight(aDrawTarget, fm, axisHeight);
     617             : 
     618             :   // get the leading to be left at the top and the bottom of the stretched char
     619             :   // this seems more reliable than using fm->GetLeading() on suspicious fonts
     620             :   nscoord em;
     621           0 :   GetEmHeight(fm, em);
     622           0 :   nscoord leading = NSToCoordRound(0.2f * em);
     623             : 
     624             :   // Operators that are stretchy, or those that are to be centered
     625             :   // to cater for fonts that are not math-aware, are handled by the MathMLChar
     626             :   // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time)
     627           0 :   bool useMathMLChar = UseMathMLChar();
     628             : 
     629           0 :   nsBoundingMetrics charSize;
     630           0 :   nsBoundingMetrics container = aDesiredStretchSize.mBoundingMetrics;
     631           0 :   bool isVertical = false;
     632             : 
     633           0 :   if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) ||
     634           0 :        (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT))  &&
     635           0 :       (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL)) {
     636           0 :     isVertical = true;
     637             :   }
     638             : 
     639             :   uint32_t stretchHint =
     640           0 :     GetStretchHint(mFlags, mPresentationData, isVertical, StyleFont());
     641             : 
     642           0 :   if (useMathMLChar) {
     643           0 :     nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics;
     644             : 
     645           0 :     if (stretchHint != NS_STRETCH_NONE) {
     646             : 
     647           0 :       container = aContainerSize;
     648             : 
     649             :       // some adjustments if the operator is symmetric and vertical
     650             : 
     651           0 :       if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
     652             :         // we need to center about the axis
     653           0 :         nscoord delta = std::max(container.ascent - axisHeight,
     654           0 :                                container.descent + axisHeight);
     655           0 :         container.ascent = delta + axisHeight;
     656           0 :         container.descent = delta - axisHeight;
     657             : 
     658             :         // get ready in case we encounter user-desired min-max size
     659           0 :         delta = std::max(initialSize.ascent - axisHeight,
     660           0 :                        initialSize.descent + axisHeight);
     661           0 :         initialSize.ascent = delta + axisHeight;
     662           0 :         initialSize.descent = delta - axisHeight;
     663             :       }
     664             : 
     665             :       // check for user-desired min-max size
     666             : 
     667           0 :       if (mMaxSize != NS_MATHML_OPERATOR_SIZE_INFINITY && mMaxSize > 0.0f) {
     668             :         // if we are here, there is a user defined maxsize ...
     669             :         //XXX Set stretchHint = NS_STRETCH_NORMAL? to honor the maxsize as close as possible?
     670           0 :         if (NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)) {
     671             :           // there is an explicit value like maxsize="20pt"
     672             :           // try to maintain the aspect ratio of the char
     673           0 :           float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent);
     674           0 :           container.ascent =
     675           0 :             std::min(container.ascent, nscoord(initialSize.ascent * aspect));
     676           0 :           container.descent =
     677           0 :             std::min(container.descent, nscoord(initialSize.descent * aspect));
     678             :           // below we use a type cast instead of a conversion to avoid a VC++ bug
     679             :           // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP
     680           0 :           container.width =
     681           0 :             std::min(container.width, (nscoord)mMaxSize);
     682             :         }
     683             :         else { // multiplicative value
     684           0 :           container.ascent =
     685           0 :             std::min(container.ascent, nscoord(initialSize.ascent * mMaxSize));
     686           0 :           container.descent =
     687           0 :             std::min(container.descent, nscoord(initialSize.descent * mMaxSize));
     688           0 :           container.width =
     689           0 :             std::min(container.width, nscoord(initialSize.width * mMaxSize));
     690             :         }
     691             : 
     692           0 :         if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
     693             :           // re-adjust to align the char with the bottom of the initial container
     694           0 :           height = container.ascent + container.descent;
     695           0 :           container.descent = aContainerSize.descent;
     696           0 :           container.ascent = height - container.descent;
     697             :         }
     698             :       }
     699             : 
     700           0 :       if (mMinSize > 0.0f) {
     701             :         // if we are here, there is a user defined minsize ...
     702             :         // always allow the char to stretch in its natural direction,
     703             :         // even if it is different from the caller's direction
     704           0 :         if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT &&
     705           0 :             aStretchDirection != mEmbellishData.direction) {
     706           0 :           aStretchDirection = NS_STRETCH_DIRECTION_DEFAULT;
     707             :           // but when we are not honoring the requested direction
     708             :           // we should not use the caller's container size either
     709           0 :           container = initialSize;
     710             :         }
     711           0 :         if (NS_MATHML_OPERATOR_MINSIZE_IS_ABSOLUTE(mFlags)) {
     712             :           // there is an explicit value like minsize="20pt"
     713             :           // try to maintain the aspect ratio of the char
     714           0 :           float aspect = mMinSize / float(initialSize.ascent + initialSize.descent);
     715           0 :           container.ascent =
     716           0 :             std::max(container.ascent, nscoord(initialSize.ascent * aspect));
     717           0 :           container.descent =
     718           0 :             std::max(container.descent, nscoord(initialSize.descent * aspect));
     719           0 :           container.width =
     720           0 :             std::max(container.width, (nscoord)mMinSize);
     721             :         }
     722             :         else { // multiplicative value
     723           0 :           container.ascent =
     724           0 :             std::max(container.ascent, nscoord(initialSize.ascent * mMinSize));
     725           0 :           container.descent =
     726           0 :             std::max(container.descent, nscoord(initialSize.descent * mMinSize));
     727           0 :           container.width =
     728           0 :             std::max(container.width, nscoord(initialSize.width * mMinSize));
     729             :         }
     730             : 
     731           0 :         if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
     732             :           // re-adjust to align the char with the bottom of the initial container
     733           0 :           height = container.ascent + container.descent;
     734           0 :           container.descent = aContainerSize.descent;
     735           0 :           container.ascent = height - container.descent;
     736             :         }
     737             :       }
     738             :     }
     739             : 
     740             :     // let the MathMLChar stretch itself...
     741           0 :     nsresult res = mMathMLChar.Stretch(PresContext(), aDrawTarget,
     742             :                                        fontSizeInflation,
     743             :                                        aStretchDirection, container, charSize,
     744             :                                        stretchHint,
     745           0 :                                        StyleVisibility()->mDirection);
     746           0 :     if (NS_FAILED(res)) {
     747             :       // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed)
     748             :       // clear our 'form' to behave as if the operator wasn't in the dictionary
     749           0 :       mFlags &= ~NS_MATHML_OPERATOR_FORM;
     750           0 :       useMathMLChar = false;
     751             :     }
     752             :   }
     753             : 
     754             :   // Place our children using the default method
     755             :   // This will allow our child text frame to get its DidReflow()
     756           0 :   nsresult rv = Place(aDrawTarget, true, aDesiredStretchSize);
     757           0 :   if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
     758             :     // Make sure the child frames get their DidReflow() calls.
     759           0 :     DidReflowChildren(mFrames.FirstChild());
     760             :   }
     761             : 
     762           0 :   if (useMathMLChar) {
     763             :     // update our bounding metrics... it becomes that of our MathML char
     764           0 :     mBoundingMetrics = charSize;
     765             : 
     766             :     // if the returned direction is 'unsupported', the char didn't actually change.
     767             :     // So we do the centering only if necessary
     768           0 :     if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED ||
     769           0 :         NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
     770             : 
     771             :       bool largeopOnly =
     772           0 :         (NS_STRETCH_LARGEOP & stretchHint) != 0 &&
     773           0 :         (NS_STRETCH_VARIABLE_MASK & stretchHint) == 0;
     774             : 
     775           0 :       if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
     776             :         // the desired size returned by mMathMLChar maybe different
     777             :         // from the size of the container.
     778             :         // the mMathMLChar.mRect.y calculation is subtle, watch out!!!
     779             : 
     780           0 :         height = mBoundingMetrics.ascent + mBoundingMetrics.descent;
     781           0 :         if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) ||
     782           0 :             NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
     783             :           // For symmetric and vertical operators, or for operators that are always
     784             :           // centered ('+', '*', etc) we want to center about the axis of the container
     785           0 :           mBoundingMetrics.descent = height/2 - axisHeight;
     786           0 :         } else if (!largeopOnly) {
     787             :           // Align the center of the char with the center of the container
     788           0 :           mBoundingMetrics.descent = height/2 +
     789           0 :             (container.ascent + container.descent)/2 - container.ascent;
     790             :         } // else align the baselines
     791           0 :         mBoundingMetrics.ascent = height - mBoundingMetrics.descent;
     792             :       }
     793             :     }
     794             :   }
     795             : 
     796             :   // Fixup for the final height.
     797             :   // On one hand, our stretchy height can sometimes be shorter than surrounding
     798             :   // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading|
     799             :   // that is smaller than the ASCII's ascent, hence when painting the background
     800             :   // later, it won't look uniform along the line.
     801             :   // On the other hand, sometimes we may leave too much gap when our glyph happens
     802             :   // to come from a font with tall glyphs. For example, since CMEX10 has very tall
     803             :   // glyphs, its natural font metrics are large, even if we pick a small glyph
     804             :   // whose size is comparable to the size of a normal ASCII glyph.
     805             :   // So to avoid uneven spacing in either of these two cases, we use the height
     806             :   // of the ASCII font as a reference and try to match it if possible.
     807             : 
     808             :   // special case for accents... keep them short to improve mouse operations...
     809             :   // an accent can only be the non-first child of <mover>, <munder>, <munderover>
     810             :   bool isAccent =
     811           0 :     NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags);
     812           0 :   if (isAccent) {
     813           0 :     nsEmbellishData parentData;
     814           0 :     GetEmbellishDataFrom(GetParent(), parentData);
     815           0 :     isAccent =
     816           0 :        (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) ||
     817           0 :         NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) &&
     818           0 :        parentData.coreFrame != this;
     819             :   }
     820           0 :   if (isAccent && firstChild) {
     821             :     // see bug 188467 for what is going on here
     822           0 :     nscoord dy = aDesiredStretchSize.BlockStartAscent() -
     823           0 :       (mBoundingMetrics.ascent + leading);
     824           0 :     aDesiredStretchSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
     825           0 :     aDesiredStretchSize.Height() = aDesiredStretchSize.BlockStartAscent() +
     826           0 :                                    mBoundingMetrics.descent;
     827             : 
     828           0 :     firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy));
     829             :   }
     830           0 :   else if (useMathMLChar) {
     831           0 :     nscoord ascent = fm->MaxAscent();
     832           0 :     nscoord descent = fm->MaxDescent();
     833           0 :     aDesiredStretchSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent + leading, ascent));
     834           0 :     aDesiredStretchSize.Height() = aDesiredStretchSize.BlockStartAscent() +
     835           0 :                                  std::max(mBoundingMetrics.descent + leading, descent);
     836             :   }
     837           0 :   aDesiredStretchSize.Width() = mBoundingMetrics.width;
     838           0 :   aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics;
     839           0 :   mReference.x = 0;
     840           0 :   mReference.y = aDesiredStretchSize.BlockStartAscent();
     841             :   // Place our mMathMLChar, its origin is in our coordinate system
     842           0 :   if (useMathMLChar) {
     843           0 :     nscoord dy = aDesiredStretchSize.BlockStartAscent() - mBoundingMetrics.ascent;
     844           0 :     mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent));
     845             :   }
     846             : 
     847             :   // Before we leave... there is a last item in the check-list:
     848             :   // If our parent is not embellished, it means we are the outermost embellished
     849             :   // container and so we put the spacing, otherwise we don't include the spacing,
     850             :   // the outermost embellished container will take care of it.
     851             : 
     852           0 :   if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
     853             : 
     854             :     // Account the spacing if we are not an accent with explicit attributes
     855           0 :     nscoord leadingSpace = mEmbellishData.leadingSpace;
     856           0 :     if (isAccent && !NS_MATHML_OPERATOR_HAS_LSPACE_ATTR(mFlags)) {
     857           0 :       leadingSpace = 0;
     858             :     }
     859           0 :     nscoord trailingSpace = mEmbellishData.trailingSpace;
     860           0 :     if (isAccent && !NS_MATHML_OPERATOR_HAS_RSPACE_ATTR(mFlags)) {
     861           0 :       trailingSpace = 0;
     862             :     }
     863             : 
     864           0 :     mBoundingMetrics.width += leadingSpace + trailingSpace;
     865           0 :     aDesiredStretchSize.Width() = mBoundingMetrics.width;
     866           0 :     aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
     867             : 
     868           0 :     nscoord dx = (StyleVisibility()->mDirection ?
     869           0 :                   trailingSpace : leadingSpace);
     870           0 :     if (dx) {
     871             :       // adjust the offsets
     872           0 :       mBoundingMetrics.leftBearing += dx;
     873           0 :       mBoundingMetrics.rightBearing += dx;
     874           0 :       aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
     875           0 :       aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
     876             : 
     877           0 :       if (useMathMLChar) {
     878           0 :         nsRect rect;
     879           0 :         mMathMLChar.GetRect(rect);
     880           0 :         mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y,
     881           0 :                                    rect.width, rect.height));
     882             :       }
     883             :       else {
     884           0 :         nsIFrame* childFrame = firstChild;
     885           0 :         while (childFrame) {
     886           0 :           childFrame->SetPosition(childFrame->GetPosition() +
     887           0 :                                   nsPoint(dx, 0));
     888           0 :           childFrame = childFrame->GetNextSibling();
     889             :         }
     890             :       }
     891             :     }
     892             :   }
     893             : 
     894             :   // Finished with these:
     895           0 :   ClearSavedChildMetrics();
     896             :   // Set our overflow area
     897           0 :   GatherAndStoreOverflow(&aDesiredStretchSize);
     898             : 
     899             :   // There used to be code here to change the height of the child frame to
     900             :   // change the caret height, but the text frame that manages the caret is now
     901             :   // not a direct child but wrapped in a block frame.  See also bug 412033.
     902             : 
     903           0 :   return NS_OK;
     904             : }
     905             : 
     906             : NS_IMETHODIMP
     907           0 : nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent)
     908             : {
     909             :   // retain our native direction, it only changes if our text content changes
     910           0 :   nsStretchDirection direction = mEmbellishData.direction;
     911           0 :   nsMathMLTokenFrame::InheritAutomaticData(aParent);
     912           0 :   ProcessTextData();
     913           0 :   mEmbellishData.direction = direction;
     914           0 :   return NS_OK;
     915             : }
     916             : 
     917             : NS_IMETHODIMP
     918           0 : nsMathMLmoFrame::TransmitAutomaticData()
     919             : {
     920             :   // this will cause us to re-sync our flags from scratch
     921             :   // but our returned 'form' is still not final (bug 133429), it will
     922             :   // be recomputed to its final value during the next call in Reflow()
     923           0 :   mEmbellishData.coreFrame = nullptr;
     924           0 :   ProcessOperatorData();
     925           0 :   return NS_OK;
     926             : }
     927             : 
     928             : void
     929           0 : nsMathMLmoFrame::SetInitialChildList(ChildListID     aListID,
     930             :                                      nsFrameList&    aChildList)
     931             : {
     932             :   // First, let the parent class do its work
     933           0 :   nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList);
     934           0 :   ProcessTextData();
     935           0 : }
     936             : 
     937             : void
     938           0 : nsMathMLmoFrame::Reflow(nsPresContext*          aPresContext,
     939             :                         ReflowOutput&     aDesiredSize,
     940             :                         const ReflowInput& aReflowInput,
     941             :                         nsReflowStatus&          aStatus)
     942             : {
     943             :   // certain values use units that depend on our style context, so
     944             :   // it is safer to just process the whole lot here
     945           0 :   ProcessOperatorData();
     946             : 
     947           0 :   nsMathMLTokenFrame::Reflow(aPresContext, aDesiredSize,
     948           0 :                              aReflowInput, aStatus);
     949           0 : }
     950             : 
     951             : nsresult
     952           0 : nsMathMLmoFrame::Place(DrawTarget*          aDrawTarget,
     953             :                        bool                 aPlaceOrigin,
     954             :                        ReflowOutput& aDesiredSize)
     955             : {
     956           0 :   nsresult rv = nsMathMLTokenFrame::Place(aDrawTarget, aPlaceOrigin, aDesiredSize);
     957             : 
     958           0 :   if (NS_FAILED(rv)) {
     959           0 :     return rv;
     960             :   }
     961             : 
     962             :   /* Special behaviour for largeops.
     963             :      In MathML "stretchy" and displaystyle "largeop" are different notions,
     964             :      even if we use the same technique to draw them (picking size variants).
     965             :      So largeop display operators should be considered "non-stretchy" and
     966             :      thus their sizes should be taken into account for the stretch size of
     967             :      other elements.
     968             : 
     969             :      This is a preliminary stretch - exact sizing/placement is handled by the
     970             :      Stretch() method.
     971             :   */
     972             : 
     973           0 :   if (!aPlaceOrigin &&
     974           0 :       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
     975           0 :       NS_MATHML_OPERATOR_IS_LARGEOP(mFlags) && UseMathMLChar()) {
     976           0 :     nsBoundingMetrics newMetrics;
     977           0 :     rv = mMathMLChar.Stretch(PresContext(), aDrawTarget,
     978             :                              nsLayoutUtils::FontSizeInflationFor(this),
     979             :                              NS_STRETCH_DIRECTION_VERTICAL,
     980             :                              aDesiredSize.mBoundingMetrics, newMetrics,
     981           0 :                              NS_STRETCH_LARGEOP, StyleVisibility()->mDirection);
     982             : 
     983           0 :     if (NS_FAILED(rv)) {
     984             :       // Just use the initial size
     985           0 :       return NS_OK;
     986             :     }
     987             : 
     988           0 :     aDesiredSize.mBoundingMetrics = newMetrics;
     989             :      /* Treat the ascent/descent values calculated in the TokenFrame place
     990             :        calculations as the minimum for aDesiredSize calculations, rather
     991             :        than fetching them from font metrics again.
     992             :     */
     993           0 :     aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent,
     994           0 :                                               newMetrics.ascent));
     995           0 :     aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     996           0 :                             std::max(mBoundingMetrics.descent,
     997           0 :                                      newMetrics.descent);
     998           0 :     aDesiredSize.Width() = newMetrics.width;
     999           0 :     mBoundingMetrics = newMetrics;
    1000             :   }
    1001           0 :   return NS_OK;
    1002             : }
    1003             : 
    1004             : /* virtual */ void
    1005           0 : nsMathMLmoFrame::MarkIntrinsicISizesDirty()
    1006             : {
    1007             :   // if we get this, it may mean that something changed in the text
    1008             :   // content. So blow away everything an re-build the automatic data
    1009             :   // from the parent of our outermost embellished container (we ensure
    1010             :   // that we are the core, not just a sibling of the core)
    1011             : 
    1012           0 :   ProcessTextData();
    1013             : 
    1014           0 :   nsIFrame* target = this;
    1015           0 :   nsEmbellishData embellishData;
    1016           0 :   do {
    1017           0 :     target = target->GetParent();
    1018           0 :     GetEmbellishDataFrom(target, embellishData);
    1019           0 :   } while (embellishData.coreFrame == this);
    1020             : 
    1021             :   // we have automatic data to update in the children of the target frame
    1022             :   // XXXldb This should really be marking dirty rather than rebuilding
    1023             :   // so that we don't rebuild multiple times for the same change.
    1024           0 :   RebuildAutomaticDataForChildren(target);
    1025             : 
    1026           0 :   nsMathMLContainerFrame::MarkIntrinsicISizesDirty();
    1027           0 : }
    1028             : 
    1029             : /* virtual */ void
    1030           0 : nsMathMLmoFrame::GetIntrinsicISizeMetrics(gfxContext* aRenderingContext,
    1031             :                                           ReflowOutput& aDesiredSize)
    1032             : {
    1033           0 :   ProcessOperatorData();
    1034           0 :   if (UseMathMLChar()) {
    1035           0 :     uint32_t stretchHint = GetStretchHint(mFlags, mPresentationData, true,
    1036           0 :                                           StyleFont());
    1037           0 :     aDesiredSize.Width() = mMathMLChar.
    1038           0 :       GetMaxWidth(PresContext(), aRenderingContext->GetDrawTarget(),
    1039             :                   nsLayoutUtils::FontSizeInflationFor(this),
    1040             :                   stretchHint);
    1041             :   }
    1042             :   else {
    1043           0 :     nsMathMLTokenFrame::GetIntrinsicISizeMetrics(aRenderingContext,
    1044           0 :                                                  aDesiredSize);
    1045             :   }
    1046             : 
    1047             :   // leadingSpace and trailingSpace are actually applied to the outermost
    1048             :   // embellished container but for determining total intrinsic width it should
    1049             :   // be safe to include it for the core here instead.
    1050           0 :   bool isRTL = StyleVisibility()->mDirection;
    1051           0 :   aDesiredSize.Width() +=
    1052           0 :     mEmbellishData.leadingSpace + mEmbellishData.trailingSpace;
    1053           0 :   aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width();
    1054           0 :   if (isRTL) {
    1055           0 :     aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.trailingSpace;
    1056           0 :     aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.trailingSpace;
    1057             :   } else {
    1058           0 :     aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.leadingSpace;
    1059           0 :     aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.leadingSpace;
    1060             :   }
    1061           0 : }
    1062             : 
    1063             : nsresult
    1064           0 : nsMathMLmoFrame::AttributeChanged(int32_t         aNameSpaceID,
    1065             :                                   nsIAtom*        aAttribute,
    1066             :                                   int32_t         aModType)
    1067             : {
    1068             :   // check if this is an attribute that can affect the embellished hierarchy
    1069             :   // in a significant way and re-layout the entire hierarchy.
    1070           0 :   if (nsGkAtoms::accent_ == aAttribute ||
    1071           0 :       nsGkAtoms::movablelimits_ == aAttribute) {
    1072             : 
    1073             :     // set the target as the parent of our outermost embellished container
    1074             :     // (we ensure that we are the core, not just a sibling of the core)
    1075           0 :     nsIFrame* target = this;
    1076           0 :     nsEmbellishData embellishData;
    1077           0 :     do {
    1078           0 :       target = target->GetParent();
    1079           0 :       GetEmbellishDataFrom(target, embellishData);
    1080           0 :     } while (embellishData.coreFrame == this);
    1081             : 
    1082             :     // we have automatic data to update in the children of the target frame
    1083           0 :     return ReLayoutChildren(target);
    1084             :   }
    1085             : 
    1086             :   return nsMathMLTokenFrame::
    1087           0 :          AttributeChanged(aNameSpaceID, aAttribute, aModType);
    1088             : }
    1089             : 
    1090             : // ----------------------
    1091             : // No need to track the style context given to our MathML char.
    1092             : // the Style System will use these to pass the proper style context to our MathMLChar
    1093             : nsStyleContext*
    1094           0 : nsMathMLmoFrame::GetAdditionalStyleContext(int32_t aIndex) const
    1095             : {
    1096           0 :   switch (aIndex) {
    1097             :   case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
    1098           0 :     return mMathMLChar.GetStyleContext();
    1099             :   default:
    1100           0 :     return nullptr;
    1101             :   }
    1102             : }
    1103             : 
    1104             : void
    1105           0 : nsMathMLmoFrame::SetAdditionalStyleContext(int32_t          aIndex,
    1106             :                                            nsStyleContext*  aStyleContext)
    1107             : {
    1108           0 :   switch (aIndex) {
    1109             :   case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
    1110           0 :     mMathMLChar.SetStyleContext(aStyleContext);
    1111           0 :     break;
    1112             :   }
    1113           0 : }

Generated by: LCOV version 1.13