tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsMathMLTokenFrame.cpp (8386B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsMathMLTokenFrame.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "gfxContext.h"
     12 #include "mozilla/PresShell.h"
     13 #include "nsContentUtils.h"
     14 #include "nsLayoutUtils.h"
     15 #include "nsPresContext.h"
     16 #include "nsTextFrame.h"
     17 
     18 using namespace mozilla;
     19 
     20 nsIFrame* NS_NewMathMLTokenFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
     21  return new (aPresShell)
     22      nsMathMLTokenFrame(aStyle, aPresShell->GetPresContext());
     23 }
     24 
     25 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
     26 
     27 nsMathMLTokenFrame::~nsMathMLTokenFrame() = default;
     28 
     29 NS_IMETHODIMP
     30 nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent) {
     31  // let the base class get the default from our parent
     32  nsMathMLContainerFrame::InheritAutomaticData(aParent);
     33 
     34  return NS_OK;
     35 }
     36 
     37 MathMLFrameType nsMathMLTokenFrame::GetMathMLFrameType() {
     38  // treat everything other than <mi> as ordinary...
     39  if (!mContent->IsMathMLElement(nsGkAtoms::mi)) {
     40    return MathMLFrameType::Ordinary;
     41  }
     42 
     43  StyleMathVariant mathVariant = StyleFont()->mMathVariant;
     44  if ((mathVariant == StyleMathVariant::None &&
     45       (StyleFont()->mFont.style.IsItalic() ||
     46        HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) ||
     47      mathVariant == StyleMathVariant::Italic ||
     48      mathVariant == StyleMathVariant::BoldItalic ||
     49      mathVariant == StyleMathVariant::SansSerifItalic ||
     50      mathVariant == StyleMathVariant::SansSerifBoldItalic) {
     51    return MathMLFrameType::ItalicIdentifier;
     52  }
     53  return MathMLFrameType::UprightIdentifier;
     54 }
     55 
     56 void nsMathMLTokenFrame::MarkTextFramesAsTokenMathML() {
     57  nsIFrame* child = nullptr;
     58  uint32_t childCount = 0;
     59 
     60  // Set flags on child text frames
     61  // - to force them to trim their leading and trailing whitespaces.
     62  // - Indicate which frames are suitable for mathvariant
     63  // - flag single character <mi> frames for special italic treatment
     64  for (nsIFrame* childFrame = PrincipalChildList().FirstChild(); childFrame;
     65       childFrame = childFrame->GetNextSibling()) {
     66    for (nsIFrame* childFrame2 = childFrame->PrincipalChildList().FirstChild();
     67         childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
     68      if (childFrame2->IsTextFrame()) {
     69        childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
     70        child = childFrame2;
     71        childCount++;
     72      }
     73    }
     74  }
     75  if (mContent->IsMathMLElement(nsGkAtoms::mi) && childCount == 1) {
     76    nsAutoString data;
     77    nsContentUtils::GetNodeTextContent(mContent, false, data);
     78 
     79    data.CompressWhitespace();
     80    int32_t length = data.Length();
     81 
     82    bool isSingleCharacter =
     83        length == 1 || (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
     84 
     85    if (isSingleCharacter) {
     86      child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
     87      AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
     88    }
     89  }
     90 }
     91 
     92 void nsMathMLTokenFrame::SetInitialChildList(ChildListID aListID,
     93                                             nsFrameList&& aChildList) {
     94  // First, let the base class do its work
     95  nsMathMLContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
     96  MarkTextFramesAsTokenMathML();
     97 }
     98 
     99 void nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
    100                                      nsFrameList&& aChildList) {
    101  nsMathMLContainerFrame::AppendFrames(aListID, std::move(aChildList));
    102  MarkTextFramesAsTokenMathML();
    103 }
    104 
    105 void nsMathMLTokenFrame::InsertFrames(
    106    ChildListID aListID, nsIFrame* aPrevFrame,
    107    const nsLineList::iterator* aPrevFrameLine, nsFrameList&& aChildList) {
    108  nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
    109                                       std::move(aChildList));
    110  MarkTextFramesAsTokenMathML();
    111 }
    112 
    113 void nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext,
    114                                ReflowOutput& aDesiredSize,
    115                                const ReflowInput& aReflowInput,
    116                                nsReflowStatus& aStatus) {
    117  MarkInReflow();
    118  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    119 
    120  // initializations needed for empty markup like <mtag></mtag>
    121  aDesiredSize.ClearSize();
    122  aDesiredSize.SetBlockStartAscent(0);
    123  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
    124 
    125  for (nsIFrame* childFrame : PrincipalChildList()) {
    126    // ask our children to compute their bounding metrics
    127    ReflowOutput childDesiredSize(aReflowInput.GetWritingMode());
    128    WritingMode wm = childFrame->GetWritingMode();
    129    LogicalSize availSize = aReflowInput.ComputedSize(wm);
    130    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    131    ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame,
    132                                 availSize);
    133    nsReflowStatus childStatus;
    134    ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowInput,
    135                childStatus);
    136    NS_ASSERTION(childStatus.IsComplete(),
    137                 "We gave the child unconstrained available block-size, so its "
    138                 "status should be complete!");
    139    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
    140                                    childDesiredSize.mBoundingMetrics);
    141  }
    142 
    143  // place and size children
    144  FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize);
    145 
    146  aStatus.Reset();  // This type of frame can't be split.
    147 }
    148 
    149 // For token elements, mBoundingMetrics is computed at the ReflowToken
    150 // pass, it is not computed here because our children may be text frames
    151 // that do not implement the GetBoundingMetrics() interface.
    152 /* virtual */
    153 void nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget,
    154                               const PlaceFlags& aFlags,
    155                               ReflowOutput& aDesiredSize) {
    156  mBoundingMetrics = nsBoundingMetrics();
    157  for (nsIFrame* childFrame : PrincipalChildList()) {
    158    ReflowOutput childSize(aDesiredSize.GetWritingMode());
    159    nsBoundingMetrics bmChild;
    160    GetReflowAndBoundingMetricsFor(childFrame, childSize, bmChild, nullptr);
    161    auto childMargin = GetMarginForPlace(aFlags, childFrame);
    162    bmChild.ascent += childMargin.top;
    163    bmChild.descent += childMargin.bottom;
    164    bmChild.rightBearing += childMargin.LeftRight();
    165    bmChild.width += childMargin.LeftRight();
    166 
    167    // compute and cache the bounding metrics
    168    mBoundingMetrics += bmChild;
    169  }
    170 
    171  RefPtr<nsFontMetrics> fm =
    172      nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
    173  nscoord ascent = fm->MaxAscent();
    174  nscoord descent = fm->MaxDescent();
    175 
    176  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
    177  aDesiredSize.Width() = mBoundingMetrics.width;
    178  aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent, ascent));
    179  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
    180                          std::max(mBoundingMetrics.descent, descent);
    181 
    182  // Apply width/height to math content box.
    183  auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
    184  auto shiftX = ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
    185                                                 mBoundingMetrics);
    186 
    187  // Add padding+border.
    188  auto borderPadding = GetBorderPaddingForPlace(aFlags);
    189  InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
    190                                  mBoundingMetrics);
    191 
    192  if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
    193    nscoord dx = borderPadding.left;
    194    dx += shiftX;
    195    for (nsIFrame* childFrame : PrincipalChildList()) {
    196      ReflowOutput childSize(aDesiredSize.GetWritingMode());
    197      GetReflowAndBoundingMetricsFor(childFrame, childSize,
    198                                     childSize.mBoundingMetrics);
    199      auto childMargin = GetMarginForPlace(aFlags, childFrame);
    200 
    201      // place and size the child; (dx,0) makes the caret happy - bug 188146
    202      nscoord dy = childSize.Height() == 0
    203                       ? 0
    204                       : aDesiredSize.BlockStartAscent() -
    205                             childSize.BlockStartAscent() + childMargin.top;
    206      FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy,
    207                        ReflowChildFlags::Default);
    208      dx += childSize.Width();
    209    }
    210  }
    211 
    212  SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
    213 }