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 "nsMathMLSelectedFrame.h"
7 #include "nsDisplayList.h"
8
9 using namespace mozilla;
10
~nsMathMLSelectedFrame()11 nsMathMLSelectedFrame::~nsMathMLSelectedFrame()
12 {
13 }
14
15 void
Init(nsIContent * aContent,nsContainerFrame * aParent,nsIFrame * aPrevInFlow)16 nsMathMLSelectedFrame::Init(nsIContent* aContent,
17 nsContainerFrame* aParent,
18 nsIFrame* aPrevInFlow)
19 {
20 // Init our local attributes
21 mInvalidMarkup = false;
22 mSelectedFrame = nullptr;
23
24 // Let the base class do the rest
25 nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
26 }
27
28 NS_IMETHODIMP
TransmitAutomaticData()29 nsMathMLSelectedFrame::TransmitAutomaticData()
30 {
31 // Note that to determine space-like and embellished op properties:
32 // - <semantics> behaves the same as <maction>
33 // - <annotation-xml> behaves the same as <mrow>
34
35 // The REC defines the following element to be space-like:
36 // * an maction element whose selected sub-expression exists and is
37 // space-like;
38 nsIMathMLFrame* mathMLFrame = do_QueryFrame(mSelectedFrame);
39 if (mathMLFrame && mathMLFrame->IsSpaceLike()) {
40 mPresentationData.flags |= NS_MATHML_SPACE_LIKE;
41 } else {
42 mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE;
43 }
44
45 // The REC defines the following element to be an embellished operator:
46 // * an maction element whose selected sub-expression exists and is an
47 // embellished operator;
48 mPresentationData.baseFrame = mSelectedFrame;
49 GetEmbellishDataFrom(mSelectedFrame, mEmbellishData);
50
51 return NS_OK;
52 }
53
54 nsresult
ChildListChanged(int32_t aModType)55 nsMathMLSelectedFrame::ChildListChanged(int32_t aModType)
56 {
57 GetSelectedFrame();
58 return nsMathMLContainerFrame::ChildListChanged(aModType);
59 }
60
61 void
SetInitialChildList(ChildListID aListID,nsFrameList & aChildList)62 nsMathMLSelectedFrame::SetInitialChildList(ChildListID aListID,
63 nsFrameList& aChildList)
64 {
65 nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
66 // This very first call to GetSelectedFrame() will cause us to be marked as an
67 // embellished operator if the selected child is an embellished operator
68 GetSelectedFrame();
69 }
70
71 // Only paint the selected child...
72 void
BuildDisplayList(nsDisplayListBuilder * aBuilder,const nsRect & aDirtyRect,const nsDisplayListSet & aLists)73 nsMathMLSelectedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
74 const nsRect& aDirtyRect,
75 const nsDisplayListSet& aLists)
76 {
77 // Report an error if something wrong was found in this frame.
78 // We can't call nsDisplayMathMLError from here,
79 // so ask nsMathMLContainerFrame to do the work for us.
80 if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
81 nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
82 return;
83 }
84
85 DisplayBorderBackgroundOutline(aBuilder, aLists);
86
87 nsIFrame* childFrame = GetSelectedFrame();
88 if (childFrame) {
89 // Put the child's background directly onto the content list
90 nsDisplayListSet set(aLists, aLists.Content());
91 // The children should be in content order
92 BuildDisplayListForChild(aBuilder, childFrame, aDirtyRect, set);
93 }
94
95 #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
96 // visual debug
97 DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
98 #endif
99 }
100
101 /* virtual */
102 LogicalSize
ComputeSize(nsRenderingContext * aRenderingContext,WritingMode aWM,const LogicalSize & aCBSize,nscoord aAvailableISize,const LogicalSize & aMargin,const LogicalSize & aBorder,const LogicalSize & aPadding,ComputeSizeFlags aFlags)103 nsMathMLSelectedFrame::ComputeSize(nsRenderingContext *aRenderingContext,
104 WritingMode aWM,
105 const LogicalSize& aCBSize,
106 nscoord aAvailableISize,
107 const LogicalSize& aMargin,
108 const LogicalSize& aBorder,
109 const LogicalSize& aPadding,
110 ComputeSizeFlags aFlags)
111 {
112 nsIFrame* childFrame = GetSelectedFrame();
113 if (childFrame) {
114 // Delegate size computation to the child frame.
115 // Try to account for border/padding/margin on this frame and the child,
116 // though we don't really support them during reflow anyway...
117 nscoord availableISize = aAvailableISize - aBorder.ISize(aWM) -
118 aPadding.ISize(aWM) - aMargin.ISize(aWM);
119 LogicalSize cbSize = aCBSize - aBorder - aPadding - aMargin;
120 SizeComputationInput offsetState(childFrame, aRenderingContext, aWM,
121 availableISize);
122 LogicalSize size =
123 childFrame->ComputeSize(aRenderingContext, aWM, cbSize,
124 availableISize, offsetState.ComputedLogicalMargin().Size(aWM),
125 offsetState.ComputedLogicalBorderPadding().Size(aWM) -
126 offsetState.ComputedLogicalPadding().Size(aWM),
127 offsetState.ComputedLogicalPadding().Size(aWM),
128 aFlags);
129 return size + offsetState.ComputedLogicalBorderPadding().Size(aWM);
130 }
131 return LogicalSize(aWM);
132 }
133
134 // Only reflow the selected child ...
135 void
Reflow(nsPresContext * aPresContext,ReflowOutput & aDesiredSize,const ReflowInput & aReflowInput,nsReflowStatus & aStatus)136 nsMathMLSelectedFrame::Reflow(nsPresContext* aPresContext,
137 ReflowOutput& aDesiredSize,
138 const ReflowInput& aReflowInput,
139 nsReflowStatus& aStatus)
140 {
141 MarkInReflow();
142 mPresentationData.flags &= ~NS_MATHML_ERROR;
143 aStatus = NS_FRAME_COMPLETE;
144 aDesiredSize.ClearSize();
145 aDesiredSize.SetBlockStartAscent(0);
146 mBoundingMetrics = nsBoundingMetrics();
147 nsIFrame* childFrame = GetSelectedFrame();
148 if (childFrame) {
149 WritingMode wm = childFrame->GetWritingMode();
150 LogicalSize availSize = aReflowInput.ComputedSize(wm);
151 availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
152 ReflowInput childReflowInput(aPresContext, aReflowInput,
153 childFrame, availSize);
154 ReflowChild(childFrame, aPresContext, aDesiredSize,
155 childReflowInput, aStatus);
156 SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize,
157 aDesiredSize.mBoundingMetrics);
158 mBoundingMetrics = aDesiredSize.mBoundingMetrics;
159 }
160 FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize);
161 NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
162 }
163
164 // Only place the selected child ...
165 /* virtual */ nsresult
Place(DrawTarget * aDrawTarget,bool aPlaceOrigin,ReflowOutput & aDesiredSize)166 nsMathMLSelectedFrame::Place(DrawTarget* aDrawTarget,
167 bool aPlaceOrigin,
168 ReflowOutput& aDesiredSize)
169 {
170 nsIFrame* childFrame = GetSelectedFrame();
171
172 if (mInvalidMarkup) {
173 return ReflowError(aDrawTarget, aDesiredSize);
174 }
175
176 aDesiredSize.ClearSize();
177 aDesiredSize.SetBlockStartAscent(0);
178 mBoundingMetrics = nsBoundingMetrics();
179 if (childFrame) {
180 GetReflowAndBoundingMetricsFor(childFrame, aDesiredSize, mBoundingMetrics);
181 if (aPlaceOrigin) {
182 FinishReflowChild(childFrame, PresContext(), aDesiredSize, nullptr, 0, 0, 0);
183 }
184 mReference.x = 0;
185 mReference.y = aDesiredSize.BlockStartAscent();
186 }
187 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
188 return NS_OK;
189 }
190