/src/mozilla-central/layout/mathml/nsMathMLTokenFrame.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "nsPresContext.h" |
9 | | #include "nsContentUtils.h" |
10 | | #include "nsTextFrame.h" |
11 | | #include <algorithm> |
12 | | |
13 | | using namespace mozilla; |
14 | | |
15 | | nsIFrame* |
16 | | NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) |
17 | 0 | { |
18 | 0 | return new (aPresShell) nsMathMLTokenFrame(aStyle); |
19 | 0 | } |
20 | | |
21 | | NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame) |
22 | | |
23 | | nsMathMLTokenFrame::~nsMathMLTokenFrame() |
24 | 0 | { |
25 | 0 | } |
26 | | |
27 | | NS_IMETHODIMP |
28 | | nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent) |
29 | 0 | { |
30 | 0 | // let the base class get the default from our parent |
31 | 0 | nsMathMLContainerFrame::InheritAutomaticData(aParent); |
32 | 0 |
|
33 | 0 | return NS_OK; |
34 | 0 | } |
35 | | |
36 | | eMathMLFrameType |
37 | | nsMathMLTokenFrame::GetMathMLFrameType() |
38 | 0 | { |
39 | 0 | // treat everything other than <mi> as ordinary... |
40 | 0 | if (!mContent->IsMathMLElement(nsGkAtoms::mi_)) { |
41 | 0 | return eMathMLFrameType_Ordinary; |
42 | 0 | } |
43 | 0 | |
44 | 0 | uint8_t mathVariant = StyleFont()->mMathVariant; |
45 | 0 | if ((mathVariant == NS_MATHML_MATHVARIANT_NONE && |
46 | 0 | (StyleFont()->mFont.style == FontSlantStyle::Italic() || |
47 | 0 | HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) || |
48 | 0 | mathVariant == NS_MATHML_MATHVARIANT_ITALIC || |
49 | 0 | mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC || |
50 | 0 | mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC || |
51 | 0 | mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) { |
52 | 0 | return eMathMLFrameType_ItalicIdentifier; |
53 | 0 | } |
54 | 0 | return eMathMLFrameType_UprightIdentifier; |
55 | 0 | } |
56 | | |
57 | | void |
58 | | nsMathMLTokenFrame::MarkTextFramesAsTokenMathML() |
59 | 0 | { |
60 | 0 | nsIFrame* child = nullptr; |
61 | 0 | uint32_t childCount = 0; |
62 | 0 |
|
63 | 0 | // Set flags on child text frames |
64 | 0 | // - to force them to trim their leading and trailing whitespaces. |
65 | 0 | // - Indicate which frames are suitable for mathvariant |
66 | 0 | // - flag single character <mi> frames for special italic treatment |
67 | 0 | for (nsIFrame* childFrame = PrincipalChildList().FirstChild(); childFrame; |
68 | 0 | childFrame = childFrame->GetNextSibling()) { |
69 | 0 | for (nsIFrame* childFrame2 = childFrame->PrincipalChildList().FirstChild(); |
70 | 0 | childFrame2; childFrame2 = childFrame2->GetNextSibling()) { |
71 | 0 | if (childFrame2->IsTextFrame()) { |
72 | 0 | childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML); |
73 | 0 | child = childFrame2; |
74 | 0 | childCount++; |
75 | 0 | } |
76 | 0 | } |
77 | 0 | } |
78 | 0 | if (mContent->IsMathMLElement(nsGkAtoms::mi_) && childCount == 1) { |
79 | 0 | nsAutoString data; |
80 | 0 | nsContentUtils::GetNodeTextContent(mContent, false, data); |
81 | 0 |
|
82 | 0 | data.CompressWhitespace(); |
83 | 0 | int32_t length = data.Length(); |
84 | 0 |
|
85 | 0 | bool isSingleCharacter = length == 1 || |
86 | 0 | (length == 2 && NS_IS_HIGH_SURROGATE(data[0])); |
87 | 0 |
|
88 | 0 | if (isSingleCharacter) { |
89 | 0 | child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI); |
90 | 0 | AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI); |
91 | 0 | } |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | void |
96 | | nsMathMLTokenFrame::SetInitialChildList(ChildListID aListID, |
97 | | nsFrameList& aChildList) |
98 | 0 | { |
99 | 0 | // First, let the base class do its work |
100 | 0 | nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList); |
101 | 0 | MarkTextFramesAsTokenMathML(); |
102 | 0 | } |
103 | | |
104 | | void |
105 | | nsMathMLTokenFrame::AppendFrames(ChildListID aListID, |
106 | | nsFrameList& aChildList) |
107 | 0 | { |
108 | 0 | nsMathMLContainerFrame::AppendFrames(aListID, aChildList); |
109 | 0 | MarkTextFramesAsTokenMathML(); |
110 | 0 | } |
111 | | |
112 | | void |
113 | | nsMathMLTokenFrame::InsertFrames(ChildListID aListID, |
114 | | nsIFrame* aPrevFrame, |
115 | | nsFrameList& aChildList) |
116 | 0 | { |
117 | 0 | nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame, aChildList); |
118 | 0 | MarkTextFramesAsTokenMathML(); |
119 | 0 | } |
120 | | |
121 | | void |
122 | | nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext, |
123 | | ReflowOutput& aDesiredSize, |
124 | | const ReflowInput& aReflowInput, |
125 | | nsReflowStatus& aStatus) |
126 | 0 | { |
127 | 0 | MarkInReflow(); |
128 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
129 | 0 |
|
130 | 0 | mPresentationData.flags &= ~NS_MATHML_ERROR; |
131 | 0 |
|
132 | 0 | // initializations needed for empty markup like <mtag></mtag> |
133 | 0 | aDesiredSize.ClearSize(); |
134 | 0 | aDesiredSize.SetBlockStartAscent(0); |
135 | 0 | aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); |
136 | 0 |
|
137 | 0 | for (nsIFrame* childFrame : PrincipalChildList()) { |
138 | 0 | // ask our children to compute their bounding metrics |
139 | 0 | ReflowOutput childDesiredSize(aReflowInput.GetWritingMode()); |
140 | 0 | WritingMode wm = childFrame->GetWritingMode(); |
141 | 0 | LogicalSize availSize = aReflowInput.ComputedSize(wm); |
142 | 0 | availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; |
143 | 0 | ReflowInput childReflowInput(aPresContext, aReflowInput, |
144 | 0 | childFrame, availSize); |
145 | 0 | ReflowChild(childFrame, aPresContext, childDesiredSize, |
146 | 0 | childReflowInput, aStatus); |
147 | 0 | //NS_ASSERTION(aStatus.IsComplete(), "bad status"); |
148 | 0 | SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, |
149 | 0 | childDesiredSize.mBoundingMetrics); |
150 | 0 | } |
151 | 0 |
|
152 | 0 | // place and size children |
153 | 0 | FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize); |
154 | 0 |
|
155 | 0 | aStatus.Reset(); // This type of frame can't be split. |
156 | 0 | NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); |
157 | 0 | } |
158 | | |
159 | | // For token elements, mBoundingMetrics is computed at the ReflowToken |
160 | | // pass, it is not computed here because our children may be text frames |
161 | | // that do not implement the GetBoundingMetrics() interface. |
162 | | /* virtual */ nsresult |
163 | | nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget, |
164 | | bool aPlaceOrigin, |
165 | | ReflowOutput& aDesiredSize) |
166 | 0 | { |
167 | 0 | mBoundingMetrics = nsBoundingMetrics(); |
168 | 0 | for (nsIFrame* childFrame :PrincipalChildList()) { |
169 | 0 | ReflowOutput childSize(aDesiredSize.GetWritingMode()); |
170 | 0 | GetReflowAndBoundingMetricsFor(childFrame, childSize, |
171 | 0 | childSize.mBoundingMetrics, nullptr); |
172 | 0 | // compute and cache the bounding metrics |
173 | 0 | mBoundingMetrics += childSize.mBoundingMetrics; |
174 | 0 | } |
175 | 0 |
|
176 | 0 | RefPtr<nsFontMetrics> fm = |
177 | 0 | nsLayoutUtils::GetInflatedFontMetricsForFrame(this); |
178 | 0 | nscoord ascent = fm->MaxAscent(); |
179 | 0 | nscoord descent = fm->MaxDescent(); |
180 | 0 |
|
181 | 0 | aDesiredSize.mBoundingMetrics = mBoundingMetrics; |
182 | 0 | aDesiredSize.Width() = mBoundingMetrics.width; |
183 | 0 | aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent, ascent)); |
184 | 0 | aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + |
185 | 0 | std::max(mBoundingMetrics.descent, descent); |
186 | 0 |
|
187 | 0 | if (aPlaceOrigin) { |
188 | 0 | nscoord dy, dx = 0; |
189 | 0 | for (nsIFrame* childFrame : PrincipalChildList()) { |
190 | 0 | ReflowOutput childSize(aDesiredSize.GetWritingMode()); |
191 | 0 | GetReflowAndBoundingMetricsFor(childFrame, childSize, |
192 | 0 | childSize.mBoundingMetrics); |
193 | 0 |
|
194 | 0 | // place and size the child; (dx,0) makes the caret happy - bug 188146 |
195 | 0 | dy = childSize.Height() == 0 ? 0 : aDesiredSize.BlockStartAscent() - childSize.BlockStartAscent(); |
196 | 0 | FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy, 0); |
197 | 0 | dx += childSize.Width(); |
198 | 0 | } |
199 | 0 | } |
200 | 0 |
|
201 | 0 | SetReference(nsPoint(0, aDesiredSize.BlockStartAscent())); |
202 | 0 |
|
203 | 0 | return NS_OK; |
204 | 0 | } |
205 | | |