Coverage Report

Created: 2018-09-25 14:53

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