Line data Source code
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/. */
5 :
6 : #include "nsMathMLTokenFrame.h"
7 : #include "nsPresContext.h"
8 : #include "nsContentUtils.h"
9 : #include "nsTextFrame.h"
10 : #include "mozilla/GeckoRestyleManager.h"
11 : #include <algorithm>
12 :
13 : using namespace mozilla;
14 :
15 : nsIFrame*
16 0 : NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
17 : {
18 0 : return new (aPresShell) nsMathMLTokenFrame(aContext);
19 : }
20 :
21 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
22 :
23 0 : nsMathMLTokenFrame::~nsMathMLTokenFrame()
24 : {
25 0 : }
26 :
27 : NS_IMETHODIMP
28 0 : nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
29 : {
30 : // let the base class get the default from our parent
31 0 : nsMathMLContainerFrame::InheritAutomaticData(aParent);
32 :
33 0 : return NS_OK;
34 : }
35 :
36 : eMathMLFrameType
37 0 : nsMathMLTokenFrame::GetMathMLFrameType()
38 : {
39 : // treat everything other than <mi> as ordinary...
40 0 : if (!mContent->IsMathMLElement(nsGkAtoms::mi_)) {
41 0 : return eMathMLFrameType_Ordinary;
42 : }
43 :
44 0 : uint8_t mathVariant = StyleFont()->mMathVariant;
45 0 : if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
46 0 : (StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_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 : mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
52 0 : return eMathMLFrameType_ItalicIdentifier;
53 : }
54 0 : return eMathMLFrameType_UprightIdentifier;
55 : }
56 :
57 : void
58 0 : nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
59 : {
60 0 : nsIFrame* child = nullptr;
61 0 : uint32_t childCount = 0;
62 :
63 : // Set flags on child text frames
64 : // - to force them to trim their leading and trailing whitespaces.
65 : // - Indicate which frames are suitable for mathvariant
66 : // - flag single character <mi> frames for special italic treatment
67 0 : for (nsIFrame* childFrame = PrincipalChildList().FirstChild(); childFrame;
68 : 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 : }
76 : }
77 : }
78 0 : if (mContent->IsMathMLElement(nsGkAtoms::mi_) && childCount == 1) {
79 0 : nsAutoString data;
80 0 : nsContentUtils::GetNodeTextContent(mContent, false, data);
81 :
82 0 : data.CompressWhitespace();
83 0 : int32_t length = data.Length();
84 :
85 0 : bool isSingleCharacter = length == 1 ||
86 0 : (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
87 :
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 : }
92 : }
93 0 : }
94 :
95 : void
96 0 : nsMathMLTokenFrame::SetInitialChildList(ChildListID aListID,
97 : nsFrameList& aChildList)
98 : {
99 : // First, let the base class do its work
100 0 : nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
101 0 : MarkTextFramesAsTokenMathML();
102 0 : }
103 :
104 : void
105 0 : nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
106 : nsFrameList& aChildList)
107 : {
108 0 : nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
109 0 : MarkTextFramesAsTokenMathML();
110 0 : }
111 :
112 : void
113 0 : nsMathMLTokenFrame::InsertFrames(ChildListID aListID,
114 : nsIFrame* aPrevFrame,
115 : nsFrameList& aChildList)
116 : {
117 0 : nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame, aChildList);
118 0 : MarkTextFramesAsTokenMathML();
119 0 : }
120 :
121 : void
122 0 : nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext,
123 : ReflowOutput& aDesiredSize,
124 : const ReflowInput& aReflowInput,
125 : nsReflowStatus& aStatus)
126 : {
127 0 : MarkInReflow();
128 0 : mPresentationData.flags &= ~NS_MATHML_ERROR;
129 :
130 : // initializations needed for empty markup like <mtag></mtag>
131 0 : aDesiredSize.ClearSize();
132 0 : aDesiredSize.SetBlockStartAscent(0);
133 0 : aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
134 :
135 0 : for (nsIFrame* childFrame : PrincipalChildList()) {
136 : // ask our children to compute their bounding metrics
137 : ReflowOutput childDesiredSize(aReflowInput.GetWritingMode(),
138 0 : aDesiredSize.mFlags
139 0 : | NS_REFLOW_CALC_BOUNDING_METRICS);
140 0 : WritingMode wm = childFrame->GetWritingMode();
141 0 : LogicalSize availSize = aReflowInput.ComputedSize(wm);
142 0 : availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
143 : ReflowInput childReflowInput(aPresContext, aReflowInput,
144 0 : childFrame, availSize);
145 0 : ReflowChild(childFrame, aPresContext, childDesiredSize,
146 0 : childReflowInput, aStatus);
147 : //NS_ASSERTION(aStatus.IsComplete(), "bad status");
148 : SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
149 0 : childDesiredSize.mBoundingMetrics);
150 : }
151 :
152 : // place and size children
153 0 : FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize);
154 :
155 0 : aStatus.Reset();
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 0 : nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget,
164 : bool aPlaceOrigin,
165 : ReflowOutput& aDesiredSize)
166 : {
167 0 : mBoundingMetrics = nsBoundingMetrics();
168 0 : for (nsIFrame* childFrame :PrincipalChildList()) {
169 0 : ReflowOutput childSize(aDesiredSize.GetWritingMode());
170 : GetReflowAndBoundingMetricsFor(childFrame, childSize,
171 0 : childSize.mBoundingMetrics, nullptr);
172 : // compute and cache the bounding metrics
173 0 : mBoundingMetrics += childSize.mBoundingMetrics;
174 : }
175 :
176 : RefPtr<nsFontMetrics> fm =
177 0 : nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
178 0 : nscoord ascent = fm->MaxAscent();
179 0 : nscoord descent = fm->MaxDescent();
180 :
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 :
187 0 : if (aPlaceOrigin) {
188 0 : nscoord dy, dx = 0;
189 0 : for (nsIFrame* childFrame : PrincipalChildList()) {
190 0 : ReflowOutput childSize(aDesiredSize.GetWritingMode());
191 : GetReflowAndBoundingMetricsFor(childFrame, childSize,
192 0 : childSize.mBoundingMetrics);
193 :
194 : // 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 : }
199 : }
200 :
201 0 : SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
202 :
203 0 : return NS_OK;
204 : }
205 :
|