LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmrootFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 212 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 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 "nsMathMLmrootFrame.h"
       7             : #include "nsPresContext.h"
       8             : #include <algorithm>
       9             : #include "gfxContext.h"
      10             : #include "gfxMathTable.h"
      11             : 
      12             : using namespace mozilla;
      13             : 
      14             : //
      15             : // <mroot> -- form a radical - implementation
      16             : //
      17             : 
      18             : // additional style context to be used by our MathMLChar.
      19             : #define NS_SQR_CHAR_STYLE_CONTEXT_INDEX   0
      20             : 
      21             : static const char16_t kSqrChar = char16_t(0x221A);
      22             : 
      23             : nsIFrame*
      24           0 : NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      25             : {
      26           0 :   return new (aPresShell) nsMathMLmrootFrame(aContext);
      27             : }
      28             : 
      29           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmrootFrame)
      30             : 
      31           0 : nsMathMLmrootFrame::nsMathMLmrootFrame(nsStyleContext* aContext) :
      32             :   nsMathMLContainerFrame(aContext, kClassID),
      33             :   mSqrChar(),
      34           0 :   mBarRect()
      35             : {
      36           0 : }
      37             : 
      38           0 : nsMathMLmrootFrame::~nsMathMLmrootFrame()
      39             : {
      40           0 : }
      41             : 
      42             : void
      43           0 : nsMathMLmrootFrame::Init(nsIContent*       aContent,
      44             :                          nsContainerFrame* aParent,
      45             :                          nsIFrame*         aPrevInFlow)
      46             : {
      47           0 :   nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
      48             : 
      49           0 :   nsPresContext *presContext = PresContext();
      50             : 
      51             :   // No need to track the style context given to our MathML char.
      52             :   // The Style System will use Get/SetAdditionalStyleContext() to keep it
      53             :   // up-to-date if dynamic changes arise.
      54           0 :   nsAutoString sqrChar; sqrChar.Assign(kSqrChar);
      55           0 :   mSqrChar.SetData(sqrChar);
      56           0 :   ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mSqrChar);
      57           0 : }
      58             : 
      59             : NS_IMETHODIMP
      60           0 : nsMathMLmrootFrame::TransmitAutomaticData()
      61             : {
      62             :   // 1. The REC says:
      63             :   //    The <mroot> element increments scriptlevel by 2, and sets displaystyle to
      64             :   //    "false", within index, but leaves both attributes unchanged within base.
      65             :   // 2. The TeXbook (Ch 17. p.141) says \sqrt is compressed
      66           0 :   UpdatePresentationDataFromChildAt(1, 1,
      67             :                                     NS_MATHML_COMPRESSED,
      68           0 :                                     NS_MATHML_COMPRESSED);
      69           0 :   UpdatePresentationDataFromChildAt(0, 0,
      70           0 :      NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED);
      71             : 
      72           0 :   PropagateFrameFlagFor(mFrames.LastChild(),
      73           0 :                         NS_FRAME_MATHML_SCRIPT_DESCENDANT);
      74             : 
      75           0 :   return NS_OK;
      76             : }
      77             : 
      78             : void
      79           0 : nsMathMLmrootFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
      80             :                                      const nsRect&           aDirtyRect,
      81             :                                      const nsDisplayListSet& aLists)
      82             : {
      83             :   /////////////
      84             :   // paint the content we are square-rooting
      85           0 :   nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
      86             : 
      87             :   /////////////
      88             :   // paint the sqrt symbol
      89           0 :   if (!NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
      90           0 :     mSqrChar.Display(aBuilder, this, aLists, 0);
      91             : 
      92           0 :     DisplayBar(aBuilder, this, mBarRect, aLists);
      93             : 
      94             : #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
      95             :     // for visual debug
      96             :     nsRect rect;
      97             :     mSqrChar.GetRect(rect);
      98             :     nsBoundingMetrics bm;
      99             :     mSqrChar.GetBoundingMetrics(bm);
     100             :     DisplayBoundingMetrics(aBuilder, this, rect.TopLeft(), bm, aLists);
     101             : #endif
     102             :   }
     103           0 : }
     104             : 
     105             : void
     106           0 : nsMathMLmrootFrame::GetRadicalXOffsets(nscoord aIndexWidth, nscoord aSqrWidth,
     107             :                                        nsFontMetrics* aFontMetrics,
     108             :                                        nscoord* aIndexOffset,
     109             :                                        nscoord* aSqrOffset)
     110             : {
     111             :   // The index is tucked in closer to the radical while making sure
     112             :   // that the kern does not make the index and radical collide
     113             :   nscoord dxIndex, dxSqr;
     114           0 :   nscoord xHeight = aFontMetrics->XHeight();
     115           0 :   nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight);
     116           0 :   nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
     117           0 :   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
     118           0 :   if (mathFont) {
     119             :     indexRadicalKern =
     120           0 :       mathFont->MathTable()->Constant(gfxMathTable::RadicalKernAfterDegree,
     121           0 :                                       oneDevPixel);
     122           0 :     indexRadicalKern = -indexRadicalKern;
     123             :   }
     124           0 :   if (indexRadicalKern > aIndexWidth) {
     125           0 :     dxIndex = indexRadicalKern - aIndexWidth;
     126           0 :     dxSqr = 0;
     127             :   }
     128             :   else {
     129           0 :     dxIndex = 0;
     130           0 :     dxSqr = aIndexWidth - indexRadicalKern;
     131             :   }
     132             : 
     133           0 :   if (mathFont) {
     134             :     // add some kern before the radical index
     135           0 :     nscoord indexRadicalKernBefore = 0;
     136             :     indexRadicalKernBefore =
     137           0 :       mathFont->MathTable()->Constant(gfxMathTable::RadicalKernBeforeDegree,
     138           0 :                                       oneDevPixel);
     139           0 :     dxIndex += indexRadicalKernBefore;
     140           0 :     dxSqr += indexRadicalKernBefore;
     141             :   } else {
     142             :     // avoid collision by leaving a minimum space between index and radical
     143           0 :     nscoord minimumClearance = aSqrWidth / 2;
     144           0 :     if (dxIndex + aIndexWidth + minimumClearance > dxSqr + aSqrWidth) {
     145           0 :       if (aIndexWidth + minimumClearance < aSqrWidth) {
     146           0 :         dxIndex = aSqrWidth - (aIndexWidth + minimumClearance);
     147           0 :         dxSqr = 0;
     148             :       }
     149             :       else {
     150           0 :         dxIndex = 0;
     151           0 :         dxSqr = (aIndexWidth + minimumClearance) - aSqrWidth;
     152             :       }
     153             :     }
     154             :   }
     155             : 
     156           0 :   if (aIndexOffset)
     157           0 :     *aIndexOffset = dxIndex;
     158           0 :   if (aSqrOffset)
     159           0 :     *aSqrOffset = dxSqr;
     160           0 : }
     161             : 
     162             : void
     163           0 : nsMathMLmrootFrame::Reflow(nsPresContext*          aPresContext,
     164             :                            ReflowOutput&     aDesiredSize,
     165             :                            const ReflowInput& aReflowInput,
     166             :                            nsReflowStatus&          aStatus)
     167             : {
     168           0 :   MarkInReflow();
     169           0 :   nsReflowStatus childStatus;
     170             : 
     171           0 :   mPresentationData.flags &= ~NS_MATHML_ERROR;
     172           0 :   aDesiredSize.ClearSize();
     173           0 :   aDesiredSize.SetBlockStartAscent(0);
     174             : 
     175           0 :   nsBoundingMetrics bmSqr, bmBase, bmIndex;
     176           0 :   DrawTarget* drawTarget = aReflowInput.mRenderingContext->GetDrawTarget();
     177             : 
     178             :   //////////////////
     179             :   // Reflow Children
     180             : 
     181           0 :   int32_t count = 0;
     182           0 :   nsIFrame* baseFrame = nullptr;
     183           0 :   nsIFrame* indexFrame = nullptr;
     184           0 :   ReflowOutput baseSize(aReflowInput);
     185           0 :   ReflowOutput indexSize(aReflowInput);
     186           0 :   nsIFrame* childFrame = mFrames.FirstChild();
     187           0 :   while (childFrame) {
     188             :     // ask our children to compute their bounding metrics
     189             :     ReflowOutput childDesiredSize(aReflowInput,
     190           0 :                                          aDesiredSize.mFlags
     191           0 :                                          | NS_REFLOW_CALC_BOUNDING_METRICS);
     192           0 :     WritingMode wm = childFrame->GetWritingMode();
     193           0 :     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     194           0 :     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     195             :     ReflowInput childReflowInput(aPresContext, aReflowInput,
     196           0 :                                        childFrame, availSize);
     197           0 :     ReflowChild(childFrame, aPresContext,
     198           0 :                      childDesiredSize, childReflowInput, childStatus);
     199             :     //NS_ASSERTION(childStatus.IsComplete(), "bad status");
     200           0 :     if (0 == count) {
     201             :       // base
     202           0 :       baseFrame = childFrame;
     203           0 :       baseSize = childDesiredSize;
     204           0 :       bmBase = childDesiredSize.mBoundingMetrics;
     205             :     }
     206           0 :     else if (1 == count) {
     207             :       // index
     208           0 :       indexFrame = childFrame;
     209           0 :       indexSize = childDesiredSize;
     210           0 :       bmIndex = childDesiredSize.mBoundingMetrics;
     211             :     }
     212           0 :     count++;
     213           0 :     childFrame = childFrame->GetNextSibling();
     214             :   }
     215           0 :   if (2 != count) {
     216             :     // report an error, encourage people to get their markups in order
     217           0 :     ReportChildCountError();
     218           0 :     ReflowError(drawTarget, aDesiredSize);
     219           0 :     aStatus.Reset();
     220           0 :     NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
     221             :     // Call DidReflow() for the child frames we successfully did reflow.
     222           0 :     DidReflowChildren(mFrames.FirstChild(), childFrame);
     223           0 :     return;
     224             :   }
     225             : 
     226             :   ////////////
     227             :   // Prepare the radical symbol and the overline bar
     228             : 
     229           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     230             :   RefPtr<nsFontMetrics> fm =
     231           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     232             : 
     233             :   nscoord ruleThickness, leading, psi;
     234           0 :   GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
     235             :                        NS_MATHML_DISPLAYSTYLE_BLOCK,
     236           0 :                        ruleThickness, leading, psi);
     237             : 
     238             :   // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
     239           0 :   char16_t one = '1';
     240             :   nsBoundingMetrics bmOne =
     241           0 :     nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, drawTarget);
     242           0 :   if (bmOne.ascent > bmBase.ascent)
     243           0 :     psi += bmOne.ascent - bmBase.ascent;
     244             : 
     245             :   // make sure that the rule appears on on screen
     246           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
     247           0 :   if (ruleThickness < onePixel) {
     248           0 :     ruleThickness = onePixel;
     249             :   }
     250             : 
     251             :   // adjust clearance psi to get an exact number of pixels -- this
     252             :   // gives a nicer & uniform look on stacked radicals (bug 130282)
     253           0 :   nscoord delta = psi % onePixel;
     254           0 :   if (delta)
     255           0 :     psi += onePixel - delta; // round up
     256             : 
     257             :   // Stretch the radical symbol to the appropriate height if it is not big enough.
     258           0 :   nsBoundingMetrics contSize = bmBase;
     259           0 :   contSize.descent = bmBase.ascent + bmBase.descent + psi;
     260           0 :   contSize.ascent = ruleThickness;
     261             : 
     262             :   // height(radical) should be >= height(base) + psi + ruleThickness
     263           0 :   nsBoundingMetrics radicalSize;
     264           0 :   mSqrChar.Stretch(aPresContext, drawTarget,
     265             :                    fontSizeInflation,
     266             :                    NS_STRETCH_DIRECTION_VERTICAL,
     267             :                    contSize, radicalSize,
     268             :                    NS_STRETCH_LARGER,
     269           0 :                    StyleVisibility()->mDirection);
     270             :   // radicalSize have changed at this point, and should match with
     271             :   // the bounding metrics of the char
     272           0 :   mSqrChar.GetBoundingMetrics(bmSqr);
     273             : 
     274             :   // Update the desired size for the container (like msqrt, index is not yet included)
     275             :   // the baseline will be that of the base.
     276           0 :   mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness;
     277           0 :   mBoundingMetrics.descent =
     278           0 :     std::max(bmBase.descent,
     279           0 :            (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent));
     280           0 :   mBoundingMetrics.width = bmSqr.width + bmBase.width;
     281           0 :   mBoundingMetrics.leftBearing = bmSqr.leftBearing;
     282           0 :   mBoundingMetrics.rightBearing = bmSqr.width +
     283           0 :     std::max(bmBase.width, bmBase.rightBearing); // take also care of the rule
     284             : 
     285           0 :   aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
     286           0 :   aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     287           0 :     std::max(baseSize.Height() - baseSize.BlockStartAscent(),
     288           0 :              mBoundingMetrics.descent + ruleThickness);
     289           0 :   aDesiredSize.Width() = mBoundingMetrics.width;
     290             : 
     291             :   /////////////
     292             :   // Re-adjust the desired size to include the index.
     293             : 
     294             :   // the index is raised by some fraction of the height
     295             :   // of the radical, see \mroot macro in App. B, TexBook
     296           0 :   float raiseIndexPercent = 0.6f;
     297           0 :   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
     298           0 :   if (mathFont) {
     299           0 :     raiseIndexPercent = mathFont->MathTable()->
     300           0 :       Constant(gfxMathTable::RadicalDegreeBottomRaisePercent);
     301             :   }
     302           0 :   nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent *
     303           0 :                                            (bmSqr.ascent + bmSqr.descent));
     304           0 :   nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical
     305           0 :     - (bmSqr.ascent + bmSqr.descent) // to bottom of radical
     306           0 :     + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index
     307             : 
     308           0 :   nscoord indexClearance = 0;
     309           0 :   if (mBoundingMetrics.ascent < indexRaisedAscent) {
     310           0 :     indexClearance =
     311           0 :       indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index
     312           0 :     mBoundingMetrics.ascent = indexRaisedAscent;
     313           0 :     nscoord descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent();
     314           0 :     aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
     315           0 :     aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + descent;
     316             :   }
     317             : 
     318             :   nscoord dxIndex, dxSqr;
     319           0 :   GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr);
     320             : 
     321           0 :   mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width;
     322           0 :   mBoundingMetrics.leftBearing =
     323           0 :     std::min(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing);
     324           0 :   mBoundingMetrics.rightBearing = dxSqr + bmSqr.width +
     325           0 :     std::max(bmBase.width, bmBase.rightBearing);
     326             : 
     327           0 :   aDesiredSize.Width() = mBoundingMetrics.width;
     328           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     329           0 :   GatherAndStoreOverflow(&aDesiredSize);
     330             : 
     331             :   // place the index
     332           0 :   nscoord dx = dxIndex;
     333           0 :   nscoord dy = aDesiredSize.BlockStartAscent() -
     334           0 :     (indexRaisedAscent + indexSize.BlockStartAscent() - bmIndex.ascent);
     335           0 :   FinishReflowChild(indexFrame, aPresContext, indexSize, nullptr,
     336           0 :                     MirrorIfRTL(aDesiredSize.Width(), indexSize.Width(), dx),
     337           0 :                     dy, 0);
     338             : 
     339             :   // place the radical symbol and the radical bar
     340           0 :   dx = dxSqr;
     341           0 :   dy = indexClearance + leading; // leave a leading at the top
     342           0 :   mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.Width(), bmSqr.width, dx),
     343           0 :                           dy, bmSqr.width, bmSqr.ascent + bmSqr.descent));
     344           0 :   dx += bmSqr.width;
     345           0 :   mBarRect.SetRect(MirrorIfRTL(aDesiredSize.Width(), bmBase.width, dx),
     346           0 :                    dy, bmBase.width, ruleThickness);
     347             : 
     348             :   // place the base
     349           0 :   dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
     350           0 :   FinishReflowChild(baseFrame, aPresContext, baseSize, nullptr,
     351           0 :                     MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx),
     352           0 :                     dy, 0);
     353             : 
     354           0 :   mReference.x = 0;
     355           0 :   mReference.y = aDesiredSize.BlockStartAscent();
     356             : 
     357           0 :   aStatus.Reset();
     358           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
     359             : }
     360             : 
     361             : /* virtual */ void
     362           0 : nsMathMLmrootFrame::GetIntrinsicISizeMetrics(gfxContext* aRenderingContext, ReflowOutput& aDesiredSize)
     363             : {
     364           0 :   nsIFrame* baseFrame = mFrames.FirstChild();
     365           0 :   nsIFrame* indexFrame = nullptr;
     366           0 :   if (baseFrame)
     367           0 :     indexFrame = baseFrame->GetNextSibling();
     368           0 :   if (!indexFrame || indexFrame->GetNextSibling()) {
     369           0 :     ReflowError(aRenderingContext->GetDrawTarget(), aDesiredSize);
     370           0 :     return;
     371             :   }
     372             : 
     373           0 :   float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
     374             :   nscoord baseWidth =
     375             :     nsLayoutUtils::IntrinsicForContainer(aRenderingContext, baseFrame,
     376           0 :                                          nsLayoutUtils::PREF_ISIZE);
     377             :   nscoord indexWidth =
     378             :     nsLayoutUtils::IntrinsicForContainer(aRenderingContext, indexFrame,
     379           0 :                                          nsLayoutUtils::PREF_ISIZE);
     380           0 :   nscoord sqrWidth = mSqrChar.GetMaxWidth(PresContext(),
     381             :                                           aRenderingContext->GetDrawTarget(),
     382           0 :                                           fontSizeInflation);
     383             : 
     384             :   nscoord dxSqr;
     385             :   RefPtr<nsFontMetrics> fm =
     386           0 :     nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
     387           0 :   GetRadicalXOffsets(indexWidth, sqrWidth, fm, nullptr, &dxSqr);
     388             : 
     389           0 :   nscoord width = dxSqr + sqrWidth + baseWidth;
     390             : 
     391           0 :   aDesiredSize.Width() = width;
     392           0 :   aDesiredSize.mBoundingMetrics.width = width;
     393           0 :   aDesiredSize.mBoundingMetrics.leftBearing = 0;
     394           0 :   aDesiredSize.mBoundingMetrics.rightBearing = width;
     395             : }
     396             : 
     397             : // ----------------------
     398             : // the Style System will use these to pass the proper style context to our MathMLChar
     399             : nsStyleContext*
     400           0 : nsMathMLmrootFrame::GetAdditionalStyleContext(int32_t aIndex) const
     401             : {
     402           0 :   switch (aIndex) {
     403             :   case NS_SQR_CHAR_STYLE_CONTEXT_INDEX:
     404           0 :     return mSqrChar.GetStyleContext();
     405             :   default:
     406           0 :     return nullptr;
     407             :   }
     408             : }
     409             : 
     410             : void
     411           0 : nsMathMLmrootFrame::SetAdditionalStyleContext(int32_t          aIndex,
     412             :                                               nsStyleContext*  aStyleContext)
     413             : {
     414           0 :   switch (aIndex) {
     415             :   case NS_SQR_CHAR_STYLE_CONTEXT_INDEX:
     416           0 :     mSqrChar.SetStyleContext(aStyleContext);
     417           0 :     break;
     418             :   }
     419           0 : }

Generated by: LCOV version 1.13