LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmmultiscriptsFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 354 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 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             : 
       7             : #include "nsMathMLmmultiscriptsFrame.h"
       8             : #include "nsPresContext.h"
       9             : #include <algorithm>
      10             : #include "gfxContext.h"
      11             : #include "gfxMathTable.h"
      12             : 
      13             : using mozilla::WritingMode;
      14             : 
      15             : //
      16             : // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
      17             : // <msub> -- attach a subscript to a base - implementation
      18             : // <msubsup> -- attach a subscript-superscript pair to a base - implementation
      19             : // <msup> -- attach a superscript to a base - implementation
      20             : //
      21             : 
      22             : nsIFrame*
      23           0 : NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      24             : {
      25           0 :   return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext);
      26             : }
      27             : 
      28           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame)
      29             : 
      30           0 : nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
      31             : {
      32           0 : }
      33             : 
      34             : uint8_t
      35           0 : nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame)
      36             : {
      37           0 :   if (!aFrame)
      38           0 :     return 0;
      39           0 :   if (mFrames.ContainsFrame(aFrame)) {
      40           0 :     if (mFrames.FirstChild() == aFrame ||
      41           0 :         aFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
      42           0 :       return 0; // No script increment for base frames or prescript markers
      43             :     }
      44           0 :     return 1;
      45             :   }
      46           0 :   return 0; //not a child
      47             : }
      48             : 
      49             : NS_IMETHODIMP
      50           0 : nsMathMLmmultiscriptsFrame::TransmitAutomaticData()
      51             : {
      52             :   // if our base is an embellished operator, let its state bubble to us
      53           0 :   mPresentationData.baseFrame = mFrames.FirstChild();
      54           0 :   GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
      55             : 
      56             :   // The TeXbook (Ch 17. p.141) says the superscript inherits the compression
      57             :   // while the subscript is compressed. So here we collect subscripts and set
      58             :   // the compression flag in them.
      59             : 
      60           0 :   int32_t count = 0;
      61           0 :   bool isSubScript = !mContent->IsMathMLElement(nsGkAtoms::msup_);
      62             : 
      63           0 :   AutoTArray<nsIFrame*, 8> subScriptFrames;
      64           0 :   nsIFrame* childFrame = mFrames.FirstChild();
      65           0 :   while (childFrame) {
      66           0 :     if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
      67             :       // mprescripts frame
      68           0 :     } else if (0 == count) {
      69             :       // base frame
      70             :     } else {
      71             :       // super/subscript block
      72           0 :       if (isSubScript) {
      73             :         // subscript
      74           0 :         subScriptFrames.AppendElement(childFrame);
      75             :       } else {
      76             :         // superscript
      77             :       }
      78           0 :       PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT);
      79           0 :       isSubScript = !isSubScript;
      80             :     }
      81           0 :     count++;
      82           0 :     childFrame = childFrame->GetNextSibling();
      83             :   }
      84           0 :   for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) {
      85           0 :     childFrame = subScriptFrames[i];
      86             :     PropagatePresentationDataFor(childFrame,
      87           0 :       NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED);
      88             :   }
      89             : 
      90           0 :   return NS_OK;
      91             : }
      92             : 
      93             : /* virtual */ nsresult
      94           0 : nsMathMLmmultiscriptsFrame::Place(DrawTarget*          aDrawTarget,
      95             :                                   bool                 aPlaceOrigin,
      96             :                                   ReflowOutput& aDesiredSize)
      97             : {
      98           0 :   nscoord subScriptShift = 0;
      99           0 :   nscoord supScriptShift = 0;
     100           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     101             : 
     102             :   // subscriptshift
     103             :   //
     104             :   // "Specifies the minimum amount to shift the baseline of subscript down; the
     105             :   // default is for the rendering agent to use its own positioning rules."
     106             :   //
     107             :   // values: length
     108             :   // default: automatic
     109             :   //
     110             :   // We use 0 as the default value so unitless values can be ignored.
     111             :   // As a minimum, negative values can be ignored.
     112             :   //
     113           0 :   nsAutoString value;
     114           0 :   if (!mContent->IsMathMLElement(nsGkAtoms::msup_)) {
     115           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value);
     116           0 :     if (!value.IsEmpty()) {
     117           0 :       ParseNumericValue(value, &subScriptShift, 0, PresContext(),
     118           0 :                         mStyleContext, fontSizeInflation);
     119             :     }
     120             :   }
     121             :   // superscriptshift
     122             :   //
     123             :   // "Specifies the minimum amount to shift the baseline of superscript up; the
     124             :   // default is for the rendering agent to use its own positioning rules."
     125             :   //
     126             :   // values: length
     127             :   // default: automatic
     128             :   //
     129             :   // We use 0 as the default value so unitless values can be ignored.
     130             :   // As a minimum, negative values can be ignored.
     131             :   //
     132           0 :   if (!mContent->IsMathMLElement(nsGkAtoms::msub_)) {
     133           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value);
     134           0 :     if (!value.IsEmpty()) {
     135           0 :       ParseNumericValue(value, &supScriptShift, 0, PresContext(),
     136           0 :                         mStyleContext, fontSizeInflation);
     137             :     }
     138             :   }
     139           0 :   return PlaceMultiScript(PresContext(), aDrawTarget, aPlaceOrigin,
     140             :                           aDesiredSize, this, subScriptShift, supScriptShift,
     141           0 :                           fontSizeInflation);
     142             : }
     143             : 
     144             : // exported routine that both munderover and mmultiscripts share.
     145             : // munderover uses this when movablelimits is set.
     146             : nsresult
     147           0 : nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext*  aPresContext,
     148             :                                         DrawTarget*          aDrawTarget,
     149             :                                         bool                 aPlaceOrigin,
     150             :                                         ReflowOutput& aDesiredSize,
     151             :                                         nsMathMLContainerFrame* aFrame,
     152             :                                         nscoord              aUserSubScriptShift,
     153             :                                         nscoord              aUserSupScriptShift,
     154             :                                         float                aFontSizeInflation)
     155             : {
     156           0 :   nsIAtom* tag = aFrame->GetContent()->NodeInfo()->NameAtom();
     157             : 
     158             :   // This function deals with both munderover etc. as well as msubsup etc.
     159             :   // As the former behaves identically to the later, we treat it as such
     160             :   // to avoid additional checks later.
     161           0 :   if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::mover_))
     162           0 :     tag = nsGkAtoms::msup_;
     163           0 :   else if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::munder_))
     164           0 :     tag = nsGkAtoms::msub_;
     165           0 :   else if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::munderover_))
     166           0 :     tag = nsGkAtoms::msubsup_;
     167             : 
     168           0 :   nsBoundingMetrics bmFrame;
     169             : 
     170             :   nscoord minShiftFromXHeight, subDrop, supDrop;
     171             : 
     172             :   ////////////////////////////////////////
     173             :   // Initialize super/sub shifts that
     174             :   // depend only on the current font
     175             :   ////////////////////////////////////////
     176             : 
     177           0 :   nsIFrame* baseFrame = aFrame->PrincipalChildList().FirstChild();
     178             : 
     179           0 :   if (!baseFrame) {
     180           0 :     if (tag == nsGkAtoms::mmultiscripts_)
     181           0 :       aFrame->ReportErrorToConsole("NoBase");
     182             :     else
     183           0 :       aFrame->ReportChildCountError();
     184           0 :     return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     185             :   }
     186             : 
     187             :   // get x-height (an ex)
     188           0 :   const nsStyleFont* font = aFrame->StyleFont();
     189             :   RefPtr<nsFontMetrics> fm =
     190           0 :     nsLayoutUtils::GetFontMetricsForFrame(baseFrame, aFontSizeInflation);
     191             : 
     192           0 :   nscoord xHeight = fm->XHeight();
     193             : 
     194           0 :   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
     195           0 :   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
     196             :   // scriptspace from TeX for extra spacing after sup/subscript
     197             :   nscoord scriptSpace;
     198           0 :   if (mathFont) {
     199           0 :     scriptSpace = mathFont->MathTable()->
     200           0 :       Constant(gfxMathTable::SpaceAfterScript, oneDevPixel);
     201             :   } else {
     202             :     // (0.5pt in plain TeX)
     203           0 :     scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
     204             :   }
     205             : 
     206             :   // Try and read sub and sup drops from the MATH table.
     207           0 :   if (mathFont) {
     208           0 :     subDrop = mathFont->MathTable()->
     209           0 :       Constant(gfxMathTable::SubscriptBaselineDropMin, oneDevPixel);
     210           0 :     supDrop = mathFont->MathTable()->
     211           0 :       Constant(gfxMathTable::SuperscriptBaselineDropMax, oneDevPixel);
     212             :   }
     213             : 
     214             :   // force the scriptSpace to be at least 1 pixel
     215           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     216           0 :   scriptSpace = std::max(onePixel, scriptSpace);
     217             : 
     218             :   /////////////////////////////////////
     219             :   // first the shift for the subscript
     220             : 
     221             :   nscoord subScriptShift;
     222           0 :   if (mathFont) {
     223             :     // Try and get the sub script shift from the MATH table. Note that contrary
     224             :     // to TeX we only have one parameter.
     225           0 :     subScriptShift = mathFont->MathTable()->
     226           0 :       Constant(gfxMathTable::SubscriptShiftDown, oneDevPixel);
     227             :   } else {
     228             :     // subScriptShift{1,2}
     229             :     // = minimum amount to shift the subscript down
     230             :     // = sub{1,2} in TeXbook
     231             :     // subScriptShift1 = subscriptshift attribute * x-height
     232             :     nscoord subScriptShift1, subScriptShift2;
     233             :     // Get subScriptShift{1,2} default from font
     234           0 :     GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
     235           0 :     if (tag == nsGkAtoms::msub_) {
     236           0 :       subScriptShift = subScriptShift1;
     237             :     } else {
     238           0 :       subScriptShift = std::max(subScriptShift1, subScriptShift2);
     239             :     }
     240             :   }
     241             : 
     242           0 :   if (0 < aUserSubScriptShift) {
     243             :     // the user has set the subscriptshift attribute
     244           0 :     subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
     245             :   }
     246             : 
     247             :   /////////////////////////////////////
     248             :   // next the shift for the superscript
     249             : 
     250             :   nscoord supScriptShift;
     251           0 :   nsPresentationData presentationData;
     252           0 :   aFrame->GetPresentationData(presentationData);
     253           0 :   if (mathFont) {
     254             :     // Try and get the super script shift from the MATH table. Note that
     255             :     // contrary to TeX we only have two parameters.
     256           0 :     supScriptShift = mathFont->
     257           0 :       MathTable()->Constant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
     258             :                             gfxMathTable::SuperscriptShiftUpCramped :
     259             :                             gfxMathTable::SuperscriptShiftUp,
     260             :                             oneDevPixel);
     261             :   } else {
     262             :     // supScriptShift{1,2,3}
     263             :     // = minimum amount to shift the supscript up
     264             :     // = sup{1,2,3} in TeX
     265             :     // supScriptShift1 = superscriptshift attribute * x-height
     266             :     // Note that there are THREE values for supscript shifts depending
     267             :     // on the current style
     268             :     nscoord supScriptShift1, supScriptShift2, supScriptShift3;
     269             :     // Set supScriptShift{1,2,3} default from font
     270           0 :     GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
     271             : 
     272             :     // get sup script shift depending on current script level and display style
     273             :     // Rule 18c, App. G, TeXbook
     274           0 :     if (font->mScriptLevel == 0 &&
     275           0 :         font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
     276           0 :         !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
     277             :       // Style D in TeXbook
     278           0 :       supScriptShift = supScriptShift1;
     279           0 :     } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
     280             :       // Style C' in TeXbook = D',T',S',SS'
     281           0 :       supScriptShift = supScriptShift3;
     282             :     } else {
     283             :       // everything else = T,S,SS
     284           0 :       supScriptShift = supScriptShift2;
     285             :     }
     286             :   }
     287             : 
     288           0 :   if (0 < aUserSupScriptShift) {
     289             :     // the user has set the supscriptshift attribute
     290           0 :     supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
     291             :   }
     292             : 
     293             :   ////////////////////////////////////
     294             :   // Get the children's sizes
     295             :   ////////////////////////////////////
     296             : 
     297           0 :   const WritingMode wm(aDesiredSize.GetWritingMode());
     298           0 :   nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
     299           0 :   nscoord minSubScriptShift = 0, minSupScriptShift = 0;
     300           0 :   nscoord trySubScriptShift = subScriptShift;
     301           0 :   nscoord trySupScriptShift = supScriptShift;
     302           0 :   nscoord maxSubScriptShift = subScriptShift;
     303           0 :   nscoord maxSupScriptShift = supScriptShift;
     304           0 :   ReflowOutput baseSize(wm);
     305           0 :   ReflowOutput subScriptSize(wm);
     306           0 :   ReflowOutput supScriptSize(wm);
     307           0 :   ReflowOutput multiSubSize(wm), multiSupSize(wm);
     308           0 :   baseFrame = nullptr;
     309           0 :   nsIFrame* subScriptFrame = nullptr;
     310           0 :   nsIFrame* supScriptFrame = nullptr;
     311           0 :   nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
     312             : 
     313           0 :   bool firstPrescriptsPair = false;
     314           0 :   nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
     315           0 :   multiSubSize.SetBlockStartAscent(-0x7FFFFFFF);
     316           0 :   multiSupSize.SetBlockStartAscent(-0x7FFFFFFF);
     317           0 :   bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
     318           0 :   bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
     319           0 :   nscoord italicCorrection = 0;
     320             : 
     321           0 :   nsBoundingMetrics boundingMetrics;
     322           0 :   boundingMetrics.width = 0;
     323           0 :   boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
     324           0 :   aDesiredSize.Width() = aDesiredSize.Height() = 0;
     325             : 
     326           0 :   int32_t count = 0;
     327           0 :   bool foundNoneTag = false;
     328             : 
     329             :   // Boolean to determine whether the current child is a subscript.
     330             :   // Note that only msup starts with a superscript.
     331           0 :   bool isSubScript = (tag != nsGkAtoms::msup_);
     332             : 
     333           0 :   nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
     334           0 :   while (childFrame) {
     335           0 :     if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
     336           0 :       if (tag != nsGkAtoms::mmultiscripts_) {
     337           0 :         if (aPlaceOrigin) {
     338           0 :           aFrame->ReportInvalidChildError(nsGkAtoms::mprescripts_);
     339             :         }
     340           0 :         return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     341             :       }
     342           0 :       if (prescriptsFrame) {
     343             :         // duplicate <mprescripts/> found
     344             :         // report an error, encourage people to get their markups in order
     345           0 :         if (aPlaceOrigin) {
     346           0 :           aFrame->ReportErrorToConsole("DuplicateMprescripts");
     347             :         }
     348           0 :         return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     349             :       }
     350           0 :       if (!isSubScript) {
     351           0 :         if (aPlaceOrigin) {
     352           0 :           aFrame->ReportErrorToConsole("SubSupMismatch");
     353             :         }
     354           0 :         return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     355             :       }
     356             : 
     357           0 :       prescriptsFrame = childFrame;
     358           0 :       firstPrescriptsPair = true;
     359           0 :     } else if (0 == count) {
     360             :       // base
     361             : 
     362           0 :       if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::none)) {
     363           0 :         if (tag == nsGkAtoms::mmultiscripts_) {
     364           0 :           if (aPlaceOrigin) {
     365           0 :             aFrame->ReportErrorToConsole("NoBase");
     366             :           }
     367           0 :           return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     368             :         } else {
     369             :           //A different error message is triggered later for the other tags
     370           0 :           foundNoneTag = true;
     371             :         }
     372             :       }
     373           0 :       baseFrame = childFrame;
     374           0 :       GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
     375             : 
     376           0 :       if (tag != nsGkAtoms::msub_) {
     377             :         // Apply italics correction if there is the potential for a
     378             :         // postsupscript.
     379           0 :         GetItalicCorrection(bmBase, italicCorrection);
     380             :         // If italics correction is applied, we always add "a little to spare"
     381             :         // (see TeXbook Ch.11, p.64), as we estimate the italic creation
     382             :         // ourselves and it isn't the same as TeX.
     383           0 :         italicCorrection += onePixel;
     384             :       }
     385             : 
     386             :       // we update boundingMetrics.{ascent,descent} with that
     387             :       // of the baseFrame only after processing all the sup/sub pairs
     388           0 :       boundingMetrics.width = bmBase.width;
     389           0 :       boundingMetrics.rightBearing = bmBase.rightBearing;
     390           0 :       boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
     391             :     } else {
     392             :       // super/subscript block
     393           0 :       if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::none)) {
     394           0 :         foundNoneTag = true;
     395             :       }
     396             : 
     397           0 :       if (isSubScript) {
     398             :         // subscript
     399           0 :         subScriptFrame = childFrame;
     400           0 :         GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
     401           0 :         if (!mathFont) {
     402             :           // get the subdrop from the subscript font
     403           0 :           GetSubDropFromChild (subScriptFrame, subDrop, aFontSizeInflation);
     404             :         }
     405             : 
     406             :         // parameter v, Rule 18a, App. G, TeXbook
     407           0 :         minSubScriptShift = bmBase.descent + subDrop;
     408           0 :         trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
     409           0 :         multiSubSize.SetBlockStartAscent(
     410           0 :            std::max(multiSubSize.BlockStartAscent(),
     411           0 :                     subScriptSize.BlockStartAscent()));
     412           0 :         bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
     413           0 :         bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
     414           0 :         multiSubSize.Height() =
     415           0 :           std::max(multiSubSize.Height(),
     416           0 :                    subScriptSize.Height() - subScriptSize.BlockStartAscent());
     417           0 :         if (bmSubScript.width)
     418           0 :           width = bmSubScript.width + scriptSpace;
     419           0 :         rightBearing = bmSubScript.rightBearing;
     420             : 
     421           0 :         if (tag == nsGkAtoms::msub_) {
     422           0 :           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
     423           0 :           boundingMetrics.width += width;
     424             : 
     425             :           nscoord subscriptTopMax;
     426           0 :           if (mathFont) {
     427             :             subscriptTopMax =
     428           0 :               mathFont->MathTable()->Constant(gfxMathTable::SubscriptTopMax,
     429           0 :                                               oneDevPixel);
     430             :           } else {
     431             :             // get min subscript shift limit from x-height
     432             :             // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
     433           0 :             subscriptTopMax = NSToCoordRound((4.0f/5.0f) * xHeight);
     434             :           }
     435           0 :           nscoord minShiftFromXHeight = bmSubScript.ascent - subscriptTopMax;
     436           0 :           maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
     437             : 
     438           0 :           maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
     439           0 :           trySubScriptShift = subScriptShift;
     440             :         }
     441             :       } else {
     442             :         // supscript
     443           0 :         supScriptFrame = childFrame;
     444           0 :         GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
     445           0 :         if (!mathFont) {
     446             :           // get the supdrop from the supscript font
     447           0 :           GetSupDropFromChild (supScriptFrame, supDrop, aFontSizeInflation);
     448             :         }
     449             :         // parameter u, Rule 18a, App. G, TeXbook
     450           0 :         minSupScriptShift = bmBase.ascent - supDrop;
     451             :         nscoord superscriptBottomMin;
     452           0 :         if (mathFont) {
     453             :           superscriptBottomMin =
     454           0 :             mathFont->MathTable()->Constant(gfxMathTable::SuperscriptBottomMin,
     455           0 :                                             oneDevPixel);
     456             :         } else {
     457             :           // get min supscript shift limit from x-height
     458             :           // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
     459           0 :           superscriptBottomMin = NSToCoordRound((1.0f / 4.0f) * xHeight);
     460             :         }
     461           0 :         minShiftFromXHeight = bmSupScript.descent + superscriptBottomMin;
     462           0 :         trySupScriptShift = std::max(minSupScriptShift,
     463             :                                      std::max(minShiftFromXHeight,
     464           0 :                                               supScriptShift));
     465           0 :         multiSupSize.SetBlockStartAscent(
     466           0 :           std::max(multiSupSize.BlockStartAscent(),
     467           0 :                    supScriptSize.BlockStartAscent()));
     468           0 :         bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
     469           0 :         bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
     470           0 :         multiSupSize.Height() =
     471           0 :           std::max(multiSupSize.Height(),
     472           0 :                    supScriptSize.Height() - supScriptSize.BlockStartAscent());
     473             : 
     474           0 :         if (bmSupScript.width)
     475           0 :           width = std::max(width, bmSupScript.width + scriptSpace);
     476             : 
     477           0 :         if (!prescriptsFrame) { // we are still looping over base & postscripts
     478           0 :           rightBearing = std::max(rightBearing,
     479           0 :                                   italicCorrection + bmSupScript.rightBearing);
     480           0 :           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
     481           0 :           boundingMetrics.width += width;
     482             :         } else {
     483           0 :           prescriptsWidth += width;
     484           0 :           if (firstPrescriptsPair) {
     485           0 :             firstPrescriptsPair = false;
     486           0 :             boundingMetrics.leftBearing =
     487           0 :               std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
     488             :           }
     489             :         }
     490           0 :         width = rightBearing = 0;
     491             : 
     492             :         // negotiate between the various shifts so that
     493             :         // there is enough gap between the sup and subscripts
     494             :         // Rule 18e, App. G, TeXbook
     495           0 :         if (tag == nsGkAtoms::mmultiscripts_ ||
     496           0 :             tag == nsGkAtoms::msubsup_) {
     497             :           nscoord subSuperscriptGapMin;
     498           0 :           if (mathFont) {
     499             :             subSuperscriptGapMin = mathFont->MathTable()->
     500           0 :               Constant(gfxMathTable::SubSuperscriptGapMin, oneDevPixel);
     501             :           } else {
     502             :             nscoord ruleSize;
     503           0 :             GetRuleThickness(aDrawTarget, fm, ruleSize);
     504           0 :             subSuperscriptGapMin = 4 * ruleSize;
     505             :           }
     506             :           nscoord gap =
     507           0 :             (trySupScriptShift - bmSupScript.descent) -
     508           0 :             (bmSubScript.ascent - trySubScriptShift);
     509           0 :           if (gap < subSuperscriptGapMin) {
     510             :             // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
     511           0 :             trySubScriptShift += subSuperscriptGapMin - gap;
     512             :           }
     513             : 
     514             :           // next we want to ensure that the bottom of the superscript
     515             :           // will be > superscriptBottomMaxWithSubscript
     516             :           nscoord superscriptBottomMaxWithSubscript;
     517           0 :           if (mathFont) {
     518             :             superscriptBottomMaxWithSubscript = mathFont->MathTable()->
     519           0 :               Constant(gfxMathTable::SuperscriptBottomMaxWithSubscript,
     520           0 :                        oneDevPixel);
     521             :           } else {
     522             :             superscriptBottomMaxWithSubscript =
     523           0 :               NSToCoordRound((4.0f / 5.0f) * xHeight);
     524             :           }
     525           0 :           gap = superscriptBottomMaxWithSubscript -
     526           0 :             (trySupScriptShift - bmSupScript.descent);
     527           0 :           if (gap > 0) {
     528           0 :             trySupScriptShift += gap;
     529           0 :             trySubScriptShift -= gap;
     530             :           }
     531             :         }
     532             : 
     533           0 :         maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
     534           0 :         maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
     535             : 
     536           0 :         trySubScriptShift = subScriptShift;
     537           0 :         trySupScriptShift = supScriptShift;
     538             :       }
     539             : 
     540           0 :       isSubScript = !isSubScript;
     541             :     }
     542           0 :     count++;
     543           0 :     childFrame = childFrame->GetNextSibling();
     544             :   }
     545             : 
     546             :   //NoBase error may also have been reported above
     547           0 :   if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) ||
     548           0 :       (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame ||
     549           0 :       (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
     550           0 :       (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
     551             :     // report an error, encourage people to get their markups in order
     552           0 :     if (aPlaceOrigin) {
     553           0 :       if ((count != 2 && (tag == nsGkAtoms::msup_ ||
     554           0 :           tag == nsGkAtoms::msub_)) ||
     555           0 :           (count != 3 && tag == nsGkAtoms::msubsup_ )) {
     556           0 :         aFrame->ReportChildCountError();
     557           0 :       } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
     558           0 :         aFrame->ReportInvalidChildError(nsGkAtoms::none);
     559           0 :       } else if (!baseFrame) {
     560           0 :         aFrame->ReportErrorToConsole("NoBase");
     561             :       } else {
     562           0 :         aFrame->ReportErrorToConsole("SubSupMismatch");
     563             :       }
     564             :     }
     565           0 :     return aFrame->ReflowError(aDrawTarget, aDesiredSize);
     566             :   }
     567             : 
     568             :   // we left out the width of prescripts, so ...
     569           0 :   boundingMetrics.rightBearing += prescriptsWidth;
     570           0 :   boundingMetrics.width += prescriptsWidth;
     571             : 
     572             :   // Zero out the shifts in where a frame isn't present to avoid the potential
     573             :   // for overflow.
     574           0 :   if (!subScriptFrame)
     575           0 :     maxSubScriptShift = 0;
     576           0 :   if (!supScriptFrame)
     577           0 :     maxSupScriptShift = 0;
     578             : 
     579             :   // we left out the base during our bounding box updates, so ...
     580           0 :   if (tag == nsGkAtoms::msub_) {
     581           0 :     boundingMetrics.ascent = std::max(bmBase.ascent,
     582           0 :                                       bmMultiSub.ascent - maxSubScriptShift);
     583             :   } else {
     584           0 :     boundingMetrics.ascent =
     585           0 :       std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
     586             :   }
     587           0 :   if (tag == nsGkAtoms::msup_) {
     588           0 :     boundingMetrics.descent = std::max(bmBase.descent,
     589           0 :                                        bmMultiSup.descent - maxSupScriptShift);
     590             :   } else {
     591           0 :     boundingMetrics.descent =
     592           0 :       std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
     593             :   }
     594           0 :   aFrame->SetBoundingMetrics(boundingMetrics);
     595             : 
     596             :   // get the reflow metrics ...
     597           0 :   aDesiredSize.SetBlockStartAscent(
     598           0 :     std::max(baseSize.BlockStartAscent(),
     599           0 :              std::max(multiSubSize.BlockStartAscent() - maxSubScriptShift,
     600           0 :                       multiSupSize.BlockStartAscent() + maxSupScriptShift)));
     601           0 :   aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     602           0 :     std::max(baseSize.Height() - baseSize.BlockStartAscent(),
     603           0 :              std::max(multiSubSize.Height() + maxSubScriptShift,
     604           0 :                       multiSupSize.Height() - maxSupScriptShift));
     605           0 :   aDesiredSize.Width() = boundingMetrics.width;
     606           0 :   aDesiredSize.mBoundingMetrics = boundingMetrics;
     607             : 
     608           0 :   aFrame->SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
     609             : 
     610             :   //////////////////
     611             :   // Place Children
     612             : 
     613             :   // Place prescripts, followed by base, and then postscripts.
     614             :   // The list of frames is in the order: {base} {postscripts} {prescripts}
     615             :   // We go over the list in a circular manner, starting at <prescripts/>
     616             : 
     617           0 :   if (aPlaceOrigin) {
     618           0 :     nscoord dx = 0, dy = 0;
     619             : 
     620             :     // With msub and msup there is only one element and
     621             :     // subscriptFrame/supScriptFrame have already been set above where
     622             :     // relevant.  In these cases we skip to the reflow part.
     623           0 :     if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
     624           0 :       count = 1;
     625             :     else
     626           0 :       count = 0;
     627           0 :     childFrame = prescriptsFrame;
     628           0 :     bool isPreScript = true;
     629           0 :     do {
     630           0 :       if (!childFrame) { // end of prescripts,
     631           0 :         isPreScript = false;
     632             :         // place the base ...
     633           0 :         childFrame = baseFrame;
     634           0 :         dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
     635           0 :         FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
     636           0 :                            aFrame->MirrorIfRTL(aDesiredSize.Width(),
     637           0 :                                                baseSize.Width(),
     638             :                                                dx),
     639           0 :                            dy, 0);
     640           0 :         dx += bmBase.width;
     641           0 :       } else if (prescriptsFrame == childFrame) {
     642             :         // Clear reflow flags of prescripts frame.
     643           0 :         prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
     644             :       } else {
     645             :         // process each sup/sub pair
     646           0 :         if (0 == count) {
     647           0 :           subScriptFrame = childFrame;
     648           0 :           count = 1;
     649           0 :         } else if (1 == count) {
     650           0 :           if (tag != nsGkAtoms::msub_)
     651           0 :             supScriptFrame = childFrame;
     652           0 :           count = 0;
     653             : 
     654             :           // get the ascent/descent of sup/subscripts stored in their rects
     655             :           // rect.x = descent, rect.y = ascent
     656           0 :           if (subScriptFrame)
     657           0 :             GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
     658           0 :           if (supScriptFrame)
     659           0 :             GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
     660             : 
     661           0 :           width = std::max(subScriptSize.Width(), supScriptSize.Width());
     662             : 
     663           0 :           if (subScriptFrame) {
     664           0 :             nscoord x = dx;
     665             :             // prescripts should be right aligned
     666             :             // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
     667           0 :             if (isPreScript)
     668           0 :               x += width - subScriptSize.Width();
     669           0 :             dy = aDesiredSize.BlockStartAscent() - subScriptSize.BlockStartAscent() +
     670             :               maxSubScriptShift;
     671           0 :             FinishReflowChild (subScriptFrame, aPresContext, subScriptSize,
     672             :                                nullptr,
     673           0 :                                aFrame->MirrorIfRTL(aDesiredSize.Width(),
     674           0 :                                                    subScriptSize.Width(),
     675             :                                                    x),
     676           0 :                                dy, 0);
     677             :           }
     678             : 
     679           0 :           if (supScriptFrame) {
     680           0 :             nscoord x = dx;
     681           0 :             if (isPreScript) {
     682           0 :               x += width - supScriptSize.Width();
     683             :             } else {
     684             :               // post superscripts are shifted by the italic correction value
     685           0 :               x += italicCorrection;
     686             :             }
     687           0 :             dy = aDesiredSize.BlockStartAscent() - supScriptSize.BlockStartAscent() -
     688             :               maxSupScriptShift;
     689           0 :             FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
     690             :                                nullptr,
     691           0 :                                aFrame->MirrorIfRTL(aDesiredSize.Width(),
     692           0 :                                                    supScriptSize.Width(),
     693             :                                                    x),
     694           0 :                                dy, 0);
     695             :           }
     696           0 :           dx += width + scriptSpace;
     697             :         }
     698             :       }
     699           0 :       childFrame = childFrame->GetNextSibling();
     700           0 :     } while (prescriptsFrame != childFrame);
     701             :   }
     702             : 
     703           0 :   return NS_OK;
     704             : }

Generated by: LCOV version 1.13