LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmunderoverFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 320 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 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 "nsMathMLmunderoverFrame.h"
       7             : #include "nsPresContext.h"
       8             : #include "nsMathMLmmultiscriptsFrame.h"
       9             : #include "nsMathMLElement.h"
      10             : #include <algorithm>
      11             : #include "gfxContext.h"
      12             : #include "gfxMathTable.h"
      13             : 
      14             : //
      15             : // <munderover> -- attach an underscript-overscript pair to a base - implementation
      16             : // <mover> -- attach an overscript to a base - implementation
      17             : // <munder> -- attach an underscript to a base - implementation
      18             : //
      19             : 
      20             : nsIFrame*
      21           0 : NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      22             : {
      23           0 :   return new (aPresShell) nsMathMLmunderoverFrame(aContext);
      24             : }
      25             : 
      26           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmunderoverFrame)
      27             : 
      28           0 : nsMathMLmunderoverFrame::~nsMathMLmunderoverFrame()
      29             : {
      30           0 : }
      31             : 
      32             : nsresult
      33           0 : nsMathMLmunderoverFrame::AttributeChanged(int32_t         aNameSpaceID,
      34             :                                           nsIAtom*        aAttribute,
      35             :                                           int32_t         aModType)
      36             : {
      37           0 :   if (nsGkAtoms::accent_ == aAttribute ||
      38           0 :       nsGkAtoms::accentunder_ == aAttribute) {
      39             :     // When we have automatic data to update within ourselves, we ask our
      40             :     // parent to re-layout its children
      41           0 :     return ReLayoutChildren(GetParent());
      42             :   }
      43             : 
      44             :   return nsMathMLContainerFrame::
      45           0 :          AttributeChanged(aNameSpaceID, aAttribute, aModType);
      46             : }
      47             : 
      48             : NS_IMETHODIMP
      49           0 : nsMathMLmunderoverFrame::UpdatePresentationData(uint32_t        aFlagsValues,
      50             :                                                 uint32_t        aFlagsToUpdate)
      51             : {
      52           0 :   nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues, aFlagsToUpdate);
      53             :   // disable the stretch-all flag if we are going to act like a subscript-superscript pair
      54           0 :   if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
      55           0 :       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
      56           0 :     mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
      57             :   }
      58             :   else {
      59           0 :     mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
      60             :   }
      61           0 :   return NS_OK;
      62             : }
      63             : 
      64             : NS_IMETHODIMP
      65           0 : nsMathMLmunderoverFrame::InheritAutomaticData(nsIFrame* aParent)
      66             : {
      67             :   // let the base class get the default from our parent
      68           0 :   nsMathMLContainerFrame::InheritAutomaticData(aParent);
      69             : 
      70           0 :   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
      71             : 
      72           0 :   return NS_OK;
      73             : }
      74             : 
      75             : void
      76           0 : nsMathMLmunderoverFrame::DestroyFrom(nsIFrame* aDestroyRoot)
      77             : {
      78           0 :   if (!mPostReflowIncrementScriptLevelCommands.IsEmpty()) {
      79           0 :     PresContext()->PresShell()->CancelReflowCallback(this);
      80             :   }
      81           0 :   nsMathMLContainerFrame::DestroyFrom(aDestroyRoot);
      82           0 : }
      83             : 
      84             : uint8_t
      85           0 : nsMathMLmunderoverFrame::ScriptIncrement(nsIFrame* aFrame)
      86             : {
      87           0 :   nsIFrame* child = mFrames.FirstChild();
      88           0 :   if (!aFrame || aFrame == child) {
      89           0 :     return 0;
      90             :   }
      91           0 :   child = child->GetNextSibling();
      92           0 :   if (aFrame == child) {
      93           0 :     if (mContent->IsMathMLElement(nsGkAtoms::mover_)) {
      94           0 :       return mIncrementOver ? 1 : 0;
      95             :     }
      96           0 :     return mIncrementUnder ? 1 : 0;
      97             :   }
      98           0 :   if (child && aFrame == child->GetNextSibling()) {
      99             :     // must be a over frame of munderover
     100           0 :     return mIncrementOver ? 1 : 0;
     101             :   }
     102           0 :   return 0;  // frame not found
     103             : }
     104             : 
     105             : void
     106           0 : nsMathMLmunderoverFrame::SetIncrementScriptLevel(uint32_t aChildIndex,
     107             :                                                  bool aIncrement)
     108             : {
     109           0 :   nsIFrame* child = PrincipalChildList().FrameAt(aChildIndex);
     110           0 :   if (!child || !child->GetContent()->IsMathMLElement() ||
     111           0 :       child->GetContent()->GetPrimaryFrame() != child) {
     112           0 :     return;
     113             :   }
     114             : 
     115           0 :   auto element = static_cast<nsMathMLElement*>(child->GetContent());
     116           0 :   if (element->GetIncrementScriptLevel() == aIncrement) {
     117           0 :     return;
     118             :   }
     119             : 
     120           0 :   if (mPostReflowIncrementScriptLevelCommands.IsEmpty()) {
     121           0 :     PresContext()->PresShell()->PostReflowCallback(this);
     122             :   }
     123             : 
     124           0 :   mPostReflowIncrementScriptLevelCommands.AppendElement(
     125           0 :       SetIncrementScriptLevelCommand { aChildIndex, aIncrement });
     126             : }
     127             : 
     128             : bool
     129           0 : nsMathMLmunderoverFrame::ReflowFinished()
     130             : {
     131           0 :   SetPendingPostReflowIncrementScriptLevel();
     132           0 :   return true;
     133             : }
     134             : 
     135             : void
     136           0 : nsMathMLmunderoverFrame::ReflowCallbackCanceled()
     137             : {
     138             :   // Do nothing, at this point our work will just be useless.
     139           0 :   mPostReflowIncrementScriptLevelCommands.Clear();
     140           0 : }
     141             : 
     142             : void
     143           0 : nsMathMLmunderoverFrame::SetPendingPostReflowIncrementScriptLevel()
     144             : {
     145           0 :   MOZ_ASSERT(!mPostReflowIncrementScriptLevelCommands.IsEmpty());
     146             : 
     147           0 :   nsTArray<SetIncrementScriptLevelCommand> commands;
     148           0 :   commands.SwapElements(mPostReflowIncrementScriptLevelCommands);
     149             : 
     150           0 :   for (const auto& command : commands) {
     151           0 :     nsIFrame* child = PrincipalChildList().FrameAt(command.mChildIndex);
     152           0 :     if (!child || !child->GetContent()->IsMathMLElement()) {
     153           0 :       continue;
     154             :     }
     155             : 
     156           0 :     auto element = static_cast<nsMathMLElement*>(child->GetContent());
     157           0 :     element->SetIncrementScriptLevel(command.mDoIncrement, true);
     158             :   }
     159           0 : }
     160             : 
     161             : NS_IMETHODIMP
     162           0 : nsMathMLmunderoverFrame::TransmitAutomaticData()
     163             : {
     164             :   // At this stage, all our children are in sync and we can fully
     165             :   // resolve our own mEmbellishData struct
     166             :   //---------------------------------------------------------------------
     167             : 
     168             :   /*
     169             :   The REC says:
     170             : 
     171             :   As regards munder (respectively mover) :
     172             :   The default value of accentunder is false, unless underscript
     173             :   is an <mo> element or an embellished operator.  If underscript is
     174             :   an <mo> element, the value of its accent attribute is used as the
     175             :   default value of accentunder. If underscript is an embellished
     176             :   operator, the accent attribute of the <mo> element at its
     177             :   core is used as the default value. As with all attributes, an
     178             :   explicitly given value overrides the default.
     179             : 
     180             : XXX The winner is the outermost setting in conflicting settings like these:
     181             : <munder accentunder='true'>
     182             :   <mi>...</mi>
     183             :   <mo accentunder='false'> ... </mo>
     184             : </munder>
     185             : 
     186             :   As regards munderover:
     187             :   The accent and accentunder attributes have the same effect as
     188             :   the attributes with the same names on <mover>  and <munder>,
     189             :   respectively. Their default values are also computed in the
     190             :   same manner as described for those elements, with the default
     191             :   value of accent depending on overscript and the default value
     192             :   of accentunder depending on underscript.
     193             :   */
     194             : 
     195           0 :   nsIFrame* overscriptFrame = nullptr;
     196           0 :   nsIFrame* underscriptFrame = nullptr;
     197           0 :   nsIFrame* baseFrame = mFrames.FirstChild();
     198             : 
     199           0 :   if (baseFrame) {
     200           0 :     if (mContent->IsAnyOfMathMLElements(nsGkAtoms::munder_,
     201             :                                         nsGkAtoms::munderover_)) {
     202           0 :       underscriptFrame = baseFrame->GetNextSibling();
     203             :     } else {
     204           0 :       NS_ASSERTION(mContent->IsMathMLElement(nsGkAtoms::mover_),
     205             :                    "mContent->NodeInfo()->NameAtom() not recognized");
     206           0 :       overscriptFrame = baseFrame->GetNextSibling();
     207             :     }
     208             :   }
     209           0 :   if (underscriptFrame &&
     210           0 :       mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
     211           0 :     overscriptFrame = underscriptFrame->GetNextSibling();
     212             : 
     213             :   }
     214             : 
     215             :   // if our base is an embellished operator, let its state bubble to us (in particular,
     216             :   // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags
     217             :   // are reset to the default values of false if the base frame isn't embellished.
     218           0 :   mPresentationData.baseFrame = baseFrame;
     219           0 :   GetEmbellishDataFrom(baseFrame, mEmbellishData);
     220             : 
     221             :   // The default value of accentunder is false, unless the underscript is embellished
     222             :   // and its core <mo> is an accent
     223           0 :   nsEmbellishData embellishData;
     224           0 :   nsAutoString value;
     225           0 :   if (mContent->IsAnyOfMathMLElements(nsGkAtoms::munder_,
     226             :                                       nsGkAtoms::munderover_)) {
     227           0 :     GetEmbellishDataFrom(underscriptFrame, embellishData);
     228           0 :     if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
     229           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
     230             :     } else {
     231           0 :       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
     232             :     }
     233             : 
     234             :     // if we have an accentunder attribute, it overrides what the underscript said
     235           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accentunder_, value)) {
     236           0 :       if (value.EqualsLiteral("true")) {
     237           0 :         mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
     238           0 :       } else if (value.EqualsLiteral("false")) {
     239           0 :         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
     240             :       }
     241             :     }
     242             :   }
     243             : 
     244             :   // The default value of accent is false, unless the overscript is embellished
     245             :   // and its core <mo> is an accent
     246           0 :   if (mContent->IsAnyOfMathMLElements(nsGkAtoms::mover_,
     247             :                                       nsGkAtoms::munderover_)) {
     248           0 :     GetEmbellishDataFrom(overscriptFrame, embellishData);
     249           0 :     if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
     250           0 :       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
     251             :     } else {
     252           0 :       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
     253             :     }
     254             : 
     255             :     // if we have an accent attribute, it overrides what the overscript said
     256           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value)) {
     257           0 :       if (value.EqualsLiteral("true")) {
     258           0 :         mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
     259           0 :       } else if (value.EqualsLiteral("false")) {
     260           0 :         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
     261             :       }
     262             :     }
     263             :   }
     264             : 
     265             :   bool subsupDisplay =
     266           0 :     NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
     267           0 :     StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE;
     268             : 
     269             :   // disable the stretch-all flag if we are going to act like a superscript
     270           0 :   if (subsupDisplay) {
     271           0 :     mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
     272             :   }
     273             : 
     274             :   // Now transmit any change that we want to our children so that they
     275             :   // can update their mPresentationData structs
     276             :   //---------------------------------------------------------------------
     277             : 
     278             :   /* The REC says:
     279             :      Within underscript, <munderover> always sets displaystyle to "false",
     280             :      but increments scriptlevel by 1 only when accentunder is "false".
     281             : 
     282             :      Within overscript, <munderover> always sets displaystyle to "false",
     283             :      but increments scriptlevel by 1 only when accent is "false".
     284             : 
     285             :      Within subscript and superscript it increments scriptlevel by 1, and
     286             :      sets displaystyle to "false", but leaves both attributes unchanged within
     287             :      base.
     288             : 
     289             :      The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a
     290             :      say it shouldn't be compressed. However, The TeXBook says
     291             :      that math accents and \overline change uncramped styles to their
     292             :      cramped counterparts.
     293             :   */
     294           0 :   if (mContent->IsAnyOfMathMLElements(nsGkAtoms::mover_,
     295             :                                       nsGkAtoms::munderover_)) {
     296           0 :     uint32_t compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)
     297           0 :       ? NS_MATHML_COMPRESSED : 0;
     298           0 :     mIncrementOver =
     299           0 :       !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ||
     300             :       subsupDisplay;
     301           0 :     SetIncrementScriptLevel(
     302           0 :         mContent->IsMathMLElement(nsGkAtoms::mover_) ? 1 : 2, mIncrementOver);
     303           0 :     if (mIncrementOver) {
     304             :       PropagateFrameFlagFor(overscriptFrame,
     305           0 :                             NS_FRAME_MATHML_SCRIPT_DESCENDANT);
     306             :     }
     307           0 :     PropagatePresentationDataFor(overscriptFrame, compress, compress);
     308             :   }
     309             :   /*
     310             :      The TeXBook treats 'under' like a subscript, so p.141 or Rule 13a
     311             :      say it should be compressed
     312             :   */
     313           0 :   if (mContent->IsAnyOfMathMLElements(nsGkAtoms::munder_,
     314             :                                       nsGkAtoms::munderover_)) {
     315           0 :     mIncrementUnder =
     316           0 :       !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags) ||
     317             :       subsupDisplay;
     318           0 :     SetIncrementScriptLevel(1, mIncrementUnder);
     319           0 :     if (mIncrementUnder) {
     320             :       PropagateFrameFlagFor(underscriptFrame,
     321           0 :                             NS_FRAME_MATHML_SCRIPT_DESCENDANT);
     322             :     }
     323             :     PropagatePresentationDataFor(underscriptFrame,
     324             :                                  NS_MATHML_COMPRESSED,
     325           0 :                                  NS_MATHML_COMPRESSED);
     326             :   }
     327             : 
     328             :   /* Set flags for dtls font feature settings.
     329             : 
     330             :      dtls
     331             :      Dotless Forms
     332             :      This feature provides dotless forms for Math Alphanumeric
     333             :      characters, such as U+1D422 MATHEMATICAL BOLD SMALL I,
     334             :      U+1D423 MATHEMATICAL BOLD SMALL J, U+1D456
     335             :      U+MATHEMATICAL ITALIC SMALL I, U+1D457 MATHEMATICAL ITALIC
     336             :      SMALL J, and so on.
     337             :      The dotless forms are to be used as base forms for placing
     338             :      mathematical accents over them.
     339             : 
     340             :      To opt out of this change, add the following to the stylesheet:
     341             :      "font-feature-settings: 'dtls' 0"
     342             :    */
     343           0 :   if (overscriptFrame &&
     344           0 :       NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) &&
     345           0 :       !NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags)) {
     346           0 :     PropagatePresentationDataFor(baseFrame, NS_MATHML_DTLS, NS_MATHML_DTLS);
     347             :   }
     348             : 
     349           0 :   return NS_OK;
     350             : }
     351             : 
     352             : /*
     353             : The REC says:
     354             : *  If the base is an operator with movablelimits="true" (or an embellished
     355             :    operator whose <mo> element core has movablelimits="true"), and
     356             :    displaystyle="false", then underscript and overscript are drawn in
     357             :    a subscript and superscript position, respectively. In this case,
     358             :    the accent and accentunder attributes are ignored. This is often
     359             :    used for limits on symbols such as &sum;.
     360             : 
     361             : i.e.,:
     362             :  if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishDataflags) &&
     363             :      StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
     364             :   // place like subscript-superscript pair
     365             :  }
     366             :  else {
     367             :   // place like underscript-overscript pair
     368             :  }
     369             : */
     370             : 
     371             : /* virtual */ nsresult
     372           0 : nsMathMLmunderoverFrame::Place(DrawTarget*          aDrawTarget,
     373             :                                bool                 aPlaceOrigin,
     374             :                                ReflowOutput& aDesiredSize)
     375             : {
     376           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     377           0 :   if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
     378           0 :       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
     379             :     //place like sub sup or subsup
     380           0 :     if (mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
     381           0 :       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
     382             :                                                           aDrawTarget,
     383             :                                                           aPlaceOrigin,
     384             :                                                           aDesiredSize,
     385             :                                                           this, 0, 0,
     386           0 :                                                           fontSizeInflation);
     387           0 :     } else if (mContent->IsMathMLElement( nsGkAtoms::munder_)) {
     388           0 :       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
     389             :                                                           aDrawTarget,
     390             :                                                           aPlaceOrigin,
     391             :                                                           aDesiredSize,
     392             :                                                           this, 0, 0,
     393           0 :                                                           fontSizeInflation);
     394             :     } else {
     395           0 :       NS_ASSERTION(mContent->IsMathMLElement(nsGkAtoms::mover_),
     396             :                    "mContent->NodeInfo()->NameAtom() not recognized");
     397           0 :       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
     398             :                                                           aDrawTarget,
     399             :                                                           aPlaceOrigin,
     400             :                                                           aDesiredSize,
     401             :                                                           this, 0, 0,
     402           0 :                                                           fontSizeInflation);
     403             :     }
     404             : 
     405             :   }
     406             : 
     407             :   ////////////////////////////////////
     408             :   // Get the children's desired sizes
     409             : 
     410           0 :   nsBoundingMetrics bmBase, bmUnder, bmOver;
     411           0 :   ReflowOutput baseSize(aDesiredSize.GetWritingMode());
     412           0 :   ReflowOutput underSize(aDesiredSize.GetWritingMode());
     413           0 :   ReflowOutput overSize(aDesiredSize.GetWritingMode());
     414           0 :   nsIFrame* overFrame = nullptr;
     415           0 :   nsIFrame* underFrame = nullptr;
     416           0 :   nsIFrame* baseFrame = mFrames.FirstChild();
     417           0 :   underSize.SetBlockStartAscent(0);
     418           0 :   overSize.SetBlockStartAscent(0);
     419           0 :   bool haveError = false;
     420           0 :   if (baseFrame) {
     421           0 :     if (mContent->IsAnyOfMathMLElements(nsGkAtoms::munder_,
     422             :                                         nsGkAtoms::munderover_)) {
     423           0 :       underFrame = baseFrame->GetNextSibling();
     424           0 :     } else if (mContent->IsMathMLElement(nsGkAtoms::mover_)) {
     425           0 :       overFrame = baseFrame->GetNextSibling();
     426             :     }
     427             :   }
     428           0 :   if (underFrame && mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
     429           0 :     overFrame = underFrame->GetNextSibling();
     430             :   }
     431             : 
     432           0 :   if (mContent->IsMathMLElement(nsGkAtoms::munder_)) {
     433           0 :     if (!baseFrame || !underFrame || underFrame->GetNextSibling()) {
     434             :       // report an error, encourage people to get their markups in order
     435           0 :       haveError = true;
     436             :     }
     437             :   }
     438           0 :   if (mContent->IsMathMLElement(nsGkAtoms::mover_)) {
     439           0 :     if (!baseFrame || !overFrame || overFrame->GetNextSibling()) {
     440             :       // report an error, encourage people to get their markups in order
     441           0 :       haveError = true;
     442             :     }
     443             :   }
     444           0 :   if (mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
     445           0 :     if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) {
     446             :       // report an error, encourage people to get their markups in order
     447           0 :       haveError = true;
     448             :     }
     449             :   }
     450           0 :   if (haveError) {
     451           0 :     if (aPlaceOrigin) {
     452           0 :       ReportChildCountError();
     453             :     }
     454           0 :     return ReflowError(aDrawTarget, aDesiredSize);
     455             :   }
     456           0 :   GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
     457           0 :   if (underFrame) {
     458           0 :     GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
     459             :   }
     460           0 :   if (overFrame) {
     461           0 :     GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
     462             :   }
     463             : 
     464           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     465             : 
     466             :   ////////////////////
     467             :   // Place Children
     468             : 
     469             :   RefPtr<nsFontMetrics> fm =
     470           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     471             : 
     472           0 :   nscoord xHeight = fm->XHeight();
     473           0 :   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
     474           0 :   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
     475             : 
     476             :   nscoord ruleThickness;
     477           0 :   GetRuleThickness (aDrawTarget, fm, ruleThickness);
     478             : 
     479           0 :   nscoord correction = 0;
     480           0 :   GetItalicCorrection (bmBase, correction);
     481             : 
     482             :   // there are 2 different types of placement depending on
     483             :   // whether we want an accented under or not
     484             : 
     485           0 :   nscoord underDelta1 = 0; // gap between base and underscript
     486           0 :   nscoord underDelta2 = 0; // extra space beneath underscript
     487             : 
     488           0 :   if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
     489             :     // Rule 13a, App. G, TeXbook
     490             :     nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy;
     491           0 :     GetBigOpSpacings (fm,
     492             :                       dummy, bigOpSpacing2,
     493             :                       dummy, bigOpSpacing4,
     494           0 :                       bigOpSpacing5);
     495           0 :     if (mathFont) {
     496             :       // XXXfredw The Open Type MATH table has some StretchStack* parameters
     497             :       // that we may use when the base is a stretchy horizontal operator. See
     498             :       // bug 963131.
     499           0 :       bigOpSpacing2 =
     500           0 :         mathFont->MathTable()->Constant(gfxMathTable::LowerLimitGapMin,
     501             :                                         oneDevPixel);
     502           0 :       bigOpSpacing4 =
     503           0 :         mathFont->MathTable()->Constant(gfxMathTable::LowerLimitBaselineDropMin,
     504             :                                         oneDevPixel);
     505           0 :       bigOpSpacing5 = 0;
     506             :     }
     507           0 :     underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
     508           0 :     underDelta2 = bigOpSpacing5;
     509             :   }
     510             :   else {
     511             :     // No corresponding rule in TeXbook - we are on our own here
     512             :     // XXX tune the gap delta between base and underscript
     513             :     // XXX Should we use Rule 10 like \underline does?
     514             :     // XXXfredw Perhaps use the Underbar* parameters of the MATH table. See
     515             :     // bug 963125.
     516           0 :     underDelta1 = ruleThickness + onePixel/2;
     517           0 :     underDelta2 = ruleThickness;
     518             :   }
     519             :   // empty under?
     520           0 :   if (!(bmUnder.ascent + bmUnder.descent)) {
     521           0 :     underDelta1 = 0;
     522           0 :     underDelta2 = 0;
     523             :   }
     524             : 
     525           0 :   nscoord overDelta1 = 0; // gap between base and overscript
     526           0 :   nscoord overDelta2 = 0; // extra space above overscript
     527             : 
     528           0 :   if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
     529             :     // Rule 13a, App. G, TeXbook
     530             :     // XXXfredw The Open Type MATH table has some StretchStack* parameters
     531             :     // that we may use when the base is a stretchy horizontal operator. See
     532             :     // bug 963131.
     533             :     nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy;
     534           0 :     GetBigOpSpacings (fm,
     535             :                       bigOpSpacing1, dummy,
     536             :                       bigOpSpacing3, dummy,
     537           0 :                       bigOpSpacing5);
     538           0 :     if (mathFont) {
     539             :       // XXXfredw The Open Type MATH table has some StretchStack* parameters
     540             :       // that we may use when the base is a stretchy horizontal operator. See
     541             :       // bug 963131.
     542           0 :       bigOpSpacing1 =
     543           0 :         mathFont->MathTable()->Constant(gfxMathTable::UpperLimitGapMin,
     544             :                                         oneDevPixel);
     545           0 :       bigOpSpacing3 =
     546           0 :         mathFont->MathTable()->Constant(gfxMathTable::UpperLimitBaselineRiseMin,
     547             :                                         oneDevPixel);
     548           0 :       bigOpSpacing5 = 0;
     549             :     }
     550           0 :     overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
     551           0 :     overDelta2 = bigOpSpacing5;
     552             : 
     553             :     // XXX This is not a TeX rule...
     554             :     // delta1 (as computed abvove) can become really big when bmOver.descent is
     555             :     // negative,  e.g., if the content is &OverBar. In such case, we use the height
     556           0 :     if (bmOver.descent < 0)
     557           0 :       overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
     558             :   }
     559             :   else {
     560             :     // Rule 12, App. G, TeXbook
     561             :     // We are going to modify this rule to make it more general.
     562             :     // The idea behind Rule 12 in the TeXBook is to keep the accent
     563             :     // as close to the base as possible, while ensuring that the
     564             :     // distance between the *baseline* of the accent char and
     565             :     // the *baseline* of the base is atleast x-height.
     566             :     // The idea is that for normal use, we would like all the accents
     567             :     // on a line to line up atleast x-height above the baseline
     568             :     // if possible.
     569             :     // When the ascent of the base is >= x-height,
     570             :     // the baseline of the accent char is placed just above the base
     571             :     // (specifically, the baseline of the accent char is placed
     572             :     // above the baseline of the base by the ascent of the base).
     573             :     // For ease of implementation,
     574             :     // this assumes that the font-designer designs accents
     575             :     // in such a way that the bottom of the accent is atleast x-height
     576             :     // above its baseline, otherwise there will be collisions
     577             :     // with the base. Also there should be proper padding between
     578             :     // the bottom of the accent char and its baseline.
     579             :     // The above rule may not be obvious from a first
     580             :     // reading of rule 12 in the TeXBook !!!
     581             :     // The mathml <mover> tag can use accent chars that
     582             :     // do not follow this convention. So we modify TeX's rule
     583             :     // so that TeX's rule gets subsumed for accents that follow
     584             :     // TeX's convention,
     585             :     // while also allowing accents that do not follow the convention :
     586             :     // we try to keep the *bottom* of the accent char atleast x-height
     587             :     // from the baseline of the base char. we also slap on an extra
     588             :     // padding between the accent and base chars.
     589           0 :     overDelta1 = ruleThickness + onePixel/2;
     590           0 :     nscoord accentBaseHeight = xHeight;
     591           0 :     if (mathFont) {
     592             :       accentBaseHeight =
     593           0 :         mathFont->MathTable()->Constant(gfxMathTable::AccentBaseHeight,
     594           0 :                                         oneDevPixel);
     595             :     }
     596           0 :     if (bmBase.ascent < accentBaseHeight) {
     597             :       // also ensure at least accentBaseHeight above the baseline of the base
     598           0 :       overDelta1 += accentBaseHeight - bmBase.ascent;
     599             :     }
     600           0 :     overDelta2 = ruleThickness;
     601             :   }
     602             :   // empty over?
     603           0 :   if (!(bmOver.ascent + bmOver.descent)) {
     604           0 :     overDelta1 = 0;
     605           0 :     overDelta2 = 0;
     606             :   }
     607             : 
     608           0 :   nscoord dxBase = 0, dxOver = 0, dxUnder = 0;
     609           0 :   nsAutoString valueAlign;
     610             :   enum {
     611             :     center,
     612             :     left,
     613             :     right
     614           0 :   } alignPosition = center;
     615             : 
     616           0 :   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, valueAlign)) {
     617           0 :     if (valueAlign.EqualsLiteral("left")) {
     618           0 :       alignPosition = left;
     619           0 :     } else if (valueAlign.EqualsLiteral("right")) {
     620           0 :       alignPosition = right;
     621             :     }
     622             :   }
     623             : 
     624             :   //////////
     625             :   // pass 1, do what <mover> does: attach the overscript on the base
     626             : 
     627             :   // Ad-hoc - This is to override fonts which have ready-made _accent_
     628             :   // glyphs with negative lbearing and rbearing. We want to position
     629             :   // the overscript ourselves
     630           0 :   nscoord overWidth = bmOver.width;
     631           0 :   if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) {
     632           0 :     overWidth = bmOver.rightBearing - bmOver.leftBearing;
     633           0 :     dxOver = -bmOver.leftBearing;
     634             :   }
     635             : 
     636           0 :   if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
     637           0 :     mBoundingMetrics.width = bmBase.width;
     638           0 :     if (alignPosition == center) {
     639           0 :       dxOver += correction;
     640             :     }
     641             :   }
     642             :   else {
     643           0 :     mBoundingMetrics.width = std::max(bmBase.width, overWidth);
     644           0 :     if (alignPosition == center) {
     645           0 :       dxOver += correction/2;
     646             :     }
     647             :   }
     648             : 
     649           0 :   if (alignPosition == center) {
     650           0 :     dxOver += (mBoundingMetrics.width - overWidth)/2;
     651           0 :     dxBase = (mBoundingMetrics.width - bmBase.width)/2;
     652           0 :   } else if (alignPosition == right) {
     653           0 :     dxOver += mBoundingMetrics.width - overWidth;
     654           0 :     dxBase = mBoundingMetrics.width - bmBase.width;
     655             :   }
     656             : 
     657           0 :   mBoundingMetrics.ascent =
     658           0 :     bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent;
     659           0 :   mBoundingMetrics.descent = bmBase.descent;
     660           0 :   mBoundingMetrics.leftBearing =
     661           0 :     std::min(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
     662           0 :   mBoundingMetrics.rightBearing =
     663           0 :     std::max(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
     664             : 
     665             :   //////////
     666             :   // pass 2, do what <munder> does: attach the underscript on the previous
     667             :   // result. We conceptually view the previous result as an "anynomous base"
     668             :   // from where to attach the underscript. Hence if the underscript is empty,
     669             :   // we should end up like <mover>. If the overscript is empty, we should
     670             :   // end up like <munder>.
     671             : 
     672           0 :   nsBoundingMetrics bmAnonymousBase = mBoundingMetrics;
     673             :   nscoord ascentAnonymousBase =
     674           0 :     std::max(mBoundingMetrics.ascent + overDelta2,
     675           0 :              overSize.BlockStartAscent() + bmOver.descent +
     676           0 :              overDelta1 + bmBase.ascent);
     677           0 :   ascentAnonymousBase = std::max(ascentAnonymousBase,
     678           0 :                                  baseSize.BlockStartAscent());
     679             : 
     680             :   // Width of non-spacing marks is zero so use left and right bearing.
     681           0 :   nscoord underWidth = bmUnder.width;
     682           0 :   if (!underWidth) {
     683           0 :     underWidth = bmUnder.rightBearing - bmUnder.leftBearing;
     684           0 :     dxUnder = -bmUnder.leftBearing;
     685             :   }
     686             : 
     687           0 :   nscoord maxWidth = std::max(bmAnonymousBase.width, underWidth);
     688           0 :   if (alignPosition == center &&
     689           0 :       !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
     690           0 :     GetItalicCorrection(bmAnonymousBase, correction);
     691           0 :     dxUnder += -correction/2;
     692             :   }
     693           0 :   nscoord dxAnonymousBase = 0;
     694           0 :   if (alignPosition == center) {
     695           0 :     dxUnder += (maxWidth - underWidth)/2;
     696           0 :     dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2;
     697           0 :   } else if (alignPosition == right) {
     698           0 :     dxUnder += maxWidth - underWidth;
     699           0 :     dxAnonymousBase = maxWidth - bmAnonymousBase.width;
     700             :   }
     701             : 
     702             :   // adjust the offsets of the real base and overscript since their
     703             :   // final offsets should be relative to us...
     704           0 :   dxOver += dxAnonymousBase;
     705           0 :   dxBase += dxAnonymousBase;
     706             : 
     707           0 :   mBoundingMetrics.width =
     708           0 :     std::max(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width);
     709             :   // At this point, mBoundingMetrics.ascent = bmAnonymousBase.ascent
     710           0 :   mBoundingMetrics.descent =
     711           0 :     bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent;
     712           0 :   mBoundingMetrics.leftBearing =
     713           0 :     std::min(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing);
     714           0 :   mBoundingMetrics.rightBearing =
     715           0 :     std::max(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing);
     716             : 
     717           0 :   aDesiredSize.SetBlockStartAscent(ascentAnonymousBase);
     718           0 :   aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     719           0 :     std::max(mBoundingMetrics.descent + underDelta2,
     720           0 :            bmAnonymousBase.descent + underDelta1 + bmUnder.ascent +
     721           0 :              underSize.Height() - underSize.BlockStartAscent());
     722           0 :   aDesiredSize.Height() = std::max(aDesiredSize.Height(),
     723           0 :                                aDesiredSize.BlockStartAscent() +
     724           0 :                                baseSize.Height() - baseSize.BlockStartAscent());
     725           0 :   aDesiredSize.Width() = mBoundingMetrics.width;
     726           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     727             : 
     728           0 :   mReference.x = 0;
     729           0 :   mReference.y = aDesiredSize.BlockStartAscent();
     730             : 
     731           0 :   if (aPlaceOrigin) {
     732             :     nscoord dy;
     733             :     // place overscript
     734           0 :     if (overFrame) {
     735           0 :       dy = aDesiredSize.BlockStartAscent() -
     736           0 :            mBoundingMetrics.ascent + bmOver.ascent -
     737           0 :            overSize.BlockStartAscent();
     738           0 :       FinishReflowChild (overFrame, PresContext(), overSize, nullptr, dxOver, dy, 0);
     739             :     }
     740             :     // place base
     741           0 :     dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
     742           0 :     FinishReflowChild (baseFrame, PresContext(), baseSize, nullptr, dxBase, dy, 0);
     743             :     // place underscript
     744           0 :     if (underFrame) {
     745           0 :       dy = aDesiredSize.BlockStartAscent() +
     746           0 :            mBoundingMetrics.descent - bmUnder.descent -
     747           0 :            underSize.BlockStartAscent();
     748           0 :       FinishReflowChild (underFrame, PresContext(), underSize, nullptr,
     749           0 :                          dxUnder, dy, 0);
     750             :     }
     751             :   }
     752           0 :   return NS_OK;
     753             : }

Generated by: LCOV version 1.13