Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 :
4 : /* This Source Code is subject to the terms of the Mozilla Public License
5 : * version 2.0 (the "License"). You can obtain a copy of the License at
6 : * http://mozilla.org/MPL/2.0/. */
7 :
8 : /* rendering object for CSS "display: flex" and "display: -webkit-box" */
9 :
10 : #ifndef nsFlexContainerFrame_h___
11 : #define nsFlexContainerFrame_h___
12 :
13 : #include "nsContainerFrame.h"
14 : #include "mozilla/UniquePtr.h"
15 :
16 : namespace mozilla {
17 : template <class T> class LinkedList;
18 : class LogicalPoint;
19 : } // namespace mozilla
20 :
21 : nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
22 : nsStyleContext* aContext);
23 :
24 :
25 : /**
26 : * This is the rendering object used for laying out elements with
27 : * "display: flex" or "display: inline-flex".
28 : *
29 : * We also use this class for elements with "display: -webkit-box" or
30 : * "display: -webkit-inline-box" (but not "-moz-box" / "-moz-inline-box" --
31 : * those are rendered with old-school XUL frame classes).
32 : *
33 : * Note: we represent the -webkit-box family of properties (-webkit-box-orient,
34 : * -webkit-box-flex, etc.) as aliases for their -moz equivalents. And for
35 : * -webkit-{inline-}box containers, nsFlexContainerFrame will honor those
36 : * "legacy" properties for alignment/flexibility/etc. *instead of* honoring the
37 : * modern flexbox & alignment properties. For brevity, many comments in
38 : * nsFlexContainerFrame.cpp simply refer to these properties using their
39 : * "-webkit" versions, since we're mostly expecting to encounter them in that
40 : * form. (Technically, the "-moz" versions of these properties *can* influence
41 : * layout here as well (since that's what the -webkit versions are aliased to)
42 : * -- but only inside of a "display:-webkit-{inline-}box" container.)
43 : */
44 : class nsFlexContainerFrame final : public nsContainerFrame
45 : {
46 : public:
47 0 : NS_DECL_FRAMEARENA_HELPERS(nsFlexContainerFrame)
48 : NS_DECL_QUERYFRAME
49 :
50 : // Factory method:
51 : friend nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
52 : nsStyleContext* aContext);
53 :
54 : // Forward-decls of helper classes
55 : class FlexItem;
56 : class FlexLine;
57 : class FlexboxAxisTracker;
58 : struct StrutInfo;
59 : class CachedMeasuringReflowResult;
60 :
61 : // nsIFrame overrides
62 : void Init(nsIContent* aContent,
63 : nsContainerFrame* aParent,
64 : nsIFrame* aPrevInFlow) override;
65 :
66 : void BuildDisplayList(nsDisplayListBuilder* aBuilder,
67 : const nsRect& aDirtyRect,
68 : const nsDisplayListSet& aLists) override;
69 :
70 : void MarkIntrinsicISizesDirty() override;
71 :
72 : void Reflow(nsPresContext* aPresContext,
73 : ReflowOutput& aDesiredSize,
74 : const ReflowInput& aReflowInput,
75 : nsReflowStatus& aStatus) override;
76 :
77 : nscoord GetMinISize(gfxContext* aRenderingContext) override;
78 : nscoord GetPrefISize(gfxContext* aRenderingContext) override;
79 :
80 : #ifdef DEBUG_FRAME_DUMP
81 : nsresult GetFrameName(nsAString& aResult) const override;
82 : #endif
83 :
84 : nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const override;
85 :
86 0 : bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
87 : nscoord* aBaseline) const override
88 : {
89 0 : return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline);
90 : }
91 :
92 0 : bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
93 : BaselineSharingGroup aBaselineGroup,
94 : nscoord* aBaseline) const override
95 : {
96 0 : if (HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) {
97 0 : return false;
98 : }
99 0 : *aBaseline = aBaselineGroup == BaselineSharingGroup::eFirst ?
100 : mBaselineFromLastReflow : mLastBaselineFromLastReflow;
101 0 : return true;
102 : }
103 :
104 : // nsContainerFrame overrides
105 : uint16_t CSSAlignmentForAbsPosChild(
106 : const ReflowInput& aChildRI,
107 : mozilla::LogicalAxis aLogicalAxis) const override;
108 :
109 : // Flexbox-specific public methods
110 : bool IsHorizontal();
111 :
112 : /**
113 : * Helper function to calculate packing space and initial offset of alignment
114 : * subjects in MainAxisPositionTracker() and CrossAxisPositionTracker() for
115 : * space-between, space-around, and space-evenly.
116 : *
117 : * @param aNumThingsToPack Number of alignment subjects.
118 : * @param aAlignVal Value for align-self or justify-self.
119 : * @param aFirstSubjectOffset Outparam for first subject offset.
120 : * @param aNumPackingSpacesRemaining Outparam for number of equal-sized
121 : * packing spaces to apply between each
122 : * alignment subject.
123 : * @param aPackingSpaceRemaining Outparam for total amount of packing
124 : * space to be divided up.
125 : */
126 : static void CalculatePackingSpace(uint32_t aNumThingsToPack,
127 : uint8_t aAlignVal,
128 : nscoord* aFirstSubjectOffset,
129 : uint32_t* aNumPackingSpacesRemaining,
130 : nscoord* aPackingSpaceRemaining);
131 :
132 : protected:
133 : // Protected constructor & destructor
134 0 : explicit nsFlexContainerFrame(nsStyleContext* aContext)
135 0 : : nsContainerFrame(aContext, kClassID)
136 : , mBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
137 0 : , mLastBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
138 0 : {}
139 :
140 : virtual ~nsFlexContainerFrame();
141 :
142 : /*
143 : * This method does the bulk of the flex layout, implementing the algorithm
144 : * described at:
145 : * http://dev.w3.org/csswg/css-flexbox/#layout-algorithm
146 : * (with a few initialization pieces happening in the caller, Reflow().
147 : *
148 : * Since this is a helper for Reflow(), this takes all the same parameters
149 : * as Reflow(), plus a few more parameters that Reflow() sets up for us.
150 : *
151 : * (The logic behind the division of work between Reflow and DoFlexLayout is
152 : * as follows: DoFlexLayout() begins at the step that we have to jump back
153 : * to, if we find any visibility:collapse children, and Reflow() does
154 : * everything before that point.)
155 : */
156 : void DoFlexLayout(nsPresContext* aPresContext,
157 : ReflowOutput& aDesiredSize,
158 : const ReflowInput& aReflowInput,
159 : nsReflowStatus& aStatus,
160 : nscoord aContentBoxMainSize,
161 : nscoord aAvailableBSizeForContent,
162 : nsTArray<StrutInfo>& aStruts,
163 : const FlexboxAxisTracker& aAxisTracker);
164 :
165 : /**
166 : * Checks whether our child-frame list "mFrames" is sorted, using the given
167 : * IsLessThanOrEqual function, and sorts it if it's not already sorted.
168 : *
169 : * XXXdholbert Once we support pagination, we need to make this function
170 : * check our continuations as well (or wrap it in a function that does).
171 : *
172 : * @return true if we had to sort mFrames, false if it was already sorted.
173 : */
174 : template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
175 : bool SortChildrenIfNeeded();
176 :
177 : // Protected flex-container-specific methods / member-vars
178 : #ifdef DEBUG
179 : void SanityCheckAnonymousFlexItems() const;
180 : #endif // DEBUG
181 :
182 : /*
183 : * Returns a new FlexItem for the given child frame, allocated on the heap.
184 : * Guaranteed to return non-null. Caller is responsible for managing the
185 : * FlexItem's lifetime.
186 : *
187 : * Before returning, this method also processes the FlexItem to resolve its
188 : * flex basis (including e.g. auto-height) as well as to resolve
189 : * "min-height:auto", via ResolveAutoFlexBasisAndMinSize(). (Basically, the
190 : * returned FlexItem will be ready to participate in the "Resolve the
191 : * Flexible Lengths" step of the Flex Layout Algorithm.)
192 : */
193 : mozilla::UniquePtr<FlexItem> GenerateFlexItemForChild(nsPresContext* aPresContext,
194 : nsIFrame* aChildFrame,
195 : const ReflowInput& aParentReflowInput,
196 : const FlexboxAxisTracker& aAxisTracker);
197 :
198 : /**
199 : * This method gets a cached measuring reflow for a flex item, or does it and
200 : * caches it.
201 : *
202 : * This avoids exponential reflows, see the comment on
203 : * CachedMeasuringReflowResult.
204 : */
205 : const CachedMeasuringReflowResult& MeasureAscentAndHeightForFlexItem(
206 : FlexItem& aItem,
207 : nsPresContext* aPresContext,
208 : ReflowInput& aChildReflowInput);
209 :
210 : /**
211 : * This method performs a "measuring" reflow to get the content height of
212 : * aFlexItem.Frame() (treating it as if it had auto-height), & returns the
213 : * resulting height.
214 : * (Helper for ResolveAutoFlexBasisAndMinSize().)
215 : */
216 : nscoord MeasureFlexItemContentHeight(nsPresContext* aPresContext,
217 : FlexItem& aFlexItem,
218 : bool aForceVerticalResizeForMeasuringReflow,
219 : const ReflowInput& aParentReflowInput);
220 :
221 : /**
222 : * This method resolves an "auto" flex-basis and/or min-main-size value
223 : * on aFlexItem, if needed.
224 : * (Helper for GenerateFlexItemForChild().)
225 : */
226 : void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
227 : FlexItem& aFlexItem,
228 : const ReflowInput& aItemReflowInput,
229 : const FlexboxAxisTracker& aAxisTracker);
230 :
231 : /**
232 : * This method:
233 : * - Creates FlexItems for all of our child frames (except placeholders).
234 : * - Groups those FlexItems into FlexLines.
235 : * - Returns those FlexLines in the outparam |aLines|.
236 : *
237 : * For any child frames which are placeholders, this method will instead just
238 : * append that child to the outparam |aPlaceholders| for separate handling.
239 : * (Absolutely positioned children of a flex container are *not* flex items.)
240 : */
241 : void GenerateFlexLines(nsPresContext* aPresContext,
242 : const ReflowInput& aReflowInput,
243 : nscoord aContentBoxMainSize,
244 : nscoord aAvailableBSizeForContent,
245 : const nsTArray<StrutInfo>& aStruts,
246 : const FlexboxAxisTracker& aAxisTracker,
247 : nsTArray<nsIFrame*>& aPlaceholders,
248 : mozilla::LinkedList<FlexLine>& aLines);
249 :
250 : nscoord GetMainSizeFromReflowInput(const ReflowInput& aReflowInput,
251 : const FlexboxAxisTracker& aAxisTracker);
252 :
253 : nscoord ComputeCrossSize(const ReflowInput& aReflowInput,
254 : const FlexboxAxisTracker& aAxisTracker,
255 : nscoord aSumLineCrossSizes,
256 : nscoord aAvailableBSizeForContent,
257 : bool* aIsDefinite,
258 : nsReflowStatus& aStatus);
259 :
260 : void SizeItemInCrossAxis(nsPresContext* aPresContext,
261 : const FlexboxAxisTracker& aAxisTracker,
262 : ReflowInput& aChildReflowInput,
263 : FlexItem& aItem);
264 :
265 : /**
266 : * Moves the given flex item's frame to the given LogicalPosition (modulo any
267 : * relative positioning).
268 : *
269 : * This can be used in cases where we've already done a "measuring reflow"
270 : * for the flex item at the correct size, and hence can skip its final reflow
271 : * (but still need to move it to the right final position).
272 : *
273 : * @param aReflowInput The flex container's reflow state.
274 : * @param aItem The flex item whose frame should be moved.
275 : * @param aFramePos The position where the flex item's frame should
276 : * be placed. (pre-relative positioning)
277 : * @param aContainerSize The flex container's size (required by some methods
278 : * that we call, to interpret aFramePos correctly).
279 : */
280 : void MoveFlexItemToFinalPosition(const ReflowInput& aReflowInput,
281 : const FlexItem& aItem,
282 : mozilla::LogicalPoint& aFramePos,
283 : const nsSize& aContainerSize);
284 : /**
285 : * Helper-function to reflow a child frame, at its final position determined
286 : * by flex layout.
287 : *
288 : * @param aPresContext The presentation context being used in reflow.
289 : * @param aAxisTracker A FlexboxAxisTracker with the flex container's axes.
290 : * @param aReflowInput The flex container's reflow state.
291 : * @param aItem The flex item to be reflowed.
292 : * @param aFramePos The position where the flex item's frame should
293 : * be placed. (pre-relative positioning)
294 : * @param aContainerSize The flex container's size (required by some methods
295 : * that we call, to interpret aFramePos correctly).
296 : */
297 : void ReflowFlexItem(nsPresContext* aPresContext,
298 : const FlexboxAxisTracker& aAxisTracker,
299 : const ReflowInput& aReflowInput,
300 : const FlexItem& aItem,
301 : mozilla::LogicalPoint& aFramePos,
302 : const nsSize& aContainerSize);
303 :
304 : /**
305 : * Helper-function to perform a "dummy reflow" on all our nsPlaceholderFrame
306 : * children, at the container's content-box origin.
307 : *
308 : * This doesn't actually represent the static position of the placeholders'
309 : * out-of-flow (OOF) frames -- we can't compute that until we've reflowed the
310 : * OOF, because (depending on the CSS Align properties) the static position
311 : * may be influenced by the OOF's size. So for now, we just co-opt the
312 : * placeholder to store the flex container's logical content-box origin, and
313 : * we defer to nsAbsoluteContainingBlock to determine the OOF's actual static
314 : * position (using this origin, the OOF's size, and the CSS Align
315 : * properties).
316 : *
317 : * @param aPresContext The presentation context being used in reflow.
318 : * @param aReflowInput The flex container's reflow input.
319 : * @param aPlaceholders An array of all the flex container's
320 : * nsPlaceholderFrame children.
321 : * @param aContentBoxOrigin The flex container's logical content-box
322 : * origin (in its own coordinate space).
323 : * @param aContainerSize The flex container's size (required by some
324 : * reflow methods to interpret positions correctly).
325 : */
326 : void ReflowPlaceholders(nsPresContext* aPresContext,
327 : const ReflowInput& aReflowInput,
328 : nsTArray<nsIFrame*>& aPlaceholders,
329 : const mozilla::LogicalPoint& aContentBoxOrigin,
330 : const nsSize& aContainerSize);
331 :
332 : nscoord mBaselineFromLastReflow;
333 : // Note: the last baseline is a distance from our border-box end edge.
334 : nscoord mLastBaselineFromLastReflow;
335 : };
336 :
337 : #endif /* nsFlexContainerFrame_h___ */
|