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 : /* This Source Code is subject to the terms of the Mozilla Public License
4 : * version 2.0 (the "License"). You can obtain a copy of the License at
5 : * http://mozilla.org/MPL/2.0/. */
6 :
7 : /* rendering object for CSS "display: grid | inline-grid" */
8 :
9 : #ifndef nsGridContainerFrame_h___
10 : #define nsGridContainerFrame_h___
11 :
12 : #include "mozilla/Maybe.h"
13 : #include "mozilla/TypeTraits.h"
14 : #include "nsContainerFrame.h"
15 : #include "nsHashKeys.h"
16 : #include "nsTHashtable.h"
17 :
18 : /**
19 : * Factory function.
20 : * @return a newly allocated nsGridContainerFrame (infallible)
21 : */
22 : nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
23 : nsStyleContext* aContext);
24 :
25 : namespace mozilla {
26 :
27 : // Forward-declare typedefs for grid item iterator helper-class:
28 : template<typename Iterator> class CSSOrderAwareFrameIteratorT;
29 : typedef CSSOrderAwareFrameIteratorT<nsFrameList::iterator>
30 : CSSOrderAwareFrameIterator;
31 : typedef CSSOrderAwareFrameIteratorT<nsFrameList::reverse_iterator>
32 : ReverseCSSOrderAwareFrameIterator;
33 :
34 : /**
35 : * The number of implicit / explicit tracks and their sizes.
36 : */
37 0 : struct ComputedGridTrackInfo
38 : {
39 0 : ComputedGridTrackInfo(uint32_t aNumLeadingImplicitTracks,
40 : uint32_t aNumExplicitTracks,
41 : uint32_t aStartFragmentTrack,
42 : uint32_t aEndFragmentTrack,
43 : nsTArray<nscoord>&& aPositions,
44 : nsTArray<nscoord>&& aSizes,
45 : nsTArray<uint32_t>&& aStates,
46 : nsTArray<bool>&& aRemovedRepeatTracks,
47 : uint32_t aRepeatFirstTrack)
48 0 : : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks)
49 : , mNumExplicitTracks(aNumExplicitTracks)
50 : , mStartFragmentTrack(aStartFragmentTrack)
51 : , mEndFragmentTrack(aEndFragmentTrack)
52 : , mPositions(aPositions)
53 : , mSizes(aSizes)
54 : , mStates(aStates)
55 : , mRemovedRepeatTracks(aRemovedRepeatTracks)
56 0 : , mRepeatFirstTrack(aRepeatFirstTrack)
57 0 : {}
58 : uint32_t mNumLeadingImplicitTracks;
59 : uint32_t mNumExplicitTracks;
60 : uint32_t mStartFragmentTrack;
61 : uint32_t mEndFragmentTrack;
62 : nsTArray<nscoord> mPositions;
63 : nsTArray<nscoord> mSizes;
64 : nsTArray<uint32_t> mStates;
65 : nsTArray<bool> mRemovedRepeatTracks;
66 : uint32_t mRepeatFirstTrack;
67 : };
68 :
69 0 : struct ComputedGridLineInfo
70 : {
71 0 : explicit ComputedGridLineInfo(nsTArray<nsTArray<nsString>>&& aNames,
72 : const nsTArray<nsString>& aNamesBefore,
73 : const nsTArray<nsString>& aNamesAfter)
74 0 : : mNames(aNames)
75 : , mNamesBefore(aNamesBefore)
76 0 : , mNamesAfter(aNamesAfter)
77 0 : {}
78 : nsTArray<nsTArray<nsString>> mNames;
79 : nsTArray<nsString> mNamesBefore;
80 : nsTArray<nsString> mNamesAfter;
81 : };
82 : } // namespace mozilla
83 :
84 0 : class nsGridContainerFrame final : public nsContainerFrame
85 : {
86 : public:
87 0 : NS_DECL_FRAMEARENA_HELPERS(nsGridContainerFrame)
88 : NS_DECL_QUERYFRAME
89 : typedef mozilla::ComputedGridTrackInfo ComputedGridTrackInfo;
90 : typedef mozilla::ComputedGridLineInfo ComputedGridLineInfo;
91 :
92 : // nsIFrame overrides
93 : void Reflow(nsPresContext* aPresContext,
94 : ReflowOutput& aDesiredSize,
95 : const ReflowInput& aReflowInput,
96 : nsReflowStatus& aStatus) override;
97 : nscoord GetMinISize(gfxContext* aRenderingContext) override;
98 : nscoord GetPrefISize(gfxContext* aRenderingContext) override;
99 : void MarkIntrinsicISizesDirty() override;
100 0 : bool IsFrameOfType(uint32_t aFlags) const override
101 : {
102 0 : return nsContainerFrame::IsFrameOfType(aFlags &
103 0 : ~nsIFrame::eCanContainOverflowContainers);
104 : }
105 :
106 : void BuildDisplayList(nsDisplayListBuilder* aBuilder,
107 : const nsRect& aDirtyRect,
108 : const nsDisplayListSet& aLists) override;
109 :
110 0 : nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const override
111 : {
112 0 : if (HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) {
113 : // Return a baseline synthesized from our margin-box.
114 0 : return nsContainerFrame::GetLogicalBaseline(aWM);
115 : }
116 : nscoord b;
117 0 : GetBBaseline(BaselineSharingGroup::eFirst, &b);
118 0 : return b;
119 : }
120 :
121 0 : bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
122 : nscoord* aBaseline) const override
123 : {
124 0 : return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline);
125 : }
126 :
127 0 : bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
128 : BaselineSharingGroup aBaselineGroup,
129 : nscoord* aBaseline) const override
130 : {
131 0 : if (HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) {
132 0 : return false;
133 : }
134 0 : return GetBBaseline(aBaselineGroup, aBaseline);
135 : }
136 :
137 : #ifdef DEBUG_FRAME_DUMP
138 : nsresult GetFrameName(nsAString& aResult) const override;
139 : #endif
140 :
141 : // nsContainerFrame overrides
142 : bool DrainSelfOverflowList() override;
143 : void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override;
144 : void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
145 : nsFrameList& aFrameList) override;
146 : void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
147 : uint16_t CSSAlignmentForAbsPosChild(
148 : const ReflowInput& aChildRI,
149 : mozilla::LogicalAxis aLogicalAxis) const override;
150 :
151 : #ifdef DEBUG
152 : void SetInitialChildList(ChildListID aListID,
153 : nsFrameList& aChildList) override;
154 : #endif
155 :
156 : /**
157 : * Return the containing block for aChild which MUST be an abs.pos. child
158 : * of a grid container. This is just a helper method for
159 : * nsAbsoluteContainingBlock::Reflow - it's not meant to be used elsewhere.
160 : */
161 : static const nsRect& GridItemCB(nsIFrame* aChild);
162 :
163 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridItemContainingBlockRect, nsRect)
164 :
165 : /**
166 : * These properties are created by a call to
167 : * nsGridContainerFrame::GetGridFrameWithComputedInfo, typically from
168 : * Element::GetGridFragments.
169 : */
170 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColTrackInfo, ComputedGridTrackInfo)
171 0 : const ComputedGridTrackInfo* GetComputedTemplateColumns()
172 : {
173 0 : const ComputedGridTrackInfo* info = GetProperty(GridColTrackInfo());
174 0 : MOZ_ASSERT(info, "Property generation wasn't requested.");
175 0 : return info;
176 : }
177 :
178 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo)
179 0 : const ComputedGridTrackInfo* GetComputedTemplateRows()
180 : {
181 0 : const ComputedGridTrackInfo* info = GetProperty(GridRowTrackInfo());
182 0 : MOZ_ASSERT(info, "Property generation wasn't requested.");
183 0 : return info;
184 : }
185 :
186 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColumnLineInfo, ComputedGridLineInfo)
187 0 : const ComputedGridLineInfo* GetComputedTemplateColumnLines()
188 : {
189 0 : const ComputedGridLineInfo* info = GetProperty(GridColumnLineInfo());
190 0 : MOZ_ASSERT(info, "Property generation wasn't requested.");
191 0 : return info;
192 : }
193 :
194 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo)
195 0 : const ComputedGridLineInfo* GetComputedTemplateRowLines()
196 : {
197 0 : const ComputedGridLineInfo* info = GetProperty(GridRowLineInfo());
198 0 : MOZ_ASSERT(info, "Property generation wasn't requested.");
199 0 : return info;
200 : }
201 :
202 : typedef nsBaseHashtable<nsStringHashKey,
203 : mozilla::css::GridNamedArea,
204 : mozilla::css::GridNamedArea> ImplicitNamedAreas;
205 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty,
206 : ImplicitNamedAreas)
207 0 : ImplicitNamedAreas* GetImplicitNamedAreas() const {
208 0 : return GetProperty(ImplicitNamedAreasProperty());
209 : }
210 :
211 : typedef nsTArray<mozilla::css::GridNamedArea> ExplicitNamedAreas;
212 0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty,
213 : ExplicitNamedAreas)
214 0 : ExplicitNamedAreas* GetExplicitNamedAreas() const {
215 0 : return GetProperty(ExplicitNamedAreasProperty());
216 : }
217 :
218 : /**
219 : * Return a containing grid frame, and ensure it has computed grid info
220 : * @return nullptr if aFrame has no grid container, or frame was destroyed
221 : * @note this might destroy layout/style data since it may flush layout
222 : */
223 : static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame);
224 :
225 : struct TrackSize;
226 : struct GridItemInfo;
227 : struct GridReflowInput;
228 : struct FindItemInGridOrderResult
229 : {
230 : // The first(last) item in (reverse) grid order.
231 : const GridItemInfo* mItem;
232 : // Does the above item span the first(last) track?
233 : bool mIsInEdgeTrack;
234 : };
235 : protected:
236 : static const uint32_t kAutoLine;
237 : // The maximum line number, in the zero-based translated grid.
238 : static const uint32_t kTranslatedMaxLine;
239 : typedef mozilla::LogicalPoint LogicalPoint;
240 : typedef mozilla::LogicalRect LogicalRect;
241 : typedef mozilla::LogicalSize LogicalSize;
242 : typedef mozilla::CSSOrderAwareFrameIterator CSSOrderAwareFrameIterator;
243 : typedef mozilla::ReverseCSSOrderAwareFrameIterator
244 : ReverseCSSOrderAwareFrameIterator;
245 : typedef mozilla::WritingMode WritingMode;
246 : typedef mozilla::css::GridNamedArea GridNamedArea;
247 : typedef mozilla::layout::AutoFrameListPtr AutoFrameListPtr;
248 : typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
249 : struct Grid;
250 : struct GridArea;
251 : class LineNameMap;
252 : struct LineRange;
253 : struct SharedGridData;
254 : struct TrackSizingFunctions;
255 : struct Tracks;
256 : struct TranslatedLineRange;
257 : friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
258 : nsStyleContext* aContext);
259 0 : explicit nsGridContainerFrame(nsStyleContext* aContext)
260 0 : : nsContainerFrame(aContext, kClassID)
261 : , mCachedMinISize(NS_INTRINSIC_WIDTH_UNKNOWN)
262 0 : , mCachedPrefISize(NS_INTRINSIC_WIDTH_UNKNOWN)
263 : {
264 0 : mBaseline[0][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
265 0 : mBaseline[0][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
266 0 : mBaseline[1][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
267 0 : mBaseline[1][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
268 0 : }
269 :
270 : /**
271 : * XXX temporary - move the ImplicitNamedAreas stuff to the style system.
272 : * The implicit area names that come from x-start .. x-end lines in
273 : * grid-template-columns / grid-template-rows are stored in this frame
274 : * property when needed, as a ImplicitNamedAreas* value.
275 : */
276 : void InitImplicitNamedAreas(const nsStylePosition* aStyle);
277 : void AddImplicitNamedAreas(const nsTArray<nsTArray<nsString>>& aLineNameLists);
278 :
279 : /**
280 : * Reflow and place our children.
281 : * @return the consumed size of all of this grid container's continuations
282 : * so far including this frame
283 : */
284 : nscoord ReflowChildren(GridReflowInput& aState,
285 : const LogicalRect& aContentArea,
286 : ReflowOutput& aDesiredSize,
287 : nsReflowStatus& aStatus);
288 :
289 : /**
290 : * Helper for GetMinISize / GetPrefISize.
291 : */
292 : nscoord IntrinsicISize(gfxContext* aRenderingContext,
293 : IntrinsicISizeType aConstraint);
294 :
295 : // Helper for AppendFrames / InsertFrames.
296 : void NoteNewChildren(ChildListID aListID, const nsFrameList& aFrameList);
297 :
298 : // Helper to move child frames into the kOverflowList.
299 : void MergeSortedOverflow(nsFrameList& aList);
300 : // Helper to move child frames into the kExcessOverflowContainersList:.
301 : void MergeSortedExcessOverflowContainers(nsFrameList& aList);
302 :
303 0 : bool GetBBaseline(BaselineSharingGroup aBaselineGroup, nscoord* aResult) const
304 : {
305 0 : *aResult = mBaseline[mozilla::eLogicalAxisBlock][aBaselineGroup];
306 0 : return true;
307 : }
308 0 : bool GetIBaseline(BaselineSharingGroup aBaselineGroup, nscoord* aResult) const
309 : {
310 0 : *aResult = mBaseline[mozilla::eLogicalAxisInline][aBaselineGroup];
311 0 : return true;
312 : }
313 :
314 : /**
315 : * Calculate this grid container's baselines.
316 : * @param aBaselineSet which baseline(s) to derive from a baseline-group or
317 : * items; a baseline not included is synthesized from the border-box instead.
318 : * @param aFragmentStartTrack is the first track in this fragment in the same
319 : * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
320 : * @param aFirstExcludedTrack should be the first track in the next fragment
321 : * or one beyond the final track in the last fragment, in aMajor's axis.
322 : * Pass the number of tracks if that's not the axis we're fragmenting in.
323 : */
324 : enum BaselineSet : uint32_t {
325 : eNone = 0x0,
326 : eFirst = 0x1,
327 : eLast = 0x2,
328 : eBoth = eFirst | eLast,
329 : };
330 : void CalculateBaselines(BaselineSet aBaselineSet,
331 : CSSOrderAwareFrameIterator* aIter,
332 : const nsTArray<GridItemInfo>* aGridItems,
333 : const Tracks& aTracks,
334 : uint32_t aFragmentStartTrack,
335 : uint32_t aFirstExcludedTrack,
336 : WritingMode aWM,
337 : const nsSize& aCBPhysicalSize,
338 : nscoord aCBBorderPaddingStart,
339 : nscoord aCBBorderPaddingStartEnd,
340 : nscoord aCBSize);
341 :
342 : /**
343 : * Synthesize a Grid container baseline for aGroup.
344 : */
345 : nscoord SynthesizeBaseline(const FindItemInGridOrderResult& aItem,
346 : mozilla::LogicalAxis aAxis,
347 : BaselineSharingGroup aGroup,
348 : const nsSize& aCBPhysicalSize,
349 : nscoord aCBSize,
350 : WritingMode aCBWM);
351 : /**
352 : * Find the first item in Grid Order in this fragment.
353 : * https://drafts.csswg.org/css-grid/#grid-order
354 : * @param aFragmentStartTrack is the first track in this fragment in the same
355 : * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
356 : */
357 : static FindItemInGridOrderResult
358 : FindFirstItemInGridOrder(CSSOrderAwareFrameIterator& aIter,
359 : const nsTArray<GridItemInfo>& aGridItems,
360 : LineRange GridArea::* aMajor,
361 : LineRange GridArea::* aMinor,
362 : uint32_t aFragmentStartTrack);
363 : /**
364 : * Find the last item in Grid Order in this fragment.
365 : * @param aFragmentStartTrack is the first track in this fragment in the same
366 : * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
367 : * @param aFirstExcludedTrack should be the first track in the next fragment
368 : * or one beyond the final track in the last fragment, in aMajor's axis.
369 : * Pass the number of tracks if that's not the axis we're fragmenting in.
370 : */
371 : static FindItemInGridOrderResult
372 : FindLastItemInGridOrder(ReverseCSSOrderAwareFrameIterator& aIter,
373 : const nsTArray<GridItemInfo>& aGridItems,
374 : LineRange GridArea::* aMajor,
375 : LineRange GridArea::* aMinor,
376 : uint32_t aFragmentStartTrack,
377 : uint32_t aFirstExcludedTrack);
378 :
379 : #ifdef DEBUG
380 : void SanityCheckGridItemsBeforeReflow() const;
381 : #endif // DEBUG
382 :
383 : private:
384 : // Helpers for ReflowChildren
385 : struct Fragmentainer {
386 : /**
387 : * The distance from the first grid container fragment's block-axis content
388 : * edge to the fragmentainer end.
389 : */
390 : nscoord mToFragmentainerEnd;
391 : /**
392 : * True if the current fragment is at the start of the fragmentainer.
393 : */
394 : bool mIsTopOfPage;
395 : /**
396 : * Is there a Class C break opportunity at the start content edge?
397 : */
398 : bool mCanBreakAtStart;
399 : /**
400 : * Is there a Class C break opportunity at the end content edge?
401 : */
402 : bool mCanBreakAtEnd;
403 : /**
404 : * Is the grid container's block-size unconstrained?
405 : */
406 : bool mIsAutoBSize;
407 : };
408 :
409 : mozilla::Maybe<nsGridContainerFrame::Fragmentainer>
410 : GetNearestFragmentainer(const GridReflowInput& aState) const;
411 :
412 : // @return the consumed size of all continuations so far including this frame
413 : nscoord ReflowInFragmentainer(GridReflowInput& aState,
414 : const LogicalRect& aContentArea,
415 : ReflowOutput& aDesiredSize,
416 : nsReflowStatus& aStatus,
417 : Fragmentainer& aFragmentainer,
418 : const nsSize& aContainerSize);
419 :
420 : // Helper for ReflowInFragmentainer
421 : // @return the consumed size of all continuations so far including this frame
422 : nscoord ReflowRowsInFragmentainer(GridReflowInput& aState,
423 : const LogicalRect& aContentArea,
424 : ReflowOutput& aDesiredSize,
425 : nsReflowStatus& aStatus,
426 : Fragmentainer& aFragmentainer,
427 : const nsSize& aContainerSize,
428 : const nsTArray<const GridItemInfo*>& aItems,
429 : uint32_t aStartRow,
430 : uint32_t aEndRow,
431 : nscoord aBSize,
432 : nscoord aAvailableSize);
433 :
434 : // Helper for ReflowChildren / ReflowInFragmentainer
435 : void ReflowInFlowChild(nsIFrame* aChild,
436 : const GridItemInfo* aGridItemInfo,
437 : nsSize aContainerSize,
438 : const mozilla::Maybe<nscoord>& aStretchBSize,
439 : const Fragmentainer* aFragmentainer,
440 : const GridReflowInput& aState,
441 : const LogicalRect& aContentArea,
442 : ReflowOutput& aDesiredSize,
443 : nsReflowStatus& aStatus);
444 :
445 : /**
446 : * Cached values to optimize GetMinISize/GetPrefISize.
447 : */
448 : nscoord mCachedMinISize;
449 : nscoord mCachedPrefISize;
450 :
451 : // Our baselines, one per BaselineSharingGroup per axis.
452 : nscoord mBaseline[2/*LogicalAxis*/][2/*BaselineSharingGroup*/];
453 :
454 : #ifdef DEBUG
455 : // If true, NS_STATE_GRID_DID_PUSH_ITEMS may be set even though all pushed
456 : // frames may have been removed. This is used to suppress an assertion
457 : // in case RemoveFrame removed all associated child frames.
458 : bool mDidPushItemsBitMayLie { false };
459 : #endif
460 : };
461 :
462 : #endif /* nsGridContainerFrame_h___ */
|