LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmencloseFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 450 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 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 "nsMathMLmencloseFrame.h"
       7             : 
       8             : #include "gfx2DGlue.h"
       9             : #include "gfxUtils.h"
      10             : #include "mozilla/gfx/2D.h"
      11             : #include "mozilla/gfx/PathHelpers.h"
      12             : #include "nsPresContext.h"
      13             : #include "nsWhitespaceTokenizer.h"
      14             : 
      15             : #include "nsDisplayList.h"
      16             : #include "gfxContext.h"
      17             : #include "nsMathMLChar.h"
      18             : #include <algorithm>
      19             : 
      20             : using namespace mozilla;
      21             : using namespace mozilla::gfx;
      22             : 
      23             : //
      24             : // <menclose> -- enclose content with a stretching symbol such
      25             : // as a long division sign. - implementation
      26             : 
      27             : // longdiv:
      28             : // Unicode 5.1 assigns U+27CC to LONG DIVISION, but a right parenthesis
      29             : // renders better with current font support.
      30             : static const char16_t kLongDivChar = ')';
      31             : 
      32             : // radical: 'SQUARE ROOT'
      33             : static const char16_t kRadicalChar = 0x221A;
      34             : 
      35             : // updiagonalstrike
      36             : static const uint8_t kArrowHeadSize = 10;
      37             : 
      38             : // phasorangle
      39             : static const uint8_t kPhasorangleWidth = 8;
      40             : 
      41             : nsIFrame*
      42           0 : NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      43             : {
      44           0 :   return new (aPresShell) nsMathMLmencloseFrame(aContext);
      45             : }
      46             : 
      47           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmencloseFrame)
      48             : 
      49           0 : nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext* aContext, ClassID aID) :
      50             :   nsMathMLContainerFrame(aContext, aID), mNotationsToDraw(0),
      51             :   mRuleThickness(0), mRadicalRuleThickness(0),
      52           0 :   mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0)
      53             : {
      54           0 : }
      55             : 
      56           0 : nsMathMLmencloseFrame::~nsMathMLmencloseFrame()
      57             : {
      58           0 : }
      59             : 
      60           0 : nsresult nsMathMLmencloseFrame::AllocateMathMLChar(nsMencloseNotation mask)
      61             : {
      62             :   // Is the char already allocated?
      63           0 :   if ((mask == NOTATION_LONGDIV && mLongDivCharIndex >= 0) ||
      64           0 :       (mask == NOTATION_RADICAL && mRadicalCharIndex >= 0))
      65           0 :     return NS_OK;
      66             : 
      67             :   // No need to track the style context given to our MathML chars.
      68             :   // The Style System will use Get/SetAdditionalStyleContext() to keep it
      69             :   // up-to-date if dynamic changes arise.
      70           0 :   uint32_t i = mMathMLChar.Length();
      71           0 :   nsAutoString Char;
      72             : 
      73           0 :   if (!mMathMLChar.AppendElement())
      74           0 :     return NS_ERROR_OUT_OF_MEMORY;
      75             : 
      76           0 :   if (mask == NOTATION_LONGDIV) {
      77           0 :     Char.Assign(kLongDivChar);
      78           0 :     mLongDivCharIndex = i;
      79           0 :   } else if (mask == NOTATION_RADICAL) {
      80           0 :     Char.Assign(kRadicalChar);
      81           0 :     mRadicalCharIndex = i;
      82             :   }
      83             : 
      84           0 :   nsPresContext *presContext = PresContext();
      85           0 :   mMathMLChar[i].SetData(Char);
      86           0 :   ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar[i]);
      87             : 
      88           0 :   return NS_OK;
      89             : }
      90             : 
      91             : /*
      92             :  * Add a notation to draw, if the argument is the name of a known notation.
      93             :  * @param aNotation string name of a notation
      94             :  */
      95           0 : nsresult nsMathMLmencloseFrame::AddNotation(const nsAString& aNotation)
      96             : {
      97             :   nsresult rv;
      98             : 
      99           0 :   if (aNotation.EqualsLiteral("longdiv")) {
     100           0 :     rv = AllocateMathMLChar(NOTATION_LONGDIV);
     101           0 :     NS_ENSURE_SUCCESS(rv, rv);
     102           0 :     mNotationsToDraw |= NOTATION_LONGDIV;
     103           0 :   } else if (aNotation.EqualsLiteral("actuarial")) {
     104           0 :     mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_TOP);
     105           0 :   } else if (aNotation.EqualsLiteral("radical")) {
     106           0 :     rv = AllocateMathMLChar(NOTATION_RADICAL);
     107           0 :     NS_ENSURE_SUCCESS(rv, rv);
     108           0 :     mNotationsToDraw |= NOTATION_RADICAL;
     109           0 :   } else if (aNotation.EqualsLiteral("box")) {
     110           0 :     mNotationsToDraw |= (NOTATION_LEFT | NOTATION_RIGHT |
     111           0 :                          NOTATION_TOP | NOTATION_BOTTOM);
     112           0 :   } else if (aNotation.EqualsLiteral("roundedbox")) {
     113           0 :     mNotationsToDraw |= NOTATION_ROUNDEDBOX;
     114           0 :   } else if (aNotation.EqualsLiteral("circle")) {
     115           0 :     mNotationsToDraw |= NOTATION_CIRCLE;
     116           0 :   } else if (aNotation.EqualsLiteral("left")) {
     117           0 :     mNotationsToDraw |= NOTATION_LEFT;
     118           0 :   } else if (aNotation.EqualsLiteral("right")) {
     119           0 :     mNotationsToDraw |= NOTATION_RIGHT;
     120           0 :   } else if (aNotation.EqualsLiteral("top")) {
     121           0 :     mNotationsToDraw |= NOTATION_TOP;
     122           0 :   } else if (aNotation.EqualsLiteral("bottom")) {
     123           0 :     mNotationsToDraw |= NOTATION_BOTTOM;
     124           0 :   } else if (aNotation.EqualsLiteral("updiagonalstrike")) {
     125           0 :     mNotationsToDraw |= NOTATION_UPDIAGONALSTRIKE;
     126           0 :   } else if (aNotation.EqualsLiteral("updiagonalarrow")) {
     127           0 :     mNotationsToDraw |= NOTATION_UPDIAGONALARROW;
     128           0 :   } else if (aNotation.EqualsLiteral("downdiagonalstrike")) {
     129           0 :     mNotationsToDraw |= NOTATION_DOWNDIAGONALSTRIKE;
     130           0 :   } else if (aNotation.EqualsLiteral("verticalstrike")) {
     131           0 :     mNotationsToDraw |= NOTATION_VERTICALSTRIKE;
     132           0 :   } else if (aNotation.EqualsLiteral("horizontalstrike")) {
     133           0 :     mNotationsToDraw |= NOTATION_HORIZONTALSTRIKE;
     134           0 :   } else if (aNotation.EqualsLiteral("madruwb")) {
     135           0 :     mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_BOTTOM);
     136           0 :   } else if (aNotation.EqualsLiteral("phasorangle")) {
     137           0 :     mNotationsToDraw |= (NOTATION_BOTTOM | NOTATION_PHASORANGLE);
     138             :   }
     139             : 
     140           0 :   return NS_OK;
     141             : }
     142             : 
     143             : /*
     144             :  * Initialize the list of notations to draw
     145             :  */
     146           0 : void nsMathMLmencloseFrame::InitNotations()
     147             : {
     148           0 :   mNotationsToDraw = 0;
     149           0 :   mLongDivCharIndex = mRadicalCharIndex = -1;
     150           0 :   mMathMLChar.Clear();
     151             : 
     152           0 :   nsAutoString value;
     153             : 
     154           0 :   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::notation_, value)) {
     155             :     // parse the notation attribute
     156           0 :     nsWhitespaceTokenizer tokenizer(value);
     157             : 
     158           0 :     while (tokenizer.hasMoreTokens())
     159           0 :       AddNotation(tokenizer.nextToken());
     160             : 
     161           0 :     if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
     162             :       // For <menclose notation="updiagonalstrike updiagonalarrow">, if
     163             :       // the two notations are drawn then the strike line may cause the point of
     164             :       // the arrow to be too wide. Hence we will only draw the updiagonalarrow
     165             :       // and the arrow shaft may be thought to be the updiagonalstrike.
     166           0 :       mNotationsToDraw &= ~NOTATION_UPDIAGONALSTRIKE;
     167             :     }
     168             :   } else {
     169             :     // default: longdiv
     170           0 :     if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV)))
     171           0 :       return;
     172           0 :     mNotationsToDraw = NOTATION_LONGDIV;
     173             :   }
     174             : }
     175             : 
     176             : NS_IMETHODIMP
     177           0 : nsMathMLmencloseFrame::InheritAutomaticData(nsIFrame* aParent)
     178             : {
     179             :   // let the base class get the default from our parent
     180           0 :   nsMathMLContainerFrame::InheritAutomaticData(aParent);
     181             : 
     182           0 :   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
     183             : 
     184           0 :   InitNotations();
     185             : 
     186           0 :   return NS_OK;
     187             : }
     188             : 
     189             : NS_IMETHODIMP
     190           0 : nsMathMLmencloseFrame::TransmitAutomaticData()
     191             : {
     192           0 :   if (IsToDraw(NOTATION_RADICAL)) {
     193             :     // The TeXBook (Ch 17. p.141) says that \sqrt is cramped
     194           0 :     UpdatePresentationDataFromChildAt(0, -1,
     195             :                                       NS_MATHML_COMPRESSED,
     196           0 :                                       NS_MATHML_COMPRESSED);
     197             :   }
     198             : 
     199           0 :   return NS_OK;
     200             : }
     201             : 
     202             : void
     203           0 : nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     204             :                                         const nsRect&           aDirtyRect,
     205             :                                         const nsDisplayListSet& aLists)
     206             : {
     207             :   /////////////
     208             :   // paint the menclosed content
     209           0 :   nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
     210             : 
     211           0 :   if (NS_MATHML_HAS_ERROR(mPresentationData.flags))
     212           0 :     return;
     213             : 
     214           0 :   nsRect mencloseRect = nsIFrame::GetRect();
     215           0 :   mencloseRect.x = mencloseRect.y = 0;
     216             : 
     217           0 :   if (IsToDraw(NOTATION_RADICAL)) {
     218           0 :     mMathMLChar[mRadicalCharIndex].Display(aBuilder, this, aLists, 0);
     219             : 
     220           0 :     nsRect rect;
     221           0 :     mMathMLChar[mRadicalCharIndex].GetRect(rect);
     222           0 :     rect.MoveBy(StyleVisibility()->mDirection ? -mContentWidth : rect.width, 0);
     223           0 :     rect.SizeTo(mContentWidth, mRadicalRuleThickness);
     224           0 :     DisplayBar(aBuilder, this, rect, aLists);
     225             :   }
     226             : 
     227           0 :   if (IsToDraw(NOTATION_PHASORANGLE)) {
     228           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     229           0 :                 mRuleThickness, NOTATION_PHASORANGLE);
     230             :   }
     231             : 
     232           0 :   if (IsToDraw(NOTATION_LONGDIV)) {
     233           0 :     mMathMLChar[mLongDivCharIndex].Display(aBuilder, this, aLists, 1);
     234             : 
     235           0 :     nsRect rect;
     236           0 :     mMathMLChar[mLongDivCharIndex].GetRect(rect);
     237           0 :     rect.SizeTo(rect.width + mContentWidth, mRuleThickness);
     238           0 :     DisplayBar(aBuilder, this, rect, aLists);
     239             :   }
     240             : 
     241           0 :   if (IsToDraw(NOTATION_TOP)) {
     242           0 :     nsRect rect(0, 0, mencloseRect.width, mRuleThickness);
     243           0 :     DisplayBar(aBuilder, this, rect, aLists);
     244             :   }
     245             : 
     246           0 :   if (IsToDraw(NOTATION_BOTTOM)) {
     247           0 :     nsRect rect(0, mencloseRect.height - mRuleThickness,
     248           0 :                 mencloseRect.width, mRuleThickness);
     249           0 :     DisplayBar(aBuilder, this, rect, aLists);
     250             :   }
     251             : 
     252           0 :   if (IsToDraw(NOTATION_LEFT)) {
     253           0 :     nsRect rect(0, 0, mRuleThickness, mencloseRect.height);
     254           0 :     DisplayBar(aBuilder, this, rect, aLists);
     255             :   }
     256             : 
     257           0 :   if (IsToDraw(NOTATION_RIGHT)) {
     258           0 :     nsRect rect(mencloseRect.width - mRuleThickness, 0,
     259           0 :                 mRuleThickness, mencloseRect.height);
     260           0 :     DisplayBar(aBuilder, this, rect, aLists);
     261             :   }
     262             : 
     263           0 :   if (IsToDraw(NOTATION_ROUNDEDBOX)) {
     264           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     265           0 :                     mRuleThickness, NOTATION_ROUNDEDBOX);
     266             :   }
     267             : 
     268           0 :   if (IsToDraw(NOTATION_CIRCLE)) {
     269           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     270           0 :                     mRuleThickness, NOTATION_CIRCLE);
     271             :   }
     272             : 
     273           0 :   if (IsToDraw(NOTATION_UPDIAGONALSTRIKE)) {
     274           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     275           0 :                     mRuleThickness, NOTATION_UPDIAGONALSTRIKE);
     276             :   }
     277             : 
     278           0 :   if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
     279           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     280           0 :                     mRuleThickness, NOTATION_UPDIAGONALARROW);
     281             :   }
     282             : 
     283           0 :   if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE)) {
     284           0 :     DisplayNotation(aBuilder, this, mencloseRect, aLists,
     285           0 :                     mRuleThickness, NOTATION_DOWNDIAGONALSTRIKE);
     286             :   }
     287             : 
     288           0 :   if (IsToDraw(NOTATION_HORIZONTALSTRIKE)) {
     289           0 :     nsRect rect(0, mencloseRect.height / 2 - mRuleThickness / 2,
     290           0 :                 mencloseRect.width, mRuleThickness);
     291           0 :     DisplayBar(aBuilder, this, rect, aLists);
     292             :   }
     293             : 
     294           0 :   if (IsToDraw(NOTATION_VERTICALSTRIKE)) {
     295           0 :     nsRect rect(mencloseRect.width / 2 - mRuleThickness / 2, 0,
     296           0 :                 mRuleThickness, mencloseRect.height);
     297           0 :     DisplayBar(aBuilder, this, rect, aLists);
     298             :   }
     299             : }
     300             : 
     301             : /* virtual */ nsresult
     302           0 : nsMathMLmencloseFrame::MeasureForWidth(DrawTarget* aDrawTarget,
     303             :                                        ReflowOutput& aDesiredSize)
     304             : {
     305           0 :   return PlaceInternal(aDrawTarget, false, aDesiredSize, true);
     306             : }
     307             : 
     308             : /* virtual */ nsresult
     309           0 : nsMathMLmencloseFrame::Place(DrawTarget*          aDrawTarget,
     310             :                              bool                 aPlaceOrigin,
     311             :                              ReflowOutput& aDesiredSize)
     312             : {
     313           0 :   return PlaceInternal(aDrawTarget, aPlaceOrigin, aDesiredSize, false);
     314             : }
     315             : 
     316             : /* virtual */ nsresult
     317           0 : nsMathMLmencloseFrame::PlaceInternal(DrawTarget*          aDrawTarget,
     318             :                                      bool                 aPlaceOrigin,
     319             :                                      ReflowOutput& aDesiredSize,
     320             :                                      bool                 aWidthOnly)
     321             : {
     322             :   ///////////////
     323             :   // Measure the size of our content using the base class to format like an
     324             :   // inferred mrow.
     325           0 :   ReflowOutput baseSize(aDesiredSize.GetWritingMode());
     326             :   nsresult rv =
     327           0 :     nsMathMLContainerFrame::Place(aDrawTarget, false, baseSize);
     328             : 
     329           0 :   if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
     330           0 :       DidReflowChildren(PrincipalChildList().FirstChild());
     331           0 :       return rv;
     332             :     }
     333             : 
     334           0 :   nsBoundingMetrics bmBase = baseSize.mBoundingMetrics;
     335           0 :   nscoord dx_left = 0, dx_right = 0;
     336           0 :   nsBoundingMetrics bmLongdivChar, bmRadicalChar;
     337           0 :   nscoord radicalAscent = 0, radicalDescent = 0;
     338           0 :   nscoord longdivAscent = 0, longdivDescent = 0;
     339           0 :   nscoord psi = 0;
     340           0 :   nscoord leading = 0;
     341             : 
     342             :   ///////////////
     343             :   // Thickness of bars and font metrics
     344           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     345             : 
     346           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     347             :   RefPtr<nsFontMetrics> fm =
     348           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     349           0 :   GetRuleThickness(aDrawTarget, fm, mRuleThickness);
     350           0 :   if (mRuleThickness < onePixel) {
     351           0 :     mRuleThickness = onePixel;
     352             :   }
     353             : 
     354           0 :   char16_t one = '1';
     355             :   nsBoundingMetrics bmOne =
     356           0 :     nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, aDrawTarget);
     357             : 
     358             :   ///////////////
     359             :   // General rules: the menclose element takes the size of the enclosed content.
     360             :   // We add a padding when needed.
     361             : 
     362             :   // determine padding & psi
     363           0 :   nscoord padding = 3 * mRuleThickness;
     364           0 :   nscoord delta = padding % onePixel;
     365           0 :   if (delta)
     366           0 :     padding += onePixel - delta; // round up
     367             : 
     368           0 :   if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
     369           0 :     GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
     370             :                          NS_MATHML_DISPLAYSTYLE_BLOCK,
     371           0 :                          mRadicalRuleThickness, leading, psi);
     372             : 
     373             :     // make sure that the rule appears on on screen
     374           0 :     if (mRadicalRuleThickness < onePixel) {
     375           0 :       mRadicalRuleThickness = onePixel;
     376             :     }
     377             : 
     378             :     // adjust clearance psi to get an exact number of pixels -- this
     379             :     // gives a nicer & uniform look on stacked radicals (bug 130282)
     380           0 :     delta = psi % onePixel;
     381           0 :     if (delta) {
     382           0 :       psi += onePixel - delta; // round up
     383             :     }
     384             :   }
     385             : 
     386             :   // Set horizontal parameters
     387           0 :   if (IsToDraw(NOTATION_ROUNDEDBOX) ||
     388           0 :       IsToDraw(NOTATION_TOP) ||
     389           0 :       IsToDraw(NOTATION_LEFT) ||
     390           0 :       IsToDraw(NOTATION_BOTTOM) ||
     391           0 :       IsToDraw(NOTATION_CIRCLE))
     392           0 :     dx_left = padding;
     393             : 
     394           0 :   if (IsToDraw(NOTATION_ROUNDEDBOX) ||
     395           0 :       IsToDraw(NOTATION_TOP) ||
     396           0 :       IsToDraw(NOTATION_RIGHT) ||
     397           0 :       IsToDraw(NOTATION_BOTTOM) ||
     398           0 :       IsToDraw(NOTATION_CIRCLE))
     399           0 :     dx_right = padding;
     400             : 
     401             :   // Set vertical parameters
     402           0 :   if (IsToDraw(NOTATION_RIGHT) ||
     403           0 :       IsToDraw(NOTATION_LEFT) ||
     404           0 :       IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
     405           0 :       IsToDraw(NOTATION_UPDIAGONALARROW) ||
     406           0 :       IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
     407           0 :       IsToDraw(NOTATION_VERTICALSTRIKE) ||
     408           0 :       IsToDraw(NOTATION_CIRCLE) ||
     409           0 :       IsToDraw(NOTATION_ROUNDEDBOX) ||
     410           0 :       IsToDraw(NOTATION_RADICAL) ||
     411           0 :       IsToDraw(NOTATION_LONGDIV) ||
     412           0 :       IsToDraw(NOTATION_PHASORANGLE)) {
     413             :       // set a minimal value for the base height
     414           0 :       bmBase.ascent = std::max(bmOne.ascent, bmBase.ascent);
     415           0 :       bmBase.descent = std::max(0, bmBase.descent);
     416             :   }
     417             : 
     418           0 :   mBoundingMetrics.ascent = bmBase.ascent;
     419           0 :   mBoundingMetrics.descent = bmBase.descent;
     420             : 
     421           0 :   if (IsToDraw(NOTATION_ROUNDEDBOX) ||
     422           0 :       IsToDraw(NOTATION_TOP) ||
     423           0 :       IsToDraw(NOTATION_LEFT) ||
     424           0 :       IsToDraw(NOTATION_RIGHT) ||
     425           0 :       IsToDraw(NOTATION_CIRCLE))
     426           0 :     mBoundingMetrics.ascent += padding;
     427             : 
     428           0 :   if (IsToDraw(NOTATION_ROUNDEDBOX) ||
     429           0 :       IsToDraw(NOTATION_LEFT) ||
     430           0 :       IsToDraw(NOTATION_RIGHT) ||
     431           0 :       IsToDraw(NOTATION_BOTTOM) ||
     432           0 :       IsToDraw(NOTATION_CIRCLE))
     433           0 :     mBoundingMetrics.descent += padding;
     434             : 
     435             :    ///////////////
     436             :    // phasorangle notation
     437           0 :   if (IsToDraw(NOTATION_PHASORANGLE)) {
     438           0 :     nscoord phasorangleWidth = kPhasorangleWidth * mRuleThickness;
     439             :     // Update horizontal parameters
     440           0 :     dx_left = std::max(dx_left, phasorangleWidth);
     441             :   }
     442             : 
     443             :   ///////////////
     444             :   // updiagonal arrow notation. We need enough space at the top right corner to
     445             :   // draw the arrow head.
     446           0 :   if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
     447             :     // This is an estimate, see nsDisplayNotation::Paint for the exact head size
     448           0 :     nscoord arrowHeadSize = kArrowHeadSize * mRuleThickness;
     449             : 
     450             :     // We want that the arrow shaft strikes the menclose content and that the
     451             :     // arrow head does not overlap with that content. Hence we add some space
     452             :     // on the right. We don't add space on the top but only ensure that the
     453             :     // ascent is large enough.
     454           0 :     dx_right = std::max(dx_right, arrowHeadSize);
     455           0 :     mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, arrowHeadSize);
     456             :   }
     457             : 
     458             :   ///////////////
     459             :   // circle notation: we don't want the ellipse to overlap the enclosed
     460             :   // content. Hence, we need to increase the size of the bounding box by a
     461             :   // factor of at least sqrt(2).
     462           0 :   if (IsToDraw(NOTATION_CIRCLE)) {
     463           0 :     double ratio = (sqrt(2.0) - 1.0) / 2.0;
     464             :     nscoord padding2;
     465             : 
     466             :     // Update horizontal parameters
     467           0 :     padding2 = ratio * bmBase.width;
     468             : 
     469           0 :     dx_left = std::max(dx_left, padding2);
     470           0 :     dx_right = std::max(dx_right, padding2);
     471             : 
     472             :     // Update vertical parameters
     473           0 :     padding2 = ratio * (bmBase.ascent + bmBase.descent);
     474             : 
     475           0 :     mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
     476           0 :                                      bmBase.ascent + padding2);
     477           0 :     mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
     478           0 :                                       bmBase.descent + padding2);
     479             :   }
     480             : 
     481             :   ///////////////
     482             :   // longdiv notation:
     483           0 :   if (IsToDraw(NOTATION_LONGDIV)) {
     484           0 :     if (aWidthOnly) {
     485           0 :         nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].
     486           0 :           GetMaxWidth(PresContext(), aDrawTarget, fontSizeInflation);
     487             : 
     488             :         // Update horizontal parameters
     489           0 :         dx_left = std::max(dx_left, longdiv_width);
     490             :     } else {
     491             :       // Stretch the parenthesis to the appropriate height if it is not
     492             :       // big enough.
     493           0 :       nsBoundingMetrics contSize = bmBase;
     494           0 :       contSize.ascent = mRuleThickness;
     495           0 :       contSize.descent = bmBase.ascent + bmBase.descent + psi;
     496             : 
     497             :       // height(longdiv) should be >= height(base) + psi + mRuleThickness
     498           0 :       mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aDrawTarget,
     499             :                                              fontSizeInflation,
     500             :                                              NS_STRETCH_DIRECTION_VERTICAL,
     501             :                                              contSize, bmLongdivChar,
     502           0 :                                              NS_STRETCH_LARGER, false);
     503           0 :       mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar);
     504             : 
     505             :       // Update horizontal parameters
     506           0 :       dx_left = std::max(dx_left, bmLongdivChar.width);
     507             : 
     508             :       // Update vertical parameters
     509           0 :       longdivAscent = bmBase.ascent + psi + mRuleThickness;
     510           0 :       longdivDescent = std::max(bmBase.descent,
     511           0 :                               (bmLongdivChar.ascent + bmLongdivChar.descent -
     512           0 :                                longdivAscent));
     513             : 
     514           0 :       mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
     515           0 :                                        longdivAscent);
     516           0 :       mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
     517           0 :                                         longdivDescent);
     518             :     }
     519             :   }
     520             : 
     521             :   ///////////////
     522             :   // radical notation:
     523           0 :   if (IsToDraw(NOTATION_RADICAL)) {
     524           0 :     nscoord *dx_leading = StyleVisibility()->mDirection ? &dx_right : &dx_left;
     525             : 
     526           0 :     if (aWidthOnly) {
     527           0 :       nscoord radical_width = mMathMLChar[mRadicalCharIndex].
     528           0 :         GetMaxWidth(PresContext(), aDrawTarget, fontSizeInflation);
     529             : 
     530             :       // Update horizontal parameters
     531           0 :       *dx_leading = std::max(*dx_leading, radical_width);
     532             :     } else {
     533             :       // Stretch the radical symbol to the appropriate height if it is not
     534             :       // big enough.
     535           0 :       nsBoundingMetrics contSize = bmBase;
     536           0 :       contSize.ascent = mRadicalRuleThickness;
     537           0 :       contSize.descent = bmBase.ascent + bmBase.descent + psi;
     538             : 
     539             :       // height(radical) should be >= height(base) + psi + mRadicalRuleThickness
     540           0 :       mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aDrawTarget,
     541             :                                              fontSizeInflation,
     542             :                                              NS_STRETCH_DIRECTION_VERTICAL,
     543             :                                              contSize, bmRadicalChar,
     544             :                                              NS_STRETCH_LARGER,
     545           0 :                                              StyleVisibility()->mDirection);
     546           0 :       mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar);
     547             : 
     548             :       // Update horizontal parameters
     549           0 :       *dx_leading = std::max(*dx_leading, bmRadicalChar.width);
     550             : 
     551             :       // Update vertical parameters
     552           0 :       radicalAscent = bmBase.ascent + psi + mRadicalRuleThickness;
     553           0 :       radicalDescent = std::max(bmBase.descent,
     554           0 :                               (bmRadicalChar.ascent + bmRadicalChar.descent -
     555           0 :                                radicalAscent));
     556             : 
     557           0 :       mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
     558           0 :                                        radicalAscent);
     559           0 :       mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
     560           0 :                                         radicalDescent);
     561             :     }
     562             :   }
     563             : 
     564             :   ///////////////
     565             :   //
     566           0 :   if (IsToDraw(NOTATION_CIRCLE) ||
     567           0 :       IsToDraw(NOTATION_ROUNDEDBOX) ||
     568           0 :       (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) {
     569             :     // center the menclose around the content (horizontally)
     570           0 :     dx_left = dx_right = std::max(dx_left, dx_right);
     571             :   }
     572             : 
     573             :   ///////////////
     574             :   // The maximum size is now computed: set the remaining parameters
     575           0 :   mBoundingMetrics.width = dx_left + bmBase.width + dx_right;
     576             : 
     577           0 :   mBoundingMetrics.leftBearing = std::min(0, dx_left + bmBase.leftBearing);
     578           0 :   mBoundingMetrics.rightBearing =
     579           0 :     std::max(mBoundingMetrics.width, dx_left + bmBase.rightBearing);
     580             : 
     581           0 :   aDesiredSize.Width() = mBoundingMetrics.width;
     582             : 
     583           0 :   aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent,
     584           0 :                                             baseSize.BlockStartAscent()));
     585           0 :   aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     586           0 :     std::max(mBoundingMetrics.descent,
     587           0 :              baseSize.Height() - baseSize.BlockStartAscent());
     588             : 
     589           0 :   if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
     590           0 :     nscoord desiredSizeAscent = aDesiredSize.BlockStartAscent();
     591           0 :     nscoord desiredSizeDescent = aDesiredSize.Height() -
     592           0 :                                  aDesiredSize.BlockStartAscent();
     593             : 
     594           0 :     if (IsToDraw(NOTATION_LONGDIV)) {
     595           0 :       desiredSizeAscent = std::max(desiredSizeAscent,
     596           0 :                                  longdivAscent + leading);
     597           0 :       desiredSizeDescent = std::max(desiredSizeDescent,
     598           0 :                                   longdivDescent + mRuleThickness);
     599             :     }
     600             : 
     601           0 :     if (IsToDraw(NOTATION_RADICAL)) {
     602           0 :       desiredSizeAscent = std::max(desiredSizeAscent,
     603           0 :                                  radicalAscent + leading);
     604           0 :       desiredSizeDescent = std::max(desiredSizeDescent,
     605           0 :                                     radicalDescent + mRadicalRuleThickness);
     606             :     }
     607             : 
     608           0 :     aDesiredSize.SetBlockStartAscent(desiredSizeAscent);
     609           0 :     aDesiredSize.Height() = desiredSizeAscent + desiredSizeDescent;
     610             :   }
     611             : 
     612           0 :   if (IsToDraw(NOTATION_CIRCLE) ||
     613           0 :       IsToDraw(NOTATION_ROUNDEDBOX) ||
     614           0 :       (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) {
     615             :     // center the menclose around the content (vertically)
     616           0 :     nscoord dy = std::max(aDesiredSize.BlockStartAscent() - bmBase.ascent,
     617           0 :                           aDesiredSize.Height() -
     618           0 :                           aDesiredSize.BlockStartAscent() - bmBase.descent);
     619             : 
     620           0 :     aDesiredSize.SetBlockStartAscent(bmBase.ascent + dy);
     621           0 :     aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + bmBase.descent + dy;
     622             :   }
     623             : 
     624             :   // Update mBoundingMetrics ascent/descent
     625           0 :   if (IsToDraw(NOTATION_TOP) ||
     626           0 :       IsToDraw(NOTATION_RIGHT) ||
     627           0 :       IsToDraw(NOTATION_LEFT) ||
     628           0 :       IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
     629           0 :       IsToDraw(NOTATION_UPDIAGONALARROW) ||
     630           0 :       IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
     631           0 :       IsToDraw(NOTATION_VERTICALSTRIKE) ||
     632           0 :       IsToDraw(NOTATION_CIRCLE) ||
     633           0 :       IsToDraw(NOTATION_ROUNDEDBOX))
     634           0 :     mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
     635             : 
     636           0 :   if (IsToDraw(NOTATION_BOTTOM) ||
     637           0 :       IsToDraw(NOTATION_RIGHT) ||
     638           0 :       IsToDraw(NOTATION_LEFT) ||
     639           0 :       IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
     640           0 :       IsToDraw(NOTATION_UPDIAGONALARROW) ||
     641           0 :       IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
     642           0 :       IsToDraw(NOTATION_VERTICALSTRIKE) ||
     643           0 :       IsToDraw(NOTATION_CIRCLE) ||
     644           0 :       IsToDraw(NOTATION_ROUNDEDBOX))
     645           0 :     mBoundingMetrics.descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent();
     646             : 
     647             :   // phasorangle notation:
     648             :   // move up from the bottom by the angled line height
     649           0 :   if (IsToDraw(NOTATION_PHASORANGLE))
     650           0 :     mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, 2 * kPhasorangleWidth * mRuleThickness - mBoundingMetrics.descent);
     651             : 
     652           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     653             : 
     654           0 :   mReference.x = 0;
     655           0 :   mReference.y = aDesiredSize.BlockStartAscent();
     656             : 
     657           0 :   if (aPlaceOrigin) {
     658             :     //////////////////
     659             :     // Set position and size of MathMLChars
     660           0 :     if (IsToDraw(NOTATION_LONGDIV))
     661           0 :       mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left -
     662           0 :                                                     bmLongdivChar.width,
     663           0 :                                                     aDesiredSize.BlockStartAscent() -
     664             :                                                     longdivAscent,
     665             :                                                     bmLongdivChar.width,
     666           0 :                                                     bmLongdivChar.ascent +
     667           0 :                                                     bmLongdivChar.descent));
     668             : 
     669           0 :     if (IsToDraw(NOTATION_RADICAL)) {
     670           0 :       nscoord dx = (StyleVisibility()->mDirection ?
     671           0 :                     dx_left + bmBase.width : dx_left - bmRadicalChar.width);
     672             : 
     673           0 :       mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx,
     674           0 :                                                     aDesiredSize.BlockStartAscent() -
     675             :                                                     radicalAscent,
     676             :                                                     bmRadicalChar.width,
     677           0 :                                                     bmRadicalChar.ascent +
     678           0 :                                                     bmRadicalChar.descent));
     679             :     }
     680             : 
     681           0 :     mContentWidth = bmBase.width;
     682             : 
     683             :     //////////////////
     684             :     // Finish reflowing child frames
     685           0 :     PositionRowChildFrames(dx_left, aDesiredSize.BlockStartAscent());
     686             :   }
     687             : 
     688           0 :   return NS_OK;
     689             : }
     690             : 
     691             : nscoord
     692           0 : nsMathMLmencloseFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
     693             : {
     694           0 :   nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
     695           0 :   if (!gap)
     696           0 :     return 0;
     697             : 
     698             :   // Move the MathML characters
     699           0 :   nsRect rect;
     700           0 :   for (uint32_t i = 0; i < mMathMLChar.Length(); i++) {
     701           0 :     mMathMLChar[i].GetRect(rect);
     702           0 :     rect.MoveBy(gap, 0);
     703           0 :     mMathMLChar[i].SetRect(rect);
     704             :   }
     705             : 
     706           0 :   return gap;
     707             : }
     708             : 
     709             : nsresult
     710           0 : nsMathMLmencloseFrame::AttributeChanged(int32_t         aNameSpaceID,
     711             :                                         nsIAtom*        aAttribute,
     712             :                                         int32_t         aModType)
     713             : {
     714           0 :   if (aAttribute == nsGkAtoms::notation_) {
     715           0 :     InitNotations();
     716             :   }
     717             : 
     718             :   return nsMathMLContainerFrame::
     719           0 :     AttributeChanged(aNameSpaceID, aAttribute, aModType);
     720             : }
     721             : 
     722             : //////////////////
     723             : // the Style System will use these to pass the proper style context to our
     724             : // MathMLChar
     725             : nsStyleContext*
     726           0 : nsMathMLmencloseFrame::GetAdditionalStyleContext(int32_t aIndex) const
     727             : {
     728           0 :   int32_t len = mMathMLChar.Length();
     729           0 :   if (aIndex >= 0 && aIndex < len)
     730           0 :     return mMathMLChar[aIndex].GetStyleContext();
     731             :   else
     732           0 :     return nullptr;
     733             : }
     734             : 
     735             : void
     736           0 : nsMathMLmencloseFrame::SetAdditionalStyleContext(int32_t          aIndex,
     737             :                                                  nsStyleContext*  aStyleContext)
     738             : {
     739           0 :   int32_t len = mMathMLChar.Length();
     740           0 :   if (aIndex >= 0 && aIndex < len)
     741           0 :     mMathMLChar[aIndex].SetStyleContext(aStyleContext);
     742           0 : }
     743             : 
     744             : class nsDisplayNotation : public nsDisplayItem
     745             : {
     746             : public:
     747           0 :   nsDisplayNotation(nsDisplayListBuilder* aBuilder,
     748             :                     nsIFrame* aFrame, const nsRect& aRect,
     749             :                     nscoord aThickness, nsMencloseNotation aType)
     750           0 :     : nsDisplayItem(aBuilder, aFrame), mRect(aRect),
     751           0 :       mThickness(aThickness), mType(aType) {
     752           0 :     MOZ_COUNT_CTOR(nsDisplayNotation);
     753           0 :   }
     754             : #ifdef NS_BUILD_REFCNT_LOGGING
     755           0 :   virtual ~nsDisplayNotation() {
     756           0 :     MOZ_COUNT_DTOR(nsDisplayNotation);
     757           0 :   }
     758             : #endif
     759             : 
     760             :   virtual void Paint(nsDisplayListBuilder* aBuilder,
     761             :                      gfxContext* aCtx) override;
     762           0 :   NS_DISPLAY_DECL_NAME("MathMLMencloseNotation", TYPE_MATHML_MENCLOSE_NOTATION)
     763             : 
     764             : private:
     765             :   nsRect             mRect;
     766             :   nscoord            mThickness;
     767             :   nsMencloseNotation mType;
     768             : };
     769             : 
     770           0 : void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
     771             :                               gfxContext* aCtx)
     772             : {
     773           0 :   DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
     774           0 :   nsPresContext* presContext = mFrame->PresContext();
     775             : 
     776           0 :   Float strokeWidth = presContext->AppUnitsToGfxUnits(mThickness);
     777             : 
     778           0 :   Rect rect = NSRectToRect(mRect + ToReferenceFrame(),
     779           0 :                            presContext->AppUnitsPerDevPixel());
     780           0 :   rect.Deflate(strokeWidth / 2.f);
     781             : 
     782           0 :   ColorPattern color(ToDeviceColor(
     783           0 :     mFrame->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor)));
     784             : 
     785           0 :   StrokeOptions strokeOptions(strokeWidth);
     786             : 
     787           0 :   switch(mType)
     788             :   {
     789             :     case NOTATION_CIRCLE: {
     790             :       RefPtr<Path> ellipse =
     791           0 :         MakePathForEllipse(aDrawTarget, rect.Center(), rect.Size());
     792           0 :       aDrawTarget.Stroke(ellipse, color, strokeOptions);
     793           0 :       return;
     794             :     }
     795             :     case NOTATION_ROUNDEDBOX: {
     796           0 :       Float radius = 3 * strokeWidth;
     797           0 :       RectCornerRadii radii(radius, radius);
     798             :       RefPtr<Path> roundedRect =
     799           0 :         MakePathForRoundedRect(aDrawTarget, rect, radii, true);
     800           0 :       aDrawTarget.Stroke(roundedRect, color, strokeOptions);
     801           0 :       return;
     802             :     }
     803             :     case NOTATION_UPDIAGONALSTRIKE: {
     804           0 :       aDrawTarget.StrokeLine(rect.BottomLeft(), rect.TopRight(),
     805           0 :                              color, strokeOptions);
     806           0 :       return;
     807             :     }
     808             :     case NOTATION_DOWNDIAGONALSTRIKE: {
     809           0 :       aDrawTarget.StrokeLine(rect.TopLeft(), rect.BottomRight(),
     810           0 :                              color, strokeOptions);
     811           0 :       return;
     812             :     }
     813             :     case NOTATION_UPDIAGONALARROW: {
     814             :       // Compute some parameters to draw the updiagonalarrow. The values below
     815             :       // are taken from MathJax's HTML-CSS output.
     816           0 :       Float W = rect.Width(); gfxFloat H = rect.Height();
     817           0 :       Float l = sqrt(W*W + H*H);
     818           0 :       Float f = Float(kArrowHeadSize) * strokeWidth / l;
     819           0 :       Float w = W * f; gfxFloat h = H * f;
     820             : 
     821             :       // Draw the arrow shaft
     822           0 :       aDrawTarget.StrokeLine(rect.BottomLeft(),
     823           0 :                              rect.TopRight() + Point(-.7*w, .7*h),
     824           0 :                              color, strokeOptions);
     825             : 
     826             :       // Draw the arrow head
     827           0 :       RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
     828           0 :       builder->MoveTo(rect.TopRight());
     829           0 :       builder->LineTo(rect.TopRight() + Point(-w -.4*h, std::max(-strokeWidth / 2.0, h - .4*w)));
     830           0 :       builder->LineTo(rect.TopRight() + Point(-.7*w, .7*h));
     831           0 :       builder->LineTo(rect.TopRight() + Point(std::min(strokeWidth / 2.0, -w + .4*h), h + .4*w));
     832           0 :       builder->Close();
     833           0 :       RefPtr<Path> path = builder->Finish();
     834           0 :       aDrawTarget.Fill(path, color);
     835           0 :       return;
     836             :     }
     837             :     case NOTATION_PHASORANGLE: {
     838             :       // Compute some parameters to draw the angled line,
     839             :       // that uses a slope of 2 (angle = tan^-1(2)).
     840             :       // H = w * tan(angle) = w * 2
     841           0 :       Float w = Float(kPhasorangleWidth) * strokeWidth;
     842           0 :       Float H = 2 * w;
     843             : 
     844             :       // Draw the angled line
     845           0 :       aDrawTarget.StrokeLine(rect.BottomLeft(),
     846           0 :                              rect.BottomLeft() + Point(w, -H),
     847           0 :                              color, strokeOptions);
     848           0 :       return;
     849             :     }
     850             :     default:
     851           0 :       NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation");
     852             :   }
     853             : }
     854             : 
     855             : void
     856           0 : nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder* aBuilder,
     857             :                                        nsIFrame* aFrame, const nsRect& aRect,
     858             :                                        const nsDisplayListSet& aLists,
     859             :                                        nscoord aThickness,
     860             :                                        nsMencloseNotation aType)
     861             : {
     862           0 :   if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty() ||
     863             :       aThickness <= 0)
     864           0 :     return;
     865             : 
     866           0 :   aLists.Content()->AppendNewToTop(new (aBuilder)
     867           0 :     nsDisplayNotation(aBuilder, aFrame, aRect, aThickness, aType));
     868             : }

Generated by: LCOV version 1.13