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