layout/mathml/nsMathMLTokenFrame.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial