LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmfracFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 304 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 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 "nsMathMLmfracFrame.h"
       8             : 
       9             : #include "gfxUtils.h"
      10             : #include "mozilla/gfx/2D.h"
      11             : #include "mozilla/RefPtr.h"
      12             : #include "nsLayoutUtils.h"
      13             : #include "nsPresContext.h"
      14             : #include "nsDisplayList.h"
      15             : #include "gfxContext.h"
      16             : #include "nsMathMLElement.h"
      17             : #include <algorithm>
      18             : #include "gfxMathTable.h"
      19             : 
      20             : using namespace mozilla;
      21             : using namespace mozilla::gfx;
      22             : 
      23             : //
      24             : // <mfrac> -- form a fraction from two subexpressions - implementation
      25             : //
      26             : 
      27             : // various fraction line thicknesses (multiplicative values of the default rule thickness)
      28             : 
      29             : #define THIN_FRACTION_LINE                   0.5f
      30             : #define THIN_FRACTION_LINE_MINIMUM_PIXELS    1  // minimum of 1 pixel
      31             : 
      32             : #define THICK_FRACTION_LINE                  2.0f
      33             : #define THICK_FRACTION_LINE_MINIMUM_PIXELS   2  // minimum of 2 pixels
      34             : 
      35             : nsIFrame*
      36           0 : NS_NewMathMLmfracFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      37             : {
      38           0 :   return new (aPresShell) nsMathMLmfracFrame(aContext);
      39             : }
      40             : 
      41           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfracFrame)
      42             : 
      43           0 : nsMathMLmfracFrame::~nsMathMLmfracFrame()
      44             : {
      45           0 : }
      46             : 
      47             : eMathMLFrameType
      48           0 : nsMathMLmfracFrame::GetMathMLFrameType()
      49             : {
      50             :   // frac is "inner" in TeXBook, Appendix G, rule 15e. See also page 170.
      51           0 :   return eMathMLFrameType_Inner;
      52             : }
      53             : 
      54             : uint8_t
      55           0 : nsMathMLmfracFrame::ScriptIncrement(nsIFrame* aFrame)
      56             : {
      57           0 :   if (!StyleFont()->mMathDisplay &&
      58           0 :       aFrame && (mFrames.FirstChild() == aFrame ||
      59           0 :                  mFrames.LastChild() == aFrame)) {
      60           0 :     return 1;
      61             :   }
      62           0 :   return 0;
      63             : }
      64             : 
      65             : NS_IMETHODIMP
      66           0 : nsMathMLmfracFrame::TransmitAutomaticData()
      67             : {
      68             :   // The TeXbook (Ch 17. p.141) says the numerator inherits the compression
      69             :   //  while the denominator is compressed
      70           0 :   UpdatePresentationDataFromChildAt(1,  1,
      71             :      NS_MATHML_COMPRESSED,
      72           0 :      NS_MATHML_COMPRESSED);
      73             : 
      74             :   // If displaystyle is false, then scriptlevel is incremented, so notify the
      75             :   // children of this.
      76           0 :   if (!StyleFont()->mMathDisplay) {
      77           0 :     PropagateFrameFlagFor(mFrames.FirstChild(),
      78           0 :                           NS_FRAME_MATHML_SCRIPT_DESCENDANT);
      79           0 :     PropagateFrameFlagFor(mFrames.LastChild(),
      80           0 :                           NS_FRAME_MATHML_SCRIPT_DESCENDANT);
      81             :   }
      82             : 
      83             :   // if our numerator is an embellished operator, let its state bubble to us
      84           0 :   GetEmbellishDataFrom(mFrames.FirstChild(), mEmbellishData);
      85           0 :   if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
      86             :     // even when embellished, we need to record that <mfrac> won't fire
      87             :     // Stretch() on its embellished child
      88           0 :     mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
      89             :   }
      90             : 
      91           0 :   return NS_OK;
      92             : }
      93             : 
      94             : nscoord
      95           0 : nsMathMLmfracFrame::CalcLineThickness(nsPresContext*  aPresContext,
      96             :                                       nsStyleContext*  aStyleContext,
      97             :                                       nsString&        aThicknessAttribute,
      98             :                                       nscoord          onePixel,
      99             :                                       nscoord          aDefaultRuleThickness,
     100             :                                       float            aFontSizeInflation)
     101             : {
     102           0 :   nscoord defaultThickness = aDefaultRuleThickness;
     103           0 :   nscoord lineThickness = aDefaultRuleThickness;
     104           0 :   nscoord minimumThickness = onePixel;
     105             : 
     106             :   // linethickness
     107             :   //
     108             :   // "Specifies the thickness of the horizontal 'fraction bar', or 'rule'. The
     109             :   // default value is 'medium', 'thin' is thinner, but visible, 'thick' is
     110             :   // thicker; the exact thickness of these is left up to the rendering agent."
     111             :   //
     112             :   // values: length | "thin" | "medium" | "thick"
     113             :   // default: medium
     114             :   //
     115           0 :   if (!aThicknessAttribute.IsEmpty()) {
     116           0 :     if (aThicknessAttribute.EqualsLiteral("thin")) {
     117           0 :       lineThickness = NSToCoordFloor(defaultThickness * THIN_FRACTION_LINE);
     118           0 :       minimumThickness = onePixel * THIN_FRACTION_LINE_MINIMUM_PIXELS;
     119             :       // should visually decrease by at least one pixel, if default is not a pixel
     120           0 :       if (defaultThickness > onePixel && lineThickness > defaultThickness - onePixel)
     121           0 :         lineThickness = defaultThickness - onePixel;
     122             :     }
     123           0 :     else if (aThicknessAttribute.EqualsLiteral("medium")) {
     124             :       // medium is default
     125             :     }
     126           0 :     else if (aThicknessAttribute.EqualsLiteral("thick")) {
     127           0 :       lineThickness = NSToCoordCeil(defaultThickness * THICK_FRACTION_LINE);
     128           0 :       minimumThickness = onePixel * THICK_FRACTION_LINE_MINIMUM_PIXELS;
     129             :       // should visually increase by at least one pixel
     130           0 :       if (lineThickness < defaultThickness + onePixel)
     131           0 :         lineThickness = defaultThickness + onePixel;
     132             :     }
     133             :     else {
     134             :       // length value
     135           0 :       lineThickness = defaultThickness;
     136             :       ParseNumericValue(aThicknessAttribute, &lineThickness,
     137             :                         nsMathMLElement::PARSE_ALLOW_UNITLESS,
     138           0 :                         aPresContext, aStyleContext, aFontSizeInflation);
     139             :     }
     140             :   }
     141             : 
     142             :   // use minimum if the lineThickness is a non-zero value less than minimun
     143           0 :   if (lineThickness && lineThickness < minimumThickness)
     144           0 :     lineThickness = minimumThickness;
     145             : 
     146           0 :   return lineThickness;
     147             : }
     148             : 
     149             : void
     150           0 : nsMathMLmfracFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     151             :                                      const nsRect&           aDirtyRect,
     152             :                                      const nsDisplayListSet& aLists)
     153             : {
     154             :   /////////////
     155             :   // paint the numerator and denominator
     156           0 :   nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
     157             : 
     158             :   /////////////
     159             :   // paint the fraction line
     160           0 :   if (mIsBevelled) {
     161           0 :     DisplaySlash(aBuilder, this, mLineRect, mLineThickness, aLists);
     162             :   } else {
     163           0 :     DisplayBar(aBuilder, this, mLineRect, aLists);
     164             :   }
     165           0 : }
     166             : 
     167             : 
     168             : nsresult
     169           0 : nsMathMLmfracFrame::AttributeChanged(int32_t  aNameSpaceID,
     170             :                                      nsIAtom* aAttribute,
     171             :                                      int32_t  aModType)
     172             : {
     173           0 :   if (nsGkAtoms::linethickness_ == aAttribute) {
     174           0 :     InvalidateFrame();
     175             :   }
     176             :   return
     177           0 :     nsMathMLContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
     178           0 :                                              aModType);
     179             : }
     180             : 
     181             : /* virtual */ nsresult
     182           0 : nsMathMLmfracFrame::MeasureForWidth(DrawTarget* aDrawTarget,
     183             :                                     ReflowOutput& aDesiredSize)
     184             : {
     185           0 :   return PlaceInternal(aDrawTarget, false, aDesiredSize, true);
     186             : }
     187             : 
     188             : nscoord
     189           0 : nsMathMLmfracFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
     190             : {
     191           0 :   nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
     192           0 :   if (!gap) return 0;
     193             : 
     194           0 :   mLineRect.MoveBy(gap, 0);
     195           0 :   return gap;
     196             : }
     197             : 
     198             : /* virtual */ nsresult
     199           0 : nsMathMLmfracFrame::Place(DrawTarget*          aDrawTarget,
     200             :                           bool                 aPlaceOrigin,
     201             :                           ReflowOutput& aDesiredSize)
     202             : {
     203           0 :   return PlaceInternal(aDrawTarget, aPlaceOrigin, aDesiredSize, false);
     204             : }
     205             : 
     206             : nsresult
     207           0 : nsMathMLmfracFrame::PlaceInternal(DrawTarget*          aDrawTarget,
     208             :                                   bool                 aPlaceOrigin,
     209             :                                   ReflowOutput& aDesiredSize,
     210             :                                   bool                 aWidthOnly)
     211             : {
     212             :   ////////////////////////////////////
     213             :   // Get the children's desired sizes
     214           0 :   nsBoundingMetrics bmNum, bmDen;
     215           0 :   ReflowOutput sizeNum(aDesiredSize.GetWritingMode());
     216           0 :   ReflowOutput sizeDen(aDesiredSize.GetWritingMode());
     217           0 :   nsIFrame* frameDen = nullptr;
     218           0 :   nsIFrame* frameNum = mFrames.FirstChild();
     219           0 :   if (frameNum)
     220           0 :     frameDen = frameNum->GetNextSibling();
     221           0 :   if (!frameNum || !frameDen || frameDen->GetNextSibling()) {
     222             :     // report an error, encourage people to get their markups in order
     223           0 :     if (aPlaceOrigin) {
     224           0 :       ReportChildCountError();
     225             :     }
     226           0 :     return ReflowError(aDrawTarget, aDesiredSize);
     227             :   }
     228           0 :   GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
     229           0 :   GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
     230             : 
     231           0 :   nsPresContext* presContext = PresContext();
     232           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     233             : 
     234           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     235             :   RefPtr<nsFontMetrics> fm =
     236           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     237             : 
     238             :   nscoord defaultRuleThickness, axisHeight;
     239           0 :   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
     240           0 :   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
     241           0 :   if (mathFont) {
     242           0 :     defaultRuleThickness = mathFont->MathTable()->
     243           0 :       Constant(gfxMathTable::FractionRuleThickness, oneDevPixel);
     244             :   } else {
     245           0 :     GetRuleThickness(aDrawTarget, fm, defaultRuleThickness);
     246             :   }
     247           0 :   GetAxisHeight(aDrawTarget, fm, axisHeight);
     248             : 
     249           0 :   bool outermostEmbellished = false;
     250           0 :   if (mEmbellishData.coreFrame) {
     251           0 :     nsEmbellishData parentData;
     252           0 :     GetEmbellishDataFrom(GetParent(), parentData);
     253           0 :     outermostEmbellished = parentData.coreFrame != mEmbellishData.coreFrame;
     254             :   }
     255             : 
     256             :   // see if the linethickness attribute is there
     257           0 :   nsAutoString value;
     258           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::linethickness_, value);
     259           0 :   mLineThickness = CalcLineThickness(presContext, mStyleContext, value,
     260             :                                      onePixel, defaultRuleThickness,
     261             :                                      fontSizeInflation);
     262             : 
     263             :   // bevelled attribute
     264           0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::bevelled_, value);
     265           0 :   mIsBevelled = value.EqualsLiteral("true");
     266             : 
     267           0 :   bool displayStyle = StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK;
     268             : 
     269           0 :   if (!mIsBevelled) {
     270           0 :     mLineRect.height = mLineThickness;
     271             : 
     272             :     // by default, leave at least one-pixel padding at either end, and add
     273             :     // lspace & rspace that may come from <mo> if we are an outermost
     274             :     // embellished container (we fetch values from the core since they may use
     275             :     // units that depend on style data, and style changes could have occurred
     276             :     // in the core since our last visit there)
     277           0 :     nscoord leftSpace = onePixel;
     278           0 :     nscoord rightSpace = onePixel;
     279           0 :     if (outermostEmbellished) {
     280           0 :       nsEmbellishData coreData;
     281           0 :       GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
     282           0 :       leftSpace += StyleVisibility()->mDirection ?
     283           0 :                      coreData.trailingSpace : coreData.leadingSpace;
     284           0 :       rightSpace += StyleVisibility()->mDirection ?
     285           0 :                       coreData.leadingSpace : coreData.trailingSpace;
     286             :     }
     287             : 
     288           0 :     nscoord actualRuleThickness =  mLineThickness;
     289             : 
     290             :     //////////////////
     291             :     // Get shifts
     292           0 :     nscoord numShift = 0;
     293           0 :     nscoord denShift = 0;
     294             : 
     295             :     // Rule 15b, App. G, TeXbook
     296             :     nscoord numShift1, numShift2, numShift3;
     297             :     nscoord denShift1, denShift2;
     298             : 
     299           0 :     GetNumeratorShifts(fm, numShift1, numShift2, numShift3);
     300           0 :     GetDenominatorShifts(fm, denShift1, denShift2);
     301             : 
     302           0 :     if (0 == actualRuleThickness) {
     303           0 :       numShift = displayStyle ? numShift1 : numShift3;
     304           0 :       denShift = displayStyle ? denShift1 : denShift2;
     305           0 :       if (mathFont) {
     306             :         numShift = mathFont->
     307           0 :           MathTable()->Constant(displayStyle ?
     308             :                                 gfxMathTable::StackTopDisplayStyleShiftUp :
     309             :                                 gfxMathTable::StackTopShiftUp,
     310           0 :                                 oneDevPixel);
     311             :         denShift = mathFont->
     312           0 :           MathTable()->Constant(displayStyle ?
     313             :                                 gfxMathTable::StackBottomDisplayStyleShiftDown :
     314             :                                 gfxMathTable::StackBottomShiftDown,
     315           0 :                                 oneDevPixel);
     316             :       }
     317             :     } else {
     318           0 :       numShift = displayStyle ? numShift1 : numShift2;
     319           0 :       denShift = displayStyle ? denShift1 : denShift2;
     320           0 :       if (mathFont) {
     321             :         numShift = mathFont->MathTable()->
     322           0 :           Constant(displayStyle ?
     323             :                    gfxMathTable::FractionNumeratorDisplayStyleShiftUp :
     324             :                    gfxMathTable::FractionNumeratorShiftUp,
     325           0 :                    oneDevPixel);
     326             :         denShift = mathFont->MathTable()->
     327           0 :           Constant(displayStyle ?
     328             :                    gfxMathTable::FractionDenominatorDisplayStyleShiftDown :
     329             :                    gfxMathTable::FractionDenominatorShiftDown,
     330           0 :                    oneDevPixel);
     331             :       }
     332             :     }
     333             : 
     334           0 :     if (0 == actualRuleThickness) {
     335             :       // Rule 15c, App. G, TeXbook
     336             : 
     337             :       // min clearance between numerator and denominator
     338           0 :       nscoord minClearance = displayStyle ?
     339           0 :         7 * defaultRuleThickness : 3 * defaultRuleThickness;
     340           0 :       if (mathFont) {
     341             :         minClearance = mathFont->MathTable()->
     342           0 :           Constant(displayStyle ?
     343             :                    gfxMathTable::StackDisplayStyleGapMin :
     344             :                    gfxMathTable::StackGapMin,
     345           0 :                    oneDevPixel);
     346             :       }
     347             :       // Factor in axis height
     348             :       // http://www.mathml-association.org/MathMLinHTML5/S3.html#SS3.SSS2
     349           0 :       numShift += axisHeight;
     350           0 :       denShift += axisHeight;
     351             : 
     352             :       nscoord actualClearance =
     353           0 :         (numShift - bmNum.descent) - (bmDen.ascent - denShift);
     354             :       // actualClearance should be >= minClearance
     355           0 :       if (actualClearance < minClearance) {
     356           0 :         nscoord halfGap = (minClearance - actualClearance)/2;
     357           0 :         numShift += halfGap;
     358           0 :         denShift += halfGap;
     359             :       }
     360             :     }
     361             :     else {
     362             :     // Rule 15d, App. G, TeXbook
     363             : 
     364             :     // min clearance between numerator or denominator and middle of bar
     365             : 
     366             :     // TeX has a different interpretation of the thickness.
     367             :     // Try $a \above10pt b$ to see. Here is what TeX does:
     368             :     // minClearance = displayStyle ?
     369             :     //   3 * actualRuleThickness : actualRuleThickness;
     370             : 
     371             :     // we slightly depart from TeX here. We use the defaultRuleThickness instead
     372             :     // of the value coming from the linethickness attribute, i.e., we recover what
     373             :     // TeX does if the user hasn't set linethickness. But when the linethickness
     374             :     // is set, we avoid the wide gap problem.
     375           0 :       nscoord minClearanceNum = displayStyle ?
     376           0 :         3 * defaultRuleThickness : defaultRuleThickness + onePixel;
     377           0 :       nscoord minClearanceDen = minClearanceNum;
     378           0 :       if (mathFont) {
     379             :         minClearanceNum = mathFont->
     380           0 :           MathTable()->Constant(displayStyle ?
     381             :                                 gfxMathTable::FractionNumDisplayStyleGapMin :
     382             :                                 gfxMathTable::FractionNumeratorGapMin,
     383           0 :                                 oneDevPixel);
     384             :         minClearanceDen = mathFont->
     385           0 :           MathTable()->Constant(displayStyle ?
     386             :                                 gfxMathTable::FractionDenomDisplayStyleGapMin :
     387             :                                 gfxMathTable::FractionDenominatorGapMin,
     388           0 :                                 oneDevPixel);
     389             :       }
     390             : 
     391             :       // adjust numShift to maintain minClearanceNum if needed
     392             :       nscoord actualClearanceNum =
     393           0 :         (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2);
     394           0 :       if (actualClearanceNum < minClearanceNum) {
     395           0 :         numShift += (minClearanceNum - actualClearanceNum);
     396             :       }
     397             :       // adjust denShift to maintain minClearanceDen if needed
     398             :       nscoord actualClearanceDen =
     399           0 :         (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift);
     400           0 :       if (actualClearanceDen < minClearanceDen) {
     401           0 :         denShift += (minClearanceDen - actualClearanceDen);
     402             :       }
     403             :     }
     404             : 
     405             :     //////////////////
     406             :     // Place Children
     407             : 
     408             :     // XXX Need revisiting the width. TeX uses the exact width
     409             :     // e.g. in $$\huge\frac{\displaystyle\int}{i}$$
     410           0 :     nscoord width = std::max(bmNum.width, bmDen.width);
     411           0 :     nscoord dxNum = leftSpace + (width - sizeNum.Width())/2;
     412           0 :     nscoord dxDen = leftSpace + (width - sizeDen.Width())/2;
     413           0 :     width += leftSpace + rightSpace;
     414             : 
     415             :     // see if the numalign attribute is there
     416           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::numalign_, value);
     417           0 :     if (value.EqualsLiteral("left"))
     418           0 :       dxNum = leftSpace;
     419           0 :     else if (value.EqualsLiteral("right"))
     420           0 :       dxNum = width - rightSpace - sizeNum.Width();
     421             : 
     422             :     // see if the denomalign attribute is there
     423           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::denomalign_, value);
     424           0 :     if (value.EqualsLiteral("left"))
     425           0 :       dxDen = leftSpace;
     426           0 :     else if (value.EqualsLiteral("right"))
     427           0 :       dxDen = width - rightSpace - sizeDen.Width();
     428             : 
     429           0 :     mBoundingMetrics.rightBearing =
     430           0 :       std::max(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing);
     431           0 :     if (mBoundingMetrics.rightBearing < width - rightSpace)
     432           0 :       mBoundingMetrics.rightBearing = width - rightSpace;
     433           0 :     mBoundingMetrics.leftBearing =
     434           0 :       std::min(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing);
     435           0 :     if (mBoundingMetrics.leftBearing > leftSpace)
     436           0 :       mBoundingMetrics.leftBearing = leftSpace;
     437           0 :     mBoundingMetrics.ascent = bmNum.ascent + numShift;
     438           0 :     mBoundingMetrics.descent = bmDen.descent + denShift;
     439           0 :     mBoundingMetrics.width = width;
     440             : 
     441           0 :     aDesiredSize.SetBlockStartAscent(sizeNum.BlockStartAscent() + numShift);
     442           0 :     aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     443           0 :       sizeDen.Height() - sizeDen.BlockStartAscent() + denShift;
     444           0 :     aDesiredSize.Width() = mBoundingMetrics.width;
     445           0 :     aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     446             : 
     447           0 :     mReference.x = 0;
     448           0 :     mReference.y = aDesiredSize.BlockStartAscent();
     449             : 
     450           0 :     if (aPlaceOrigin) {
     451             :       nscoord dy;
     452             :       // place numerator
     453           0 :       dy = 0;
     454           0 :       FinishReflowChild(frameNum, presContext, sizeNum, nullptr, dxNum, dy, 0);
     455             :       // place denominator
     456           0 :       dy = aDesiredSize.Height() - sizeDen.Height();
     457           0 :       FinishReflowChild(frameDen, presContext, sizeDen, nullptr, dxDen, dy, 0);
     458             :       // place the fraction bar - dy is top of bar
     459           0 :       dy = aDesiredSize.BlockStartAscent() - (axisHeight + actualRuleThickness/2);
     460           0 :       mLineRect.SetRect(leftSpace, dy, width - (leftSpace + rightSpace),
     461           0 :                         actualRuleThickness);
     462             :     }
     463             :   } else {
     464           0 :     nscoord numShift = 0.0;
     465           0 :     nscoord denShift = 0.0;
     466           0 :     nscoord padding = 3 * defaultRuleThickness;
     467           0 :     nscoord slashRatio = 3;
     468             : 
     469             :     // Define the constant used in the expression of the maximum width
     470           0 :     nscoord em = fm->EmHeight();
     471           0 :     nscoord slashMaxWidthConstant = 2 * em;
     472             : 
     473             :     // For large line thicknesses the minimum slash height is limited to the
     474             :     // largest expected height of a fraction
     475             :     nscoord slashMinHeight = slashRatio *
     476           0 :       std::min(2 * mLineThickness, slashMaxWidthConstant);
     477             : 
     478           0 :     nscoord leadingSpace = padding;
     479           0 :     nscoord trailingSpace = padding;
     480           0 :     if (outermostEmbellished) {
     481           0 :       nsEmbellishData coreData;
     482           0 :       GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
     483           0 :       leadingSpace += coreData.leadingSpace;
     484           0 :       trailingSpace += coreData.trailingSpace;
     485             :     }
     486             :     nscoord delta;
     487             : 
     488             :     //           ___________
     489             :     //          |           |    /
     490             :     //         {|-NUMERATOR-|   /
     491             :     //         {|___________|  S
     492             :     //         {               L
     493             :     // numShift{               A
     494             :     // ------------------------------------------------------- baseline
     495             :     //                         S   _____________ } denShift
     496             :     //                         H  |             |}
     497             :     //                        /   |-DENOMINATOR-|}
     498             :     //                       /    |_____________|
     499             :     //
     500             : 
     501             :     // first, ensure that the top of the numerator is at least as high as the
     502             :     // top of the denominator (and the reverse for the bottoms)
     503           0 :     delta = std::max(bmDen.ascent - bmNum.ascent,
     504           0 :                    bmNum.descent - bmDen.descent) / 2;
     505           0 :     if (delta > 0) {
     506           0 :       numShift += delta;
     507           0 :       denShift += delta;
     508             :     }
     509             : 
     510           0 :     if (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK) {
     511           0 :       delta = std::min(bmDen.ascent + bmDen.descent,
     512           0 :                      bmNum.ascent + bmNum.descent) / 2;
     513           0 :       numShift += delta;
     514           0 :       denShift += delta;
     515             :     } else {
     516           0 :       nscoord xHeight = fm->XHeight();
     517           0 :       numShift += xHeight / 2;
     518           0 :       denShift += xHeight / 4;
     519             :     }
     520             : 
     521             :     // Set the ascent/descent of our BoundingMetrics.
     522           0 :     mBoundingMetrics.ascent = bmNum.ascent + numShift;
     523           0 :     mBoundingMetrics.descent = bmDen.descent + denShift;
     524             : 
     525             :     // At this point the height of the slash is
     526             :     // mBoundingMetrics.ascent + mBoundingMetrics.descent
     527             :     // Ensure that it is greater than slashMinHeight
     528           0 :     delta = (slashMinHeight -
     529           0 :              (mBoundingMetrics.ascent + mBoundingMetrics.descent)) / 2;
     530           0 :     if (delta > 0) {
     531           0 :       mBoundingMetrics.ascent += delta;
     532           0 :       mBoundingMetrics.descent += delta;
     533             :     }
     534             : 
     535             :     // Set the width of the slash
     536           0 :     if (aWidthOnly) {
     537           0 :       mLineRect.width = mLineThickness + slashMaxWidthConstant;
     538             :     } else {
     539           0 :       mLineRect.width = mLineThickness +
     540           0 :         std::min(slashMaxWidthConstant,
     541           0 :                (mBoundingMetrics.ascent + mBoundingMetrics.descent) /
     542           0 :                slashRatio);
     543             :     }
     544             : 
     545             :     // Set horizontal bounding metrics
     546           0 :     if (StyleVisibility()->mDirection) {
     547           0 :       mBoundingMetrics.leftBearing = trailingSpace + bmDen.leftBearing;
     548           0 :       mBoundingMetrics.rightBearing = trailingSpace + bmDen.width + mLineRect.width + bmNum.rightBearing;
     549             :     } else {
     550           0 :       mBoundingMetrics.leftBearing = leadingSpace + bmNum.leftBearing;
     551           0 :       mBoundingMetrics.rightBearing = leadingSpace + bmNum.width + mLineRect.width + bmDen.rightBearing;
     552             :     }
     553           0 :     mBoundingMetrics.width =
     554           0 :       leadingSpace + bmNum.width + mLineRect.width + bmDen.width +
     555             :       trailingSpace;
     556             : 
     557             :     // Set aDesiredSize
     558           0 :     aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + padding);
     559           0 :     aDesiredSize.Height() =
     560           0 :       mBoundingMetrics.ascent + mBoundingMetrics.descent + 2 * padding;
     561           0 :     aDesiredSize.Width() = mBoundingMetrics.width;
     562           0 :     aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     563             : 
     564           0 :     mReference.x = 0;
     565           0 :     mReference.y = aDesiredSize.BlockStartAscent();
     566             : 
     567           0 :     if (aPlaceOrigin) {
     568             :       nscoord dx, dy;
     569             : 
     570             :       // place numerator
     571           0 :       dx = MirrorIfRTL(aDesiredSize.Width(), sizeNum.Width(),
     572           0 :                        leadingSpace);
     573           0 :       dy = aDesiredSize.BlockStartAscent() - numShift - sizeNum.BlockStartAscent();
     574           0 :       FinishReflowChild(frameNum, presContext, sizeNum, nullptr, dx, dy, 0);
     575             : 
     576             :       // place the fraction bar
     577           0 :       dx = MirrorIfRTL(aDesiredSize.Width(), mLineRect.width,
     578           0 :                        leadingSpace + bmNum.width);
     579           0 :       dy = aDesiredSize.BlockStartAscent() - mBoundingMetrics.ascent;
     580           0 :       mLineRect.SetRect(dx, dy,
     581           0 :                         mLineRect.width, aDesiredSize.Height() - 2 * padding);
     582             : 
     583             :       // place denominator
     584           0 :       dx = MirrorIfRTL(aDesiredSize.Width(), sizeDen.Width(),
     585           0 :                        leadingSpace + bmNum.width + mLineRect.width);
     586           0 :       dy = aDesiredSize.BlockStartAscent() + denShift - sizeDen.BlockStartAscent();
     587           0 :       FinishReflowChild(frameDen, presContext, sizeDen, nullptr, dx, dy, 0);
     588             :     }
     589             : 
     590             :   }
     591             : 
     592           0 :   return NS_OK;
     593             : }
     594             : 
     595             : class nsDisplayMathMLSlash : public nsDisplayItem {
     596             : public:
     597           0 :   nsDisplayMathMLSlash(nsDisplayListBuilder* aBuilder,
     598             :                        nsIFrame* aFrame, const nsRect& aRect,
     599             :                        nscoord aThickness, bool aRTL)
     600           0 :     : nsDisplayItem(aBuilder, aFrame), mRect(aRect), mThickness(aThickness),
     601           0 :       mRTL(aRTL) {
     602           0 :     MOZ_COUNT_CTOR(nsDisplayMathMLSlash);
     603           0 :   }
     604             : #ifdef NS_BUILD_REFCNT_LOGGING
     605           0 :   virtual ~nsDisplayMathMLSlash() {
     606           0 :     MOZ_COUNT_DTOR(nsDisplayMathMLSlash);
     607           0 :   }
     608             : #endif
     609             : 
     610             :   virtual void Paint(nsDisplayListBuilder* aBuilder,
     611             :                      gfxContext* aCtx) override;
     612           0 :   NS_DISPLAY_DECL_NAME("MathMLSlash", TYPE_MATHML_SLASH)
     613             : 
     614             : private:
     615             :   nsRect    mRect;
     616             :   nscoord   mThickness;
     617             :   bool      mRTL;
     618             : };
     619             : 
     620           0 : void nsDisplayMathMLSlash::Paint(nsDisplayListBuilder* aBuilder,
     621             :                                  gfxContext* aCtx)
     622             : {
     623           0 :   DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
     624             : 
     625             :   // get the gfxRect
     626           0 :   nsPresContext* presContext = mFrame->PresContext();
     627           0 :   Rect rect = NSRectToRect(mRect + ToReferenceFrame(),
     628           0 :                            presContext->AppUnitsPerDevPixel());
     629             : 
     630           0 :   ColorPattern color(ToDeviceColor(
     631           0 :     mFrame->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor)));
     632             : 
     633             :   // draw the slash as a parallelogram
     634           0 :   Point delta = Point(presContext->AppUnitsToGfxUnits(mThickness), 0);
     635           0 :   RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
     636           0 :   if (mRTL) {
     637           0 :     builder->MoveTo(rect.TopLeft());
     638           0 :     builder->LineTo(rect.TopLeft() + delta);
     639           0 :     builder->LineTo(rect.BottomRight());
     640           0 :     builder->LineTo(rect.BottomRight() - delta);
     641             :   } else {
     642           0 :     builder->MoveTo(rect.BottomLeft());
     643           0 :     builder->LineTo(rect.BottomLeft() + delta);
     644           0 :     builder->LineTo(rect.TopRight());
     645           0 :     builder->LineTo(rect.TopRight() - delta);
     646             :   }
     647           0 :   RefPtr<Path> path = builder->Finish();
     648           0 :   aDrawTarget.Fill(path, color);
     649           0 : }
     650             : 
     651             : void
     652           0 : nsMathMLmfracFrame::DisplaySlash(nsDisplayListBuilder* aBuilder,
     653             :                                  nsIFrame* aFrame, const nsRect& aRect,
     654             :                                  nscoord aThickness,
     655             :                                  const nsDisplayListSet& aLists) {
     656           0 :   if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty())
     657           0 :     return;
     658             : 
     659           0 :   aLists.Content()->AppendNewToTop(new (aBuilder)
     660             :     nsDisplayMathMLSlash(aBuilder, aFrame, aRect, aThickness,
     661           0 :                          StyleVisibility()->mDirection));
     662             : }

Generated by: LCOV version 1.13