Bug 1800044 [wpt PR 36907] - Fix same URL navigation test, a=testonly
[gecko.git] / layout / generic / nsGridContainerFrame.h
blob09ace39f2e1e5ea87e97bb0ee09c4e7a690ae864
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/. */
7 /* rendering object for CSS "display: grid | inline-grid" */
9 #ifndef nsGridContainerFrame_h___
10 #define nsGridContainerFrame_h___
12 #include "mozilla/CSSOrderAwareFrameIterator.h"
13 #include "mozilla/MathAlgorithms.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/HashTable.h"
16 #include "nsContainerFrame.h"
17 #include "nsILineIterator.h"
19 namespace mozilla {
20 class PresShell;
21 } // namespace mozilla
23 /**
24 * Factory function.
25 * @return a newly allocated nsGridContainerFrame (infallible)
27 nsContainerFrame* NS_NewGridContainerFrame(mozilla::PresShell* aPresShell,
28 mozilla::ComputedStyle* aStyle);
30 namespace mozilla {
32 /**
33 * The number of implicit / explicit tracks and their sizes.
35 struct ComputedGridTrackInfo {
36 ComputedGridTrackInfo(
37 uint32_t aNumLeadingImplicitTracks, uint32_t aNumExplicitTracks,
38 uint32_t aStartFragmentTrack, uint32_t aEndFragmentTrack,
39 nsTArray<nscoord>&& aPositions, nsTArray<nscoord>&& aSizes,
40 nsTArray<uint32_t>&& aStates, nsTArray<bool>&& aRemovedRepeatTracks,
41 uint32_t aRepeatFirstTrack,
42 nsTArray<nsTArray<StyleCustomIdent>>&& aResolvedLineNames,
43 bool aIsSubgrid, bool aIsMasonry)
44 : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks),
45 mNumExplicitTracks(aNumExplicitTracks),
46 mStartFragmentTrack(aStartFragmentTrack),
47 mEndFragmentTrack(aEndFragmentTrack),
48 mPositions(std::move(aPositions)),
49 mSizes(std::move(aSizes)),
50 mStates(std::move(aStates)),
51 mRemovedRepeatTracks(std::move(aRemovedRepeatTracks)),
52 mResolvedLineNames(std::move(aResolvedLineNames)),
53 mRepeatFirstTrack(aRepeatFirstTrack),
54 mIsSubgrid(aIsSubgrid),
55 mIsMasonry(aIsMasonry) {}
56 uint32_t mNumLeadingImplicitTracks;
57 uint32_t mNumExplicitTracks;
58 uint32_t mStartFragmentTrack;
59 uint32_t mEndFragmentTrack;
60 nsTArray<nscoord> mPositions;
61 nsTArray<nscoord> mSizes;
62 nsTArray<uint32_t> mStates;
63 // Indicates if a track has been collapsed. This will be populated for each
64 // track in the repeat(auto-fit) and repeat(auto-fill), even if there are no
65 // collapsed tracks.
66 nsTArray<bool> mRemovedRepeatTracks;
67 // Contains lists of all line name lists, including the name lists inside
68 // repeats. When a repeat(auto) track exists, the internal track names will
69 // appear once each in this array.
70 nsTArray<nsTArray<StyleCustomIdent>> mResolvedLineNames;
71 uint32_t mRepeatFirstTrack;
72 bool mIsSubgrid;
73 bool mIsMasonry;
76 struct ComputedGridLineInfo {
77 explicit ComputedGridLineInfo(
78 nsTArray<nsTArray<RefPtr<nsAtom>>>&& aNames,
79 const nsTArray<RefPtr<nsAtom>>& aNamesBefore,
80 const nsTArray<RefPtr<nsAtom>>& aNamesAfter,
81 nsTArray<RefPtr<nsAtom>>&& aNamesFollowingRepeat)
82 : mNames(std::move(aNames)),
83 mNamesBefore(aNamesBefore.Clone()),
84 mNamesAfter(aNamesAfter.Clone()),
85 mNamesFollowingRepeat(std::move(aNamesFollowingRepeat)) {}
86 nsTArray<nsTArray<RefPtr<nsAtom>>> mNames;
87 nsTArray<RefPtr<nsAtom>> mNamesBefore;
88 nsTArray<RefPtr<nsAtom>> mNamesAfter;
89 nsTArray<RefPtr<nsAtom>> mNamesFollowingRepeat;
91 } // namespace mozilla
93 class nsGridContainerFrame final : public nsContainerFrame,
94 public nsILineIterator {
95 public:
96 NS_DECL_FRAMEARENA_HELPERS(nsGridContainerFrame)
97 NS_DECL_QUERYFRAME
98 using ComputedGridTrackInfo = mozilla::ComputedGridTrackInfo;
99 using ComputedGridLineInfo = mozilla::ComputedGridLineInfo;
100 using LogicalAxis = mozilla::LogicalAxis;
101 using BaselineSharingGroup = mozilla::BaselineSharingGroup;
102 using NamedArea = mozilla::StyleNamedArea;
104 template <typename T>
105 using PerBaseline = mozilla::EnumeratedArray<BaselineSharingGroup,
106 BaselineSharingGroup(2), T>;
108 template <typename T>
109 using PerLogicalAxis =
110 mozilla::EnumeratedArray<LogicalAxis, LogicalAxis(2), T>;
112 // nsIFrame overrides
113 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
114 const ReflowInput& aReflowInput,
115 nsReflowStatus& aStatus) override;
116 void Init(nsIContent* aContent, nsContainerFrame* aParent,
117 nsIFrame* aPrevInFlow) override;
118 void DidSetComputedStyle(ComputedStyle* aOldStyle) override;
119 nscoord GetMinISize(gfxContext* aRenderingContext) override;
120 nscoord GetPrefISize(gfxContext* aRenderingContext) override;
121 void MarkIntrinsicISizesDirty() override;
122 bool IsFrameOfType(uint32_t aFlags) const override {
123 return nsContainerFrame::IsFrameOfType(
124 aFlags & ~nsIFrame::eCanContainOverflowContainers);
127 void BuildDisplayList(nsDisplayListBuilder* aBuilder,
128 const nsDisplayListSet& aLists) override;
130 nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const override {
131 if (HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) {
132 // Return a baseline synthesized from our margin-box.
133 return nsContainerFrame::GetLogicalBaseline(aWM);
135 nscoord b;
136 GetBBaseline(BaselineSharingGroup::First, &b);
137 return b;
140 bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
141 nscoord* aBaseline) const override {
142 return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::First,
143 aBaseline);
146 bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
147 BaselineSharingGroup aBaselineGroup,
148 nscoord* aBaseline) const override {
149 if (StyleDisplay()->IsContainLayout() ||
150 HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) {
151 return false;
153 return GetBBaseline(aBaselineGroup, aBaseline);
156 #ifdef DEBUG_FRAME_DUMP
157 nsresult GetFrameName(nsAString& aResult) const override;
158 void ExtraContainerFrameInfo(nsACString& aTo) const override;
159 #endif
161 // nsContainerFrame overrides
162 bool DrainSelfOverflowList() override;
163 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override;
164 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
165 const nsLineList::iterator* aPrevFrameLine,
166 nsFrameList&& aFrameList) override;
167 void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
168 mozilla::StyleAlignFlags CSSAlignmentForAbsPosChild(
169 const ReflowInput& aChildRI, LogicalAxis aLogicalAxis) const override;
171 #ifdef DEBUG
172 void SetInitialChildList(ChildListID aListID,
173 nsFrameList&& aChildList) override;
174 #endif
177 * Return the containing block for aChild which MUST be an abs.pos. child
178 * of a grid container and that container must have been reflowed.
180 static const nsRect& GridItemCB(nsIFrame* aChild);
182 NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridItemContainingBlockRect, nsRect)
185 * These properties are created by a call to
186 * nsGridContainerFrame::GetGridFrameWithComputedInfo, typically from
187 * Element::GetGridFragments.
189 NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColTrackInfo, ComputedGridTrackInfo)
190 const ComputedGridTrackInfo* GetComputedTemplateColumns() {
191 const ComputedGridTrackInfo* info = GetProperty(GridColTrackInfo());
192 MOZ_ASSERT(info, "Property generation wasn't requested.");
193 return info;
196 NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo)
197 const ComputedGridTrackInfo* GetComputedTemplateRows() {
198 const ComputedGridTrackInfo* info = GetProperty(GridRowTrackInfo());
199 MOZ_ASSERT(info, "Property generation wasn't requested.");
200 return info;
203 NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColumnLineInfo, ComputedGridLineInfo)
204 const ComputedGridLineInfo* GetComputedTemplateColumnLines() {
205 const ComputedGridLineInfo* info = GetProperty(GridColumnLineInfo());
206 MOZ_ASSERT(info, "Property generation wasn't requested.");
207 return info;
210 NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo)
211 const ComputedGridLineInfo* GetComputedTemplateRowLines() {
212 const ComputedGridLineInfo* info = GetProperty(GridRowLineInfo());
213 MOZ_ASSERT(info, "Property generation wasn't requested.");
214 return info;
217 struct AtomKey {
218 RefPtr<nsAtom> mKey;
220 explicit AtomKey(nsAtom* aAtom) : mKey(aAtom) {}
222 using Lookup = nsAtom*;
224 static mozilla::HashNumber hash(const Lookup& aKey) { return aKey->hash(); }
226 static bool match(const AtomKey& aFirst, const Lookup& aSecond) {
227 return aFirst.mKey == aSecond;
231 using ImplicitNamedAreas = mozilla::HashMap<AtomKey, NamedArea, AtomKey>;
232 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty,
233 ImplicitNamedAreas)
234 ImplicitNamedAreas* GetImplicitNamedAreas() const {
235 return GetProperty(ImplicitNamedAreasProperty());
238 using ExplicitNamedAreas = mozilla::StyleOwnedSlice<NamedArea>;
239 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty,
240 ExplicitNamedAreas)
241 ExplicitNamedAreas* GetExplicitNamedAreas() const {
242 return GetProperty(ExplicitNamedAreasProperty());
245 using nsContainerFrame::IsMasonry;
247 /** Return true if this frame has masonry layout in any axis. */
248 bool IsMasonry() const {
249 return HasAnyStateBits(NS_STATE_GRID_IS_ROW_MASONRY |
250 NS_STATE_GRID_IS_COL_MASONRY);
253 /** Return true if this frame is subgridded in its aAxis. */
254 bool IsSubgrid(LogicalAxis aAxis) const {
255 return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
256 ? NS_STATE_GRID_IS_ROW_SUBGRID
257 : NS_STATE_GRID_IS_COL_SUBGRID);
259 bool IsColSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisInline); }
260 bool IsRowSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisBlock); }
261 /** Return true if this frame is subgridded in any axis. */
262 bool IsSubgrid() const {
263 return HasAnyStateBits(NS_STATE_GRID_IS_ROW_SUBGRID |
264 NS_STATE_GRID_IS_COL_SUBGRID);
267 /** Return true if this frame has an item that is subgridded in our aAxis. */
268 bool HasSubgridItems(LogicalAxis aAxis) const {
269 return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
270 ? NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM
271 : NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
273 /** Return true if this frame has any subgrid items. */
274 bool HasSubgridItems() const {
275 return HasAnyStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM |
276 NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
280 * Return a container grid frame for the supplied frame, if available.
281 * @return nullptr if aFrame has no grid container.
283 static nsGridContainerFrame* GetGridContainerFrame(nsIFrame* aFrame);
286 * Return a container grid frame, and ensure it has computed grid info
287 * @return nullptr if aFrame has no grid container, or frame was destroyed
288 * @note this might destroy layout/style data since it may flush layout
290 MOZ_CAN_RUN_SCRIPT_BOUNDARY
291 static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame);
293 struct Subgrid;
294 struct UsedTrackSizes;
295 struct TrackSize;
296 struct GridItemInfo;
297 struct GridReflowInput;
298 struct FindItemInGridOrderResult {
299 // The first(last) item in (reverse) grid order.
300 const GridItemInfo* mItem;
301 // Does the above item span the first(last) track?
302 bool mIsInEdgeTrack;
305 /** Return our parent grid container; |this| MUST be a subgrid. */
306 nsGridContainerFrame* ParentGridContainerForSubgrid() const;
308 // https://drafts.csswg.org/css-sizing/#constraints
309 enum class SizingConstraint {
310 MinContent, // sizing under min-content constraint
311 MaxContent, // sizing under max-content constraint
312 NoConstraint // no constraint, used during Reflow
315 protected:
316 typedef mozilla::LogicalPoint LogicalPoint;
317 typedef mozilla::LogicalRect LogicalRect;
318 typedef mozilla::LogicalSize LogicalSize;
319 typedef mozilla::WritingMode WritingMode;
320 struct Grid;
321 struct GridArea;
322 class LineNameMap;
323 struct LineRange;
324 struct SharedGridData;
325 struct SubgridFallbackTrackSizingFunctions;
326 struct TrackSizingFunctions;
327 struct Tracks;
328 struct TranslatedLineRange;
329 friend nsContainerFrame* NS_NewGridContainerFrame(
330 mozilla::PresShell* aPresShell, ComputedStyle* aStyle);
331 explicit nsGridContainerFrame(ComputedStyle* aStyle,
332 nsPresContext* aPresContext)
333 : nsContainerFrame(aStyle, aPresContext, kClassID),
334 mCachedMinISize(NS_INTRINSIC_ISIZE_UNKNOWN),
335 mCachedPrefISize(NS_INTRINSIC_ISIZE_UNKNOWN) {
336 for (auto& perAxisBaseline : mBaseline) {
337 for (auto& baseline : perAxisBaseline) {
338 baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
344 * XXX temporary - move the ImplicitNamedAreas stuff to the style system.
345 * The implicit area names that come from x-start .. x-end lines in
346 * grid-template-columns / grid-template-rows are stored in this frame
347 * property when needed, as a ImplicitNamedAreas* value.
349 void InitImplicitNamedAreas(const nsStylePosition* aStyle);
351 using LineNameList =
352 const mozilla::StyleOwnedSlice<mozilla::StyleCustomIdent>;
353 void AddImplicitNamedAreas(mozilla::Span<LineNameList>);
356 * Reflow and place our children.
357 * @return the consumed size of all of this grid container's continuations
358 * so far including this frame
360 nscoord ReflowChildren(GridReflowInput& aState,
361 const LogicalRect& aContentArea,
362 const nsSize& aContainerSize,
363 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus);
366 * Helper for GetMinISize / GetPrefISize.
368 nscoord IntrinsicISize(gfxContext* aRenderingContext,
369 mozilla::IntrinsicISizeType aConstraint);
371 bool GetBBaseline(BaselineSharingGroup aBaselineGroup,
372 nscoord* aResult) const {
373 *aResult = mBaseline[mozilla::eLogicalAxisBlock][aBaselineGroup];
374 return true;
376 bool GetIBaseline(BaselineSharingGroup aBaselineGroup,
377 nscoord* aResult) const {
378 *aResult = mBaseline[mozilla::eLogicalAxisInline][aBaselineGroup];
379 return true;
383 * Calculate this grid container's baselines.
384 * @param aBaselineSet which baseline(s) to derive from a baseline-group or
385 * items; a baseline not included is synthesized from the border-box instead.
386 * @param aFragmentStartTrack is the first track in this fragment in the same
387 * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
388 * @param aFirstExcludedTrack should be the first track in the next fragment
389 * or one beyond the final track in the last fragment, in aMajor's axis.
390 * Pass the number of tracks if that's not the axis we're fragmenting in.
392 enum BaselineSet : uint32_t {
393 eNone = 0x0,
394 eFirst = 0x1,
395 eLast = 0x2,
396 eBoth = eFirst | eLast,
398 void CalculateBaselines(BaselineSet aBaselineSet,
399 mozilla::CSSOrderAwareFrameIterator* aIter,
400 const nsTArray<GridItemInfo>* aGridItems,
401 const Tracks& aTracks, uint32_t aFragmentStartTrack,
402 uint32_t aFirstExcludedTrack, WritingMode aWM,
403 const nsSize& aCBPhysicalSize,
404 nscoord aCBBorderPaddingStart,
405 nscoord aCBBorderPaddingStartEnd, nscoord aCBSize);
408 * Synthesize a Grid container baseline for aGroup.
410 nscoord SynthesizeBaseline(const FindItemInGridOrderResult& aItem,
411 LogicalAxis aAxis, BaselineSharingGroup aGroup,
412 const nsSize& aCBPhysicalSize, nscoord aCBSize,
413 WritingMode aCBWM);
415 * Find the first item in Grid Order in this fragment.
416 * https://drafts.csswg.org/css-grid/#grid-order
417 * @param aFragmentStartTrack is the first track in this fragment in the same
418 * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
420 static FindItemInGridOrderResult FindFirstItemInGridOrder(
421 mozilla::CSSOrderAwareFrameIterator& aIter,
422 const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::*aMajor,
423 LineRange GridArea::*aMinor, uint32_t aFragmentStartTrack);
425 * Find the last item in Grid Order in this fragment.
426 * @param aFragmentStartTrack is the first track in this fragment in the same
427 * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
428 * @param aFirstExcludedTrack should be the first track in the next fragment
429 * or one beyond the final track in the last fragment, in aMajor's axis.
430 * Pass the number of tracks if that's not the axis we're fragmenting in.
432 static FindItemInGridOrderResult FindLastItemInGridOrder(
433 mozilla::ReverseCSSOrderAwareFrameIterator& aIter,
434 const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::*aMajor,
435 LineRange GridArea::*aMinor, uint32_t aFragmentStartTrack,
436 uint32_t aFirstExcludedTrack);
439 * Update our NS_STATE_GRID_IS_COL/ROW_SUBGRID bits and related subgrid state
440 * on our entire continuation chain based on the current style.
441 * This is needed because grid-template-columns/rows style changes only
442 * trigger a reflow so we need to update this dynamically.
444 void UpdateSubgridFrameState();
447 * Return the NS_STATE_GRID_IS_COL/ROW_SUBGRID and
448 * NS_STATE_GRID_IS_ROW/COL_MASONRY bits we ought to have.
450 nsFrameState ComputeSelfSubgridMasonryBits() const;
452 /** Helper for ComputeSelfSubgridMasonryBits(). */
453 bool WillHaveAtLeastOneTrackInAxis(LogicalAxis aAxis) const;
455 private:
456 // Helpers for ReflowChildren
457 struct Fragmentainer {
459 * The distance from the first grid container fragment's block-axis content
460 * edge to the fragmentainer end.
462 nscoord mToFragmentainerEnd;
464 * True if the current fragment is at the start of the fragmentainer.
466 bool mIsTopOfPage;
468 * Is there a Class C break opportunity at the start content edge?
470 bool mCanBreakAtStart;
472 * Is there a Class C break opportunity at the end content edge?
474 bool mCanBreakAtEnd;
476 * Is the grid container's block-size unconstrained?
478 bool mIsAutoBSize;
481 mozilla::Maybe<nsGridContainerFrame::Fragmentainer> GetNearestFragmentainer(
482 const GridReflowInput& aState) const;
484 // @return the consumed size of all continuations so far including this frame
485 nscoord ReflowInFragmentainer(GridReflowInput& aState,
486 const LogicalRect& aContentArea,
487 ReflowOutput& aDesiredSize,
488 nsReflowStatus& aStatus,
489 Fragmentainer& aFragmentainer,
490 const nsSize& aContainerSize);
492 // Helper for ReflowInFragmentainer
493 // @return the consumed size of all continuations so far including this frame
494 nscoord ReflowRowsInFragmentainer(
495 GridReflowInput& aState, const LogicalRect& aContentArea,
496 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
497 Fragmentainer& aFragmentainer, const nsSize& aContainerSize,
498 const nsTArray<const GridItemInfo*>& aItems, uint32_t aStartRow,
499 uint32_t aEndRow, nscoord aBSize, nscoord aAvailableSize);
501 // Helper for ReflowChildren / ReflowInFragmentainer
502 void ReflowInFlowChild(nsIFrame* aChild, const GridItemInfo* aGridItemInfo,
503 nsSize aContainerSize,
504 const mozilla::Maybe<nscoord>& aStretchBSize,
505 const Fragmentainer* aFragmentainer,
506 const GridReflowInput& aState,
507 const LogicalRect& aContentArea,
508 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus);
511 * Places and reflows items when we have masonry layout.
512 * It handles unconstrained reflow and also fragmentation when the row axis
513 * is the masonry axis. ReflowInFragmentainer handles the case when we're
514 * fragmenting and our row axis is a grid axis and it handles masonry layout
515 * in the column axis in that case.
516 * @return the intrinsic size in the masonry axis
518 nscoord MasonryLayout(GridReflowInput& aState,
519 const LogicalRect& aContentArea,
520 SizingConstraint aConstraint,
521 ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
522 Fragmentainer* aFragmentainer,
523 const nsSize& aContainerSize);
525 // Return the stored UsedTrackSizes, if any.
526 UsedTrackSizes* GetUsedTrackSizes() const;
528 // Store the given TrackSizes in aAxis on a UsedTrackSizes frame property.
529 void StoreUsedTrackSizes(LogicalAxis aAxis,
530 const nsTArray<TrackSize>& aSizes);
533 * Cached values to optimize GetMinISize/GetPrefISize.
535 nscoord mCachedMinISize;
536 nscoord mCachedPrefISize;
538 // Our baselines, one per BaselineSharingGroup per axis.
539 PerLogicalAxis<PerBaseline<nscoord>> mBaseline;
541 public:
542 // A cached result for a grid item's block-axis measuring reflow. This
543 // cache prevents us from doing exponential reflows in cases of deeply
544 // nested grid frames.
546 // We store the cached value in the grid item's frame property table.
548 // We cache the following as a "key"
549 // - The size of the grid area in the item's inline axis
550 // - The item's block axis baseline padding
551 // ...and we cache the following as the "value",
552 // - The item's border-box BSize
553 class CachedBAxisMeasurement {
554 public:
555 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(Prop, CachedBAxisMeasurement)
556 CachedBAxisMeasurement(const nsIFrame* aFrame, const LogicalSize& aCBSize,
557 const nscoord aBSize)
558 : mKey(aFrame, aCBSize), mBSize(aBSize) {}
560 CachedBAxisMeasurement() = default;
562 bool IsValidFor(const nsIFrame* aFrame, const LogicalSize& aCBSize) const {
563 if (aFrame->IsSubtreeDirty()) {
564 return false;
567 if (!CanCacheMeasurement(aFrame, aCBSize)) {
568 return false;
571 return mKey == Key(aFrame, aCBSize);
574 static bool CanCacheMeasurement(const nsIFrame* aFrame,
575 const LogicalSize& aCBSize) {
576 return Key::CanHash(aFrame, aCBSize);
579 nscoord BSize() const { return mBSize; }
581 void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize,
582 const nscoord aBSize) {
583 MOZ_ASSERT(CanCacheMeasurement(aFrame, aCBSize));
584 mKey.mHashKey = Key::GenerateHash(aFrame, aCBSize);
585 mBSize = aBSize;
588 private:
589 struct Key {
590 // mHashKey is generated by combining these 2 variables together
591 // 1. The containing block size in the item's inline axis used
592 // for measuring reflow
593 // 2. The item's baseline padding property
594 uint32_t mHashKey;
596 Key() = default;
598 Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
599 MOZ_ASSERT(CanHash(aFrame, aCBSize));
600 mHashKey = GenerateHash(aFrame, aCBSize);
603 void UpdateHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
604 MOZ_ASSERT(CanHash(aFrame, aCBSize));
605 mHashKey = GenerateHash(aFrame, aCBSize);
608 static uint32_t GenerateHash(const nsIFrame* aFrame,
609 const LogicalSize& aCBSize) {
610 MOZ_ASSERT(CanHash(aFrame, aCBSize));
612 nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode());
613 nscoord bBaselinePaddingProperty =
614 abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()));
616 uint_fast8_t bitsNeededForISize = mozilla::FloorLog2(gridAreaISize) + 1;
618 return (gridAreaISize << (32 - bitsNeededForISize)) |
619 bBaselinePaddingProperty;
622 static bool CanHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
623 uint_fast8_t bitsNeededForISize =
624 mozilla::FloorLog2(aCBSize.ISize(aFrame->GetWritingMode())) + 1;
626 uint_fast8_t bitsNeededForBBaselinePadding =
627 mozilla::FloorLog2(
628 abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()))) +
631 return bitsNeededForISize + bitsNeededForBBaselinePadding <= 32;
634 bool operator==(const Key& aOther) const {
635 return mHashKey == aOther.mHashKey;
639 Key mKey;
640 nscoord mBSize;
643 bool CanProvideLineIterator() const final { return true; }
644 nsILineIterator* GetLineIterator() final { return this; }
645 int32_t GetNumLines() const final;
646 bool IsLineIteratorFlowRTL() final;
647 mozilla::Result<LineInfo, nsresult> GetLine(int32_t aLineNumber) final;
648 int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) final;
649 NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos,
650 nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame,
651 bool* aPosIsAfterLastFrame) final;
652 NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered,
653 nsIFrame** aFirstVisual,
654 nsIFrame** aLastVisual) final;
657 #endif /* nsGridContainerFrame_h___ */