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 +