summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsGridContainerFrame.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--layout/generic/nsGridContainerFrame.h652
1 files changed, 652 insertions, 0 deletions
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h
new file mode 100644
index 0000000000..72c5073e47
--- /dev/null
+++ b/layout/generic/nsGridContainerFrame.h
@@ -0,0 +1,652 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* rendering object for CSS "display: grid | inline-grid" */
+
+#ifndef nsGridContainerFrame_h___
+#define nsGridContainerFrame_h___
+
+#include "mozilla/CSSOrderAwareFrameIterator.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/HashTable.h"
+#include "nsContainerFrame.h"
+#include "nsILineIterator.h"
+
+namespace mozilla {
+class PresShell;
+namespace dom {
+class Grid;
+}
+} // namespace mozilla
+
+/**
+ * Factory function.
+ * @return a newly allocated nsGridContainerFrame (infallible)
+ */
+nsContainerFrame* NS_NewGridContainerFrame(mozilla::PresShell* aPresShell,
+ mozilla::ComputedStyle* aStyle);
+
+namespace mozilla {
+
+/**
+ * The number of implicit / explicit tracks and their sizes.
+ */
+struct ComputedGridTrackInfo {
+ ComputedGridTrackInfo(
+ uint32_t aNumLeadingImplicitTracks, uint32_t aNumExplicitTracks,
+ uint32_t aStartFragmentTrack, uint32_t aEndFragmentTrack,
+ nsTArray<nscoord>&& aPositions, nsTArray<nscoord>&& aSizes,
+ nsTArray<uint32_t>&& aStates, nsTArray<bool>&& aRemovedRepeatTracks,
+ uint32_t aRepeatFirstTrack,
+ nsTArray<nsTArray<StyleCustomIdent>>&& aResolvedLineNames,
+ bool aIsSubgrid, bool aIsMasonry)
+ : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks),
+ mNumExplicitTracks(aNumExplicitTracks),
+ mStartFragmentTrack(aStartFragmentTrack),
+ mEndFragmentTrack(aEndFragmentTrack),
+ mPositions(std::move(aPositions)),
+ mSizes(std::move(aSizes)),
+ mStates(std::move(aStates)),
+ mRemovedRepeatTracks(std::move(aRemovedRepeatTracks)),
+ mResolvedLineNames(std::move(aResolvedLineNames)),
+ mRepeatFirstTrack(aRepeatFirstTrack),
+ mIsSubgrid(aIsSubgrid),
+ mIsMasonry(aIsMasonry) {}
+ uint32_t mNumLeadingImplicitTracks;
+ uint32_t mNumExplicitTracks;
+ uint32_t mStartFragmentTrack;
+ uint32_t mEndFragmentTrack;
+ nsTArray<nscoord> mPositions;
+ nsTArray<nscoord> mSizes;
+ nsTArray<uint32_t> mStates;
+ // Indicates if a track has been collapsed. This will be populated for each
+ // track in the repeat(auto-fit) and repeat(auto-fill), even if there are no
+ // collapsed tracks.
+ nsTArray<bool> mRemovedRepeatTracks;
+ // Contains lists of all line name lists, including the name lists inside
+ // repeats. When a repeat(auto) track exists, the internal track names will
+ // appear once each in this array.
+ nsTArray<nsTArray<StyleCustomIdent>> mResolvedLineNames;
+ uint32_t mRepeatFirstTrack;
+ bool mIsSubgrid;
+ bool mIsMasonry;
+};
+
+struct ComputedGridLineInfo {
+ explicit ComputedGridLineInfo(
+ nsTArray<nsTArray<RefPtr<nsAtom>>>&& aNames,
+ const nsTArray<RefPtr<nsAtom>>& aNamesBefore,
+ const nsTArray<RefPtr<nsAtom>>& aNamesAfter,
+ nsTArray<RefPtr<nsAtom>>&& aNamesFollowingRepeat)
+ : mNames(std::move(aNames)),
+ mNamesBefore(aNamesBefore.Clone()),
+ mNamesAfter(aNamesAfter.Clone()),
+ mNamesFollowingRepeat(std::move(aNamesFollowingRepeat)) {}
+ nsTArray<nsTArray<RefPtr<nsAtom>>> mNames;
+ nsTArray<RefPtr<nsAtom>> mNamesBefore;
+ nsTArray<RefPtr<nsAtom>> mNamesAfter;
+ nsTArray<RefPtr<nsAtom>> mNamesFollowingRepeat;
+};
+} // namespace mozilla
+
+class nsGridContainerFrame final : public nsContainerFrame,
+ public nsILineIterator {
+ public:
+ NS_DECL_FRAMEARENA_HELPERS(nsGridContainerFrame)
+ NS_DECL_QUERYFRAME
+ using ComputedGridTrackInfo = mozilla::ComputedGridTrackInfo;
+ using ComputedGridLineInfo = mozilla::ComputedGridLineInfo;
+ using LogicalAxis = mozilla::LogicalAxis;
+ using BaselineSharingGroup = mozilla::BaselineSharingGroup;
+ using NamedArea = mozilla::StyleNamedArea;
+
+ template <typename T>
+ using PerBaseline = mozilla::EnumeratedArray<BaselineSharingGroup,
+ BaselineSharingGroup(2), T>;
+
+ template <typename T>
+ using PerLogicalAxis =
+ mozilla::EnumeratedArray<LogicalAxis, LogicalAxis(2), T>;
+
+ // nsIFrame overrides
+ void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
+ void Init(nsIContent* aContent, nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow) override;
+ void DidSetComputedStyle(ComputedStyle* aOldStyle) override;
+ nscoord GetMinISize(gfxContext* aRenderingContext) override;
+ nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+ void MarkIntrinsicISizesDirty() override;
+ bool IsFrameOfType(uint32_t aFlags) const override {
+ return nsContainerFrame::IsFrameOfType(
+ aFlags & ~nsIFrame::eCanContainOverflowContainers);
+ }
+
+ void BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists) override;
+
+ Maybe<nscoord> GetNaturalBaselineBOffset(
+ mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
+ BaselineExportContext) const override {
+ if (StyleDisplay()->IsContainLayout() ||
+ HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) {
+ return Nothing{};
+ }
+ return mozilla::Some(GetBBaseline(aBaselineGroup));
+ }
+
+#ifdef DEBUG_FRAME_DUMP
+ nsresult GetFrameName(nsAString& aResult) const override;
+ void ExtraContainerFrameInfo(nsACString& aTo) const override;
+#endif
+
+ // nsContainerFrame overrides
+ bool DrainSelfOverflowList() override;
+ void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override;
+ void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
+ const nsLineList::iterator* aPrevFrameLine,
+ nsFrameList&& aFrameList) override;
+ void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override;
+ mozilla::StyleAlignFlags CSSAlignmentForAbsPosChild(
+ const ReflowInput& aChildRI, LogicalAxis aLogicalAxis) const override;
+
+#ifdef DEBUG
+ void SetInitialChildList(ChildListID aListID,
+ nsFrameList&& aChildList) override;
+#endif
+
+ /**
+ * Return the containing block for aChild which MUST be an abs.pos. child
+ * of a grid container and that container must have been reflowed.
+ */
+ static const nsRect& GridItemCB(nsIFrame* aChild);
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridItemContainingBlockRect, nsRect)
+
+ /**
+ * These properties are created by a call to
+ * nsGridContainerFrame::GetGridFrameWithComputedInfo, typically from
+ * Element::GetGridFragments.
+ */
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColTrackInfo, ComputedGridTrackInfo)
+ const ComputedGridTrackInfo* GetComputedTemplateColumns() {
+ const ComputedGridTrackInfo* info = GetProperty(GridColTrackInfo());
+ MOZ_ASSERT(info, "Property generation wasn't requested.");
+ return info;
+ }
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo)
+ const ComputedGridTrackInfo* GetComputedTemplateRows() {
+ const ComputedGridTrackInfo* info = GetProperty(GridRowTrackInfo());
+ MOZ_ASSERT(info, "Property generation wasn't requested.");
+ return info;
+ }
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColumnLineInfo, ComputedGridLineInfo)
+ const ComputedGridLineInfo* GetComputedTemplateColumnLines() {
+ const ComputedGridLineInfo* info = GetProperty(GridColumnLineInfo());
+ MOZ_ASSERT(info, "Property generation wasn't requested.");
+ return info;
+ }
+
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo)
+ const ComputedGridLineInfo* GetComputedTemplateRowLines() {
+ const ComputedGridLineInfo* info = GetProperty(GridRowLineInfo());
+ MOZ_ASSERT(info, "Property generation wasn't requested.");
+ return info;
+ }
+
+ /**
+ * This property is set by the creation of a dom::Grid object, and cleared
+ * during GC unlink. Since the Grid object manages the lifecycle, the property
+ * itself is set without a destructor. The property is also cleared whenever
+ * new grid computed info is generated during reflow, ensuring that we aren't
+ * holding a stale dom::Grid object.
+ */
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(GridFragmentInfo, mozilla::dom::Grid)
+ mozilla::dom::Grid* GetGridFragmentInfo() {
+ return GetProperty(GridFragmentInfo());
+ }
+
+ struct AtomKey {
+ RefPtr<nsAtom> mKey;
+
+ explicit AtomKey(nsAtom* aAtom) : mKey(aAtom) {}
+
+ using Lookup = nsAtom*;
+
+ static mozilla::HashNumber hash(const Lookup& aKey) { return aKey->hash(); }
+
+ static bool match(const AtomKey& aFirst, const Lookup& aSecond) {
+ return aFirst.mKey == aSecond;
+ }
+ };
+
+ using ImplicitNamedAreas = mozilla::HashMap<AtomKey, NamedArea, AtomKey>;
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty,
+ ImplicitNamedAreas)
+ ImplicitNamedAreas* GetImplicitNamedAreas() const {
+ return GetProperty(ImplicitNamedAreasProperty());
+ }
+
+ using ExplicitNamedAreas = mozilla::StyleOwnedSlice<NamedArea>;
+ NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty,
+ ExplicitNamedAreas)
+ ExplicitNamedAreas* GetExplicitNamedAreas() const {
+ return GetProperty(ExplicitNamedAreasProperty());
+ }
+
+ using nsContainerFrame::IsMasonry;
+
+ /** Return true if this frame has masonry layout in any axis. */
+ bool IsMasonry() const {
+ return HasAnyStateBits(NS_STATE_GRID_IS_ROW_MASONRY |
+ NS_STATE_GRID_IS_COL_MASONRY);
+ }
+
+ /** Return true if this frame is subgridded in its aAxis. */
+ bool IsSubgrid(LogicalAxis aAxis) const {
+ return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
+ ? NS_STATE_GRID_IS_ROW_SUBGRID
+ : NS_STATE_GRID_IS_COL_SUBGRID);
+ }
+ bool IsColSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisInline); }
+ bool IsRowSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisBlock); }
+ /** Return true if this frame is subgridded in any axis. */
+ bool IsSubgrid() const {
+ return HasAnyStateBits(NS_STATE_GRID_IS_ROW_SUBGRID |
+ NS_STATE_GRID_IS_COL_SUBGRID);
+ }
+
+ /** Return true if this frame has an item that is subgridded in our aAxis. */
+ bool HasSubgridItems(LogicalAxis aAxis) const {
+ return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
+ ? NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM
+ : NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
+ }
+ /** Return true if this frame has any subgrid items. */
+ bool HasSubgridItems() const {
+ return HasAnyStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM |
+ NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
+ }
+
+ /**
+ * Return a container grid frame for the supplied frame, if available.
+ * @return nullptr if aFrame has no grid container.
+ */
+ static nsGridContainerFrame* GetGridContainerFrame(nsIFrame* aFrame);
+
+ /**
+ * Return a container grid frame, and ensure it has computed grid info
+ * @return nullptr if aFrame has no grid container, or frame was destroyed
+ * @note this might destroy layout/style data since it may flush layout
+ */
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY
+ static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame);
+
+ struct Subgrid;
+ struct UsedTrackSizes;
+ struct TrackSize;
+ struct GridItemInfo;
+ struct GridReflowInput;
+ struct FindItemInGridOrderResult {
+ // The first(last) item in (reverse) grid order.
+ const GridItemInfo* mItem;
+ // Does the above item span the first(last) track?
+ bool mIsInEdgeTrack;
+ };
+
+ /** Return our parent grid container; |this| MUST be a subgrid. */
+ nsGridContainerFrame* ParentGridContainerForSubgrid() const;
+
+ // https://drafts.csswg.org/css-sizing/#constraints
+ enum class SizingConstraint {
+ MinContent, // sizing under min-content constraint
+ MaxContent, // sizing under max-content constraint
+ NoConstraint // no constraint, used during Reflow
+ };
+
+ protected:
+ typedef mozilla::LogicalPoint LogicalPoint;
+ typedef mozilla::LogicalRect LogicalRect;
+ typedef mozilla::LogicalSize LogicalSize;
+ typedef mozilla::WritingMode WritingMode;
+ struct Grid;
+ struct GridArea;
+ class LineNameMap;
+ struct LineRange;
+ struct SharedGridData;
+ struct SubgridFallbackTrackSizingFunctions;
+ struct TrackSizingFunctions;
+ struct Tracks;
+ struct TranslatedLineRange;
+ friend nsContainerFrame* NS_NewGridContainerFrame(
+ mozilla::PresShell* aPresShell, ComputedStyle* aStyle);
+ explicit nsGridContainerFrame(ComputedStyle* aStyle,
+ nsPresContext* aPresContext)
+ : nsContainerFrame(aStyle, aPresContext, kClassID),
+ mCachedMinISize(NS_INTRINSIC_ISIZE_UNKNOWN),
+ mCachedPrefISize(NS_INTRINSIC_ISIZE_UNKNOWN) {
+ for (auto& perAxisBaseline : mBaseline) {
+ for (auto& baseline : perAxisBaseline) {
+ baseline = NS_INTRINSIC_ISIZE_UNKNOWN;
+ }
+ }
+ }
+
+ /**
+ * XXX temporary - move the ImplicitNamedAreas stuff to the style system.
+ * The implicit area names that come from x-start .. x-end lines in
+ * grid-template-columns / grid-template-rows are stored in this frame
+ * property when needed, as a ImplicitNamedAreas* value.
+ */
+ void InitImplicitNamedAreas(const nsStylePosition* aStyle);
+
+ using LineNameList =
+ const mozilla::StyleOwnedSlice<mozilla::StyleCustomIdent>;
+ void AddImplicitNamedAreas(mozilla::Span<LineNameList>);
+
+ /**
+ * Reflow and place our children.
+ * @return the consumed size of all of this grid container's continuations
+ * so far including this frame
+ */
+ nscoord ReflowChildren(GridReflowInput& aState,
+ const LogicalRect& aContentArea,
+ const nsSize& aContainerSize,
+ ReflowOutput& aDesiredSize, nsReflowStatus& aStatus);
+
+ /**
+ * Helper for GetMinISize / GetPrefISize.
+ */
+ nscoord IntrinsicISize(gfxContext* aRenderingContext,
+ mozilla::IntrinsicISizeType aConstraint);
+
+ nscoord GetBBaseline(BaselineSharingGroup aBaselineGroup) const {
+ return mBaseline[mozilla::eLogicalAxisBlock][aBaselineGroup];
+ }
+ nscoord GetIBaseline(BaselineSharingGroup aBaselineGroup) const {
+ return mBaseline[mozilla::eLogicalAxisInline][aBaselineGroup];
+ }
+
+ /**
+ * Calculate this grid container's baselines.
+ * @param aBaselineSet which baseline(s) to derive from a baseline-group or
+ * items; a baseline not included is synthesized from the border-box instead.
+ * @param aFragmentStartTrack is the first track in this fragment in the same
+ * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
+ * @param aFirstExcludedTrack should be the first track in the next fragment
+ * or one beyond the final track in the last fragment, in aMajor's axis.
+ * Pass the number of tracks if that's not the axis we're fragmenting in.
+ */
+ enum BaselineSet : uint32_t {
+ eNone = 0x0,
+ eFirst = 0x1,
+ eLast = 0x2,
+ eBoth = eFirst | eLast,
+ };
+ void CalculateBaselines(BaselineSet aBaselineSet,
+ mozilla::CSSOrderAwareFrameIterator* aIter,
+ const nsTArray<GridItemInfo>* aGridItems,
+ const Tracks& aTracks, uint32_t aFragmentStartTrack,
+ uint32_t aFirstExcludedTrack, WritingMode aWM,
+ const nsSize& aCBPhysicalSize,
+ nscoord aCBBorderPaddingStart,
+ nscoord aCBBorderPaddingStartEnd, nscoord aCBSize);
+
+ /**
+ * Synthesize a Grid container baseline for aGroup.
+ */
+ nscoord SynthesizeBaseline(const FindItemInGridOrderResult& aItem,
+ LogicalAxis aAxis, BaselineSharingGroup aGroup,
+ const nsSize& aCBPhysicalSize, nscoord aCBSize,
+ WritingMode aCBWM);
+ /**
+ * Find the first item in Grid Order in this fragment.
+ * https://drafts.csswg.org/css-grid/#grid-order
+ * @param aFragmentStartTrack is the first track in this fragment in the same
+ * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
+ */
+ static FindItemInGridOrderResult FindFirstItemInGridOrder(
+ mozilla::CSSOrderAwareFrameIterator& aIter,
+ const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::*aMajor,
+ LineRange GridArea::*aMinor, uint32_t aFragmentStartTrack);
+ /**
+ * Find the last item in Grid Order in this fragment.
+ * @param aFragmentStartTrack is the first track in this fragment in the same
+ * axis as aMajor. Pass zero if that's not the axis we're fragmenting in.
+ * @param aFirstExcludedTrack should be the first track in the next fragment
+ * or one beyond the final track in the last fragment, in aMajor's axis.
+ * Pass the number of tracks if that's not the axis we're fragmenting in.
+ */
+ static FindItemInGridOrderResult FindLastItemInGridOrder(
+ mozilla::ReverseCSSOrderAwareFrameIterator& aIter,
+ const nsTArray<GridItemInfo>& aGridItems, LineRange GridArea::*aMajor,
+ LineRange GridArea::*aMinor, uint32_t aFragmentStartTrack,
+ uint32_t aFirstExcludedTrack);
+
+ /**
+ * Update our NS_STATE_GRID_IS_COL/ROW_SUBGRID bits and related subgrid state
+ * on our entire continuation chain based on the current style.
+ * This is needed because grid-template-columns/rows style changes only
+ * trigger a reflow so we need to update this dynamically.
+ */
+ void UpdateSubgridFrameState();
+
+ /**
+ * Return the NS_STATE_GRID_IS_COL/ROW_SUBGRID and
+ * NS_STATE_GRID_IS_ROW/COL_MASONRY bits we ought to have.
+ */
+ nsFrameState ComputeSelfSubgridMasonryBits() const;
+
+ /** Helper for ComputeSelfSubgridMasonryBits(). */
+ bool WillHaveAtLeastOneTrackInAxis(LogicalAxis aAxis) const;
+
+ private:
+ // Helpers for ReflowChildren
+ struct Fragmentainer {
+ /**
+ * The distance from the first grid container fragment's block-axis content
+ * edge to the fragmentainer end.
+ */
+ nscoord mToFragmentainerEnd;
+ /**
+ * True if the current fragment is at the start of the fragmentainer.
+ */
+ bool mIsTopOfPage;
+ /**
+ * Is there a Class C break opportunity at the start content edge?
+ */
+ bool mCanBreakAtStart;
+ /**
+ * Is there a Class C break opportunity at the end content edge?
+ */
+ bool mCanBreakAtEnd;
+ /**
+ * Is the grid container's block-size unconstrained?
+ */
+ bool mIsAutoBSize;
+ };
+
+ mozilla::Maybe<nsGridContainerFrame::Fragmentainer> GetNearestFragmentainer(
+ const GridReflowInput& aState) const;
+
+ // @return the consumed size of all continuations so far including this frame
+ nscoord ReflowInFragmentainer(GridReflowInput& aState,
+ const LogicalRect& aContentArea,
+ ReflowOutput& aDesiredSize,
+ nsReflowStatus& aStatus,
+ Fragmentainer& aFragmentainer,
+ const nsSize& aContainerSize);
+
+ // Helper for ReflowInFragmentainer
+ // @return the consumed size of all continuations so far including this frame
+ nscoord ReflowRowsInFragmentainer(
+ GridReflowInput& aState, const LogicalRect& aContentArea,
+ ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
+ Fragmentainer& aFragmentainer, const nsSize& aContainerSize,
+ const nsTArray<const GridItemInfo*>& aItems, uint32_t aStartRow,
+ uint32_t aEndRow, nscoord aBSize, nscoord aAvailableSize);
+
+ // Helper for ReflowChildren / ReflowInFragmentainer
+ void ReflowInFlowChild(nsIFrame* aChild, const GridItemInfo* aGridItemInfo,
+ nsSize aContainerSize,
+ const mozilla::Maybe<nscoord>& aStretchBSize,
+ const Fragmentainer* aFragmentainer,
+ const GridReflowInput& aState,
+ const LogicalRect& aContentArea,
+ ReflowOutput& aDesiredSize, nsReflowStatus& aStatus);
+
+ /**
+ * Places and reflows items when we have masonry layout.
+ * It handles unconstrained reflow and also fragmentation when the row axis
+ * is the masonry axis. ReflowInFragmentainer handles the case when we're
+ * fragmenting and our row axis is a grid axis and it handles masonry layout
+ * in the column axis in that case.
+ * @return the intrinsic size in the masonry axis
+ */
+ nscoord MasonryLayout(GridReflowInput& aState,
+ const LogicalRect& aContentArea,
+ SizingConstraint aConstraint,
+ ReflowOutput& aDesiredSize, nsReflowStatus& aStatus,
+ Fragmentainer* aFragmentainer,
+ const nsSize& aContainerSize);
+
+ // Return the stored UsedTrackSizes, if any.
+ UsedTrackSizes* GetUsedTrackSizes() const;
+
+ // Store the given TrackSizes in aAxis on a UsedTrackSizes frame property.
+ void StoreUsedTrackSizes(LogicalAxis aAxis,
+ const nsTArray<TrackSize>& aSizes);
+
+ /**
+ * Cached values to optimize GetMinISize/GetPrefISize.
+ */
+ nscoord mCachedMinISize;
+ nscoord mCachedPrefISize;
+
+ // Our baselines, one per BaselineSharingGroup per axis.
+ PerLogicalAxis<PerBaseline<nscoord>> mBaseline;
+
+ public:
+ // A cached result for a grid item's block-axis measuring reflow. This
+ // cache prevents us from doing exponential reflows in cases of deeply
+ // nested grid frames.
+ //
+ // We store the cached value in the grid item's frame property table.
+ //
+ // We cache the following as a "key"
+ // - The size of the grid area in the item's inline axis
+ // - The item's block axis baseline padding
+ // ...and we cache the following as the "value",
+ // - The item's border-box BSize
+ class CachedBAxisMeasurement {
+ public:
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(Prop, CachedBAxisMeasurement)
+ CachedBAxisMeasurement(const nsIFrame* aFrame, const LogicalSize& aCBSize,
+ const nscoord aBSize)
+ : mKey(aFrame, aCBSize), mBSize(aBSize) {}
+
+ CachedBAxisMeasurement() = default;
+
+ bool IsValidFor(const nsIFrame* aFrame, const LogicalSize& aCBSize) const {
+ if (aFrame->IsSubtreeDirty()) {
+ return false;
+ }
+
+ if (!CanCacheMeasurement(aFrame, aCBSize)) {
+ return false;
+ }
+
+ return mKey == Key(aFrame, aCBSize);
+ }
+
+ static bool CanCacheMeasurement(const nsIFrame* aFrame,
+ const LogicalSize& aCBSize) {
+ return Key::CanHash(aFrame, aCBSize);
+ }
+
+ nscoord BSize() const { return mBSize; }
+
+ void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize,
+ const nscoord aBSize) {
+ MOZ_ASSERT(CanCacheMeasurement(aFrame, aCBSize));
+ mKey.mHashKey = Key::GenerateHash(aFrame, aCBSize);
+ mBSize = aBSize;
+ }
+
+ private:
+ struct Key {
+ // mHashKey is generated by combining these 2 variables together
+ // 1. The containing block size in the item's inline axis used
+ // for measuring reflow
+ // 2. The item's baseline padding property
+ uint32_t mHashKey;
+
+ Key() = default;
+
+ Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
+ MOZ_ASSERT(CanHash(aFrame, aCBSize));
+ mHashKey = GenerateHash(aFrame, aCBSize);
+ }
+
+ void UpdateHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
+ MOZ_ASSERT(CanHash(aFrame, aCBSize));
+ mHashKey = GenerateHash(aFrame, aCBSize);
+ }
+
+ static uint32_t GenerateHash(const nsIFrame* aFrame,
+ const LogicalSize& aCBSize) {
+ MOZ_ASSERT(CanHash(aFrame, aCBSize));
+
+ nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode());
+ nscoord bBaselinePaddingProperty =
+ abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()));
+
+ uint_fast8_t bitsNeededForISize = mozilla::FloorLog2(gridAreaISize) + 1;
+
+ return (gridAreaISize << (32 - bitsNeededForISize)) |
+ bBaselinePaddingProperty;
+ }
+
+ static bool CanHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
+ uint_fast8_t bitsNeededForISize =
+ mozilla::FloorLog2(aCBSize.ISize(aFrame->GetWritingMode())) + 1;
+
+ uint_fast8_t bitsNeededForBBaselinePadding =
+ mozilla::FloorLog2(
+ abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()))) +
+ 1;
+
+ return bitsNeededForISize + bitsNeededForBBaselinePadding <= 32;
+ }
+
+ bool operator==(const Key& aOther) const {
+ return mHashKey == aOther.mHashKey;
+ }
+ };
+
+ Key mKey;
+ nscoord mBSize;
+ };
+
+ bool CanProvideLineIterator() const final { return true; }
+ nsILineIterator* GetLineIterator() final { return this; }
+ int32_t GetNumLines() const final;
+ bool IsLineIteratorFlowRTL() final;
+ mozilla::Result<LineInfo, nsresult> GetLine(int32_t aLineNumber) final;
+ int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) final;
+ NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos,
+ nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame,
+ bool* aPosIsAfterLastFrame) final;
+ NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered,
+ nsIFrame** aFirstVisual,
+ nsIFrame** aLastVisual) final;
+};
+
+#endif /* nsGridContainerFrame_h___ */