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