layout/mathml/nsMathMLTokenFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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/. */
     6 #include "nsMathMLTokenFrame.h"
     7 #include "nsPresContext.h"
     8 #include "nsContentUtils.h"
     9 #include "nsTextFrame.h"
    10 #include "RestyleManager.h"
    11 #include <algorithm>
    13 nsIFrame*
    14 NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    15 {
    16   return new (aPresShell) nsMathMLTokenFrame(aContext);
    17 }
    19 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
    21 nsMathMLTokenFrame::~nsMathMLTokenFrame()
    22 {
    23 }
    25 NS_IMETHODIMP
    26 nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
    27 {
    28   // let the base class get the default from our parent
    29   nsMathMLContainerFrame::InheritAutomaticData(aParent);
    31   return NS_OK;
    32 }
    34 eMathMLFrameType
    35 nsMathMLTokenFrame::GetMathMLFrameType()
    36 {
    37   // treat everything other than <mi> as ordinary...
    38   if (mContent->Tag() != nsGkAtoms::mi_) {
    39     return eMathMLFrameType_Ordinary;
    40   }
    42   uint8_t mathVariant = StyleFont()->mMathVariant;
    43   if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
    44        (StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_ITALIC ||
    45         HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) ||
    46       mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
    47       mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
    48       mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
    49       mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
    50     return eMathMLFrameType_ItalicIdentifier;
    51   }
    52   return eMathMLFrameType_UprightIdentifier;
    53 }
    55 void
    56 nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
    57 {
    58   nsIFrame* child = nullptr;
    59   uint32_t childCount = 0;
    61   // Set flags on child text frames
    62   // - to force them to trim their leading and trailing whitespaces.
    63   // - Indicate which frames are suitable for mathvariant
    64   // - flag single character <mi> frames for special italic treatment
    65   for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
    66        childFrame = childFrame->GetNextSibling()) {
    67     for (nsIFrame* childFrame2 = childFrame->GetFirstPrincipalChild();
    68          childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
    69       if (childFrame2->GetType() == nsGkAtoms::textFrame) {
    70         childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
    71         child = childFrame2;
    72         childCount++;
    73       }
    74     }
    75   }
    76   if (mContent->Tag() == nsGkAtoms::mi_ && childCount == 1) {
    77     nsAutoString data;
    78     if (!nsContentUtils::GetNodeTextContent(mContent, false, data)) {
    79       NS_RUNTIMEABORT("OOM");
    80     }
    82     data.CompressWhitespace();
    83     int32_t length = data.Length();
    85     bool isSingleCharacter = length == 1 ||
    86       (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
    88     if (isSingleCharacter) {
    89       child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
    90       AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
    91     }
    92   }
    93 }
    95 nsresult
    96 nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
    97                                         nsFrameList&    aChildList)
    98 {
    99   // First, let the base class do its work
   100   nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
   101   if (NS_FAILED(rv))
   102     return rv;
   104   MarkTextFramesAsTokenMathML();
   106   return rv;
   107 }
   109 nsresult
   110 nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
   111                                  nsFrameList& aChildList)
   112 {
   113   nsresult rv = nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
   114   if (NS_FAILED(rv))
   115     return rv;
   117   MarkTextFramesAsTokenMathML();
   119   return rv;
   120 }
   122 nsresult
   123 nsMathMLTokenFrame::InsertFrames(ChildListID aListID,
   124                                  nsIFrame* aPrevFrame,
   125                                  nsFrameList& aChildList)
   126 {
   127   nsresult rv = nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame,
   128                                                      aChildList);
   129   if (NS_FAILED(rv))
   130     return rv;
   132   MarkTextFramesAsTokenMathML();
   134   return rv;
   135 }
   137 nsresult
   138 nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
   139                            nsHTMLReflowMetrics&     aDesiredSize,
   140                            const nsHTMLReflowState& aReflowState,
   141                            nsReflowStatus&          aStatus)
   142 {
   143   nsresult rv = NS_OK;
   145   // initializations needed for empty markup like <mtag></mtag>
   146   aDesiredSize.Width() = aDesiredSize.Height() = 0;
   147   aDesiredSize.SetTopAscent(0);
   148   aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
   150   nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
   151   nsIFrame* childFrame = GetFirstPrincipalChild();
   152   while (childFrame) {
   153     // ask our children to compute their bounding metrics
   154     nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(),
   155                                          aDesiredSize.mFlags
   156                                          | NS_REFLOW_CALC_BOUNDING_METRICS);
   157     nsHTMLReflowState childReflowState(aPresContext, aReflowState,
   158                                        childFrame, availSize);
   159     rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
   160                      childReflowState, aStatus);
   161     //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
   162     if (NS_FAILED(rv)) {
   163       // Call DidReflow() for the child frames we successfully did reflow.
   164       DidReflowChildren(GetFirstPrincipalChild(), childFrame);
   165       return rv;
   166     }
   168     SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
   169                                     childDesiredSize.mBoundingMetrics);
   171     childFrame = childFrame->GetNextSibling();
   172   }
   175   // place and size children
   176   FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
   178   aStatus = NS_FRAME_COMPLETE;
   179   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   180   return NS_OK;
   181 }
   183 // For token elements, mBoundingMetrics is computed at the ReflowToken
   184 // pass, it is not computed here because our children may be text frames
   185 // that do not implement the GetBoundingMetrics() interface.
   186 /* virtual */ nsresult
   187 nsMathMLTokenFrame::Place(nsRenderingContext& aRenderingContext,
   188                           bool                 aPlaceOrigin,
   189                           nsHTMLReflowMetrics& aDesiredSize)
   190 {
   191   mBoundingMetrics = nsBoundingMetrics();
   192   for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
   193        childFrame = childFrame->GetNextSibling()) {
   194     nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode());
   195     GetReflowAndBoundingMetricsFor(childFrame, childSize,
   196                                    childSize.mBoundingMetrics, nullptr);
   197     // compute and cache the bounding metrics
   198     mBoundingMetrics += childSize.mBoundingMetrics;
   199   }
   201   nsRefPtr<nsFontMetrics> fm;
   202   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   203   nscoord ascent = fm->MaxAscent();
   204   nscoord descent = fm->MaxDescent();
   206   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
   207   aDesiredSize.Width() = mBoundingMetrics.width;
   208   aDesiredSize.SetTopAscent(std::max(mBoundingMetrics.ascent, ascent));
   209   aDesiredSize.Height() = aDesiredSize.TopAscent() +
   210                         std::max(mBoundingMetrics.descent, descent);
   212   if (aPlaceOrigin) {
   213     nscoord dy, dx = 0;
   214     for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
   215          childFrame = childFrame->GetNextSibling()) {
   216       nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode());
   217       GetReflowAndBoundingMetricsFor(childFrame, childSize,
   218                                      childSize.mBoundingMetrics);
   220       // place and size the child; (dx,0) makes the caret happy - bug 188146
   221       dy = childSize.Height() == 0 ? 0 : aDesiredSize.TopAscent() - childSize.TopAscent();
   222       FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy, 0);
   223       dx += childSize.Width();
   224     }
   225   }
   227   SetReference(nsPoint(0, aDesiredSize.TopAscent()));
   229   return NS_OK;
   230 }

mercurial