layout/mathml/nsMathMLTokenFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/mathml/nsMathMLTokenFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,231 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsMathMLTokenFrame.h"
    1.10 +#include "nsPresContext.h"
    1.11 +#include "nsContentUtils.h"
    1.12 +#include "nsTextFrame.h"
    1.13 +#include "RestyleManager.h"
    1.14 +#include <algorithm>
    1.15 +
    1.16 +nsIFrame*
    1.17 +NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.18 +{
    1.19 +  return new (aPresShell) nsMathMLTokenFrame(aContext);
    1.20 +}
    1.21 +
    1.22 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
    1.23 +
    1.24 +nsMathMLTokenFrame::~nsMathMLTokenFrame()
    1.25 +{
    1.26 +}
    1.27 +
    1.28 +NS_IMETHODIMP
    1.29 +nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
    1.30 +{
    1.31 +  // let the base class get the default from our parent
    1.32 +  nsMathMLContainerFrame::InheritAutomaticData(aParent);
    1.33 +
    1.34 +  return NS_OK;
    1.35 +}
    1.36 +
    1.37 +eMathMLFrameType
    1.38 +nsMathMLTokenFrame::GetMathMLFrameType()
    1.39 +{
    1.40 +  // treat everything other than <mi> as ordinary...
    1.41 +  if (mContent->Tag() != nsGkAtoms::mi_) {
    1.42 +    return eMathMLFrameType_Ordinary;
    1.43 +  }
    1.44 +
    1.45 +  uint8_t mathVariant = StyleFont()->mMathVariant;
    1.46 +  if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
    1.47 +       (StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_ITALIC ||
    1.48 +        HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) ||
    1.49 +      mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
    1.50 +      mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
    1.51 +      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
    1.52 +      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
    1.53 +    return eMathMLFrameType_ItalicIdentifier;
    1.54 +  }
    1.55 +  return eMathMLFrameType_UprightIdentifier;
    1.56 +}
    1.57 +
    1.58 +void
    1.59 +nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
    1.60 +{
    1.61 +  nsIFrame* child = nullptr;
    1.62 +  uint32_t childCount = 0;
    1.63 +
    1.64 +  // Set flags on child text frames
    1.65 +  // - to force them to trim their leading and trailing whitespaces.
    1.66 +  // - Indicate which frames are suitable for mathvariant
    1.67 +  // - flag single character <mi> frames for special italic treatment
    1.68 +  for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
    1.69 +       childFrame = childFrame->GetNextSibling()) {
    1.70 +    for (nsIFrame* childFrame2 = childFrame->GetFirstPrincipalChild();
    1.71 +         childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
    1.72 +      if (childFrame2->GetType() == nsGkAtoms::textFrame) {
    1.73 +        childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
    1.74 +        child = childFrame2;
    1.75 +        childCount++;
    1.76 +      }
    1.77 +    }
    1.78 +  }
    1.79 +  if (mContent->Tag() == nsGkAtoms::mi_ && childCount == 1) {
    1.80 +    nsAutoString data;
    1.81 +    if (!nsContentUtils::GetNodeTextContent(mContent, false, data)) {
    1.82 +      NS_RUNTIMEABORT("OOM");
    1.83 +    }
    1.84 +
    1.85 +    data.CompressWhitespace();
    1.86 +    int32_t length = data.Length();
    1.87 +
    1.88 +    bool isSingleCharacter = length == 1 ||
    1.89 +      (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
    1.90 +
    1.91 +    if (isSingleCharacter) {
    1.92 +      child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
    1.93 +      AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
    1.94 +    }
    1.95 +  }
    1.96 +}
    1.97 +
    1.98 +nsresult
    1.99 +nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
   1.100 +                                        nsFrameList&    aChildList)
   1.101 +{
   1.102 +  // First, let the base class do its work
   1.103 +  nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
   1.104 +  if (NS_FAILED(rv))
   1.105 +    return rv;
   1.106 +
   1.107 +  MarkTextFramesAsTokenMathML();
   1.108 +
   1.109 +  return rv;
   1.110 +}
   1.111 +
   1.112 +nsresult
   1.113 +nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
   1.114 +                                 nsFrameList& aChildList)
   1.115 +{
   1.116 +  nsresult rv = nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
   1.117 +  if (NS_FAILED(rv))
   1.118 +    return rv;
   1.119 +
   1.120 +  MarkTextFramesAsTokenMathML();
   1.121 +
   1.122 +  return rv;
   1.123 +}
   1.124 +
   1.125 +nsresult
   1.126 +nsMathMLTokenFrame::InsertFrames(ChildListID aListID,
   1.127 +                                 nsIFrame* aPrevFrame,
   1.128 +                                 nsFrameList& aChildList)
   1.129 +{
   1.130 +  nsresult rv = nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame,
   1.131 +                                                     aChildList);
   1.132 +  if (NS_FAILED(rv))
   1.133 +    return rv;
   1.134 +
   1.135 +  MarkTextFramesAsTokenMathML();
   1.136 +
   1.137 +  return rv;
   1.138 +}
   1.139 +
   1.140 +nsresult
   1.141 +nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
   1.142 +                           nsHTMLReflowMetrics&     aDesiredSize,
   1.143 +                           const nsHTMLReflowState& aReflowState,
   1.144 +                           nsReflowStatus&          aStatus)
   1.145 +{
   1.146 +  nsresult rv = NS_OK;
   1.147 +
   1.148 +  // initializations needed for empty markup like <mtag></mtag>
   1.149 +  aDesiredSize.Width() = aDesiredSize.Height() = 0;
   1.150 +  aDesiredSize.SetTopAscent(0);
   1.151 +  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
   1.152 +
   1.153 +  nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
   1.154 +  nsIFrame* childFrame = GetFirstPrincipalChild();
   1.155 +  while (childFrame) {
   1.156 +    // ask our children to compute their bounding metrics
   1.157 +    nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(),
   1.158 +                                         aDesiredSize.mFlags
   1.159 +                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
   1.160 +    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
   1.161 +                                       childFrame, availSize);
   1.162 +    rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
   1.163 +                     childReflowState, aStatus);
   1.164 +    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
   1.165 +    if (NS_FAILED(rv)) {
   1.166 +      // Call DidReflow() for the child frames we successfully did reflow.
   1.167 +      DidReflowChildren(GetFirstPrincipalChild(), childFrame);
   1.168 +      return rv;
   1.169 +    }
   1.170 +
   1.171 +    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
   1.172 +                                    childDesiredSize.mBoundingMetrics);
   1.173 +
   1.174 +    childFrame = childFrame->GetNextSibling();
   1.175 +  }
   1.176 +
   1.177 +
   1.178 +  // place and size children
   1.179 +  FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
   1.180 +
   1.181 +  aStatus = NS_FRAME_COMPLETE;
   1.182 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   1.183 +  return NS_OK;
   1.184 +}
   1.185 +
   1.186 +// For token elements, mBoundingMetrics is computed at the ReflowToken
   1.187 +// pass, it is not computed here because our children may be text frames
   1.188 +// that do not implement the GetBoundingMetrics() interface.
   1.189 +/* virtual */ nsresult
   1.190 +nsMathMLTokenFrame::Place(nsRenderingContext& aRenderingContext,
   1.191 +                          bool                 aPlaceOrigin,
   1.192 +                          nsHTMLReflowMetrics& aDesiredSize)
   1.193 +{
   1.194 +  mBoundingMetrics = nsBoundingMetrics();
   1.195 +  for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
   1.196 +       childFrame = childFrame->GetNextSibling()) {
   1.197 +    nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode());
   1.198 +    GetReflowAndBoundingMetricsFor(childFrame, childSize,
   1.199 +                                   childSize.mBoundingMetrics, nullptr);
   1.200 +    // compute and cache the bounding metrics
   1.201 +    mBoundingMetrics += childSize.mBoundingMetrics;
   1.202 +  }
   1.203 +
   1.204 +  nsRefPtr<nsFontMetrics> fm;
   1.205 +  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   1.206 +  nscoord ascent = fm->MaxAscent();
   1.207 +  nscoord descent = fm->MaxDescent();
   1.208 +
   1.209 +  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
   1.210 +  aDesiredSize.Width() = mBoundingMetrics.width;
   1.211 +  aDesiredSize.SetTopAscent(std::max(mBoundingMetrics.ascent, ascent));
   1.212 +  aDesiredSize.Height() = aDesiredSize.TopAscent() +
   1.213 +                        std::max(mBoundingMetrics.descent, descent);
   1.214 +
   1.215 +  if (aPlaceOrigin) {
   1.216 +    nscoord dy, dx = 0;
   1.217 +    for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
   1.218 +         childFrame = childFrame->GetNextSibling()) {
   1.219 +      nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode());
   1.220 +      GetReflowAndBoundingMetricsFor(childFrame, childSize,
   1.221 +                                     childSize.mBoundingMetrics);
   1.222 +
   1.223 +      // place and size the child; (dx,0) makes the caret happy - bug 188146
   1.224 +      dy = childSize.Height() == 0 ? 0 : aDesiredSize.TopAscent() - childSize.TopAscent();
   1.225 +      FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy, 0);
   1.226 +      dx += childSize.Width();
   1.227 +    }
   1.228 +  }
   1.229 +
   1.230 +  SetReference(nsPoint(0, aDesiredSize.TopAscent()));
   1.231 +
   1.232 +  return NS_OK;
   1.233 +}
   1.234 +

mercurial