diff options
Diffstat (limited to 'layout/generic/nsGridContainerFrame.h')
-rw-r--r-- | layout/generic/nsGridContainerFrame.h | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h new file mode 100644 index 000000000..e610dfa0b --- /dev/null +++ b/layout/generic/nsGridContainerFrame.h @@ -0,0 +1,458 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code is subject to the terms of the Mozilla Public License + * version 2.0 (the "License"). You can obtain a copy of the License at + * http://mozilla.org/MPL/2.0/. */ + +/* rendering object for CSS "display: grid | inline-grid" */ + +#ifndef nsGridContainerFrame_h___ +#define nsGridContainerFrame_h___ + +#include "mozilla/Maybe.h" +#include "mozilla/TypeTraits.h" +#include "nsContainerFrame.h" +#include "nsHashKeys.h" +#include "nsTHashtable.h" + +/** + * Factory function. + * @return a newly allocated nsGridContainerFrame (infallible) + */ +nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); + +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) + : mNumLeadingImplicitTracks(aNumLeadingImplicitTracks) + , mNumExplicitTracks(aNumExplicitTracks) + , mStartFragmentTrack(aStartFragmentTrack) + , mEndFragmentTrack(aEndFragmentTrack) + , mPositions(aPositions) + , mSizes(aSizes) + , mStates(aStates) + , mRemovedRepeatTracks(aRemovedRepeatTracks) + , mRepeatFirstTrack(aRepeatFirstTrack) + {} + uint32_t mNumLeadingImplicitTracks; + uint32_t mNumExplicitTracks; + uint32_t mStartFragmentTrack; + uint32_t mEndFragmentTrack; + nsTArray<nscoord> mPositions; + nsTArray<nscoord> mSizes; + nsTArray<uint32_t> mStates; + nsTArray<bool> mRemovedRepeatTracks; + uint32_t mRepeatFirstTrack; +}; + +struct ComputedGridLineInfo +{ + explicit ComputedGridLineInfo(nsTArray<nsTArray<nsString>>&& aNames, + const nsTArray<nsString>& aNamesBefore, + const nsTArray<nsString>& aNamesAfter) + : mNames(aNames) + , mNamesBefore(aNamesBefore) + , mNamesAfter(aNamesAfter) + {} + nsTArray<nsTArray<nsString>> mNames; + nsTArray<nsString> mNamesBefore; + nsTArray<nsString> mNamesAfter; +}; +} // namespace mozilla + +class nsGridContainerFrame final : public nsContainerFrame +{ +public: + NS_DECL_FRAMEARENA_HELPERS + NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame) + NS_DECL_QUERYFRAME + typedef mozilla::ComputedGridTrackInfo ComputedGridTrackInfo; + typedef mozilla::ComputedGridLineInfo ComputedGridLineInfo; + + // nsIFrame overrides + void Reflow(nsPresContext* aPresContext, + ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + nscoord GetMinISize(nsRenderingContext* aRenderingContext) override; + nscoord GetPrefISize(nsRenderingContext* aRenderingContext) override; + void MarkIntrinsicISizesDirty() override; + nsIAtom* GetType() const override; + bool IsFrameOfType(uint32_t aFlags) const override + { + return nsContainerFrame::IsFrameOfType(aFlags & + ~nsIFrame::eCanContainOverflowContainers); + } + + void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) override; + + nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const override + { + if (HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) { + // Return a baseline synthesized from our margin-box. + return nsContainerFrame::GetLogicalBaseline(aWM); + } + nscoord b; + GetBBaseline(BaselineSharingGroup::eFirst, &b); + return b; + } + + bool GetVerticalAlignBaseline(mozilla::WritingMode aWM, + nscoord* aBaseline) const override + { + return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline); + } + + bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM, + BaselineSharingGroup aBaselineGroup, + nscoord* aBaseline) const override + { + if (HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) { + return false; + } + return GetBBaseline(aBaselineGroup, aBaseline); + } + +#ifdef DEBUG_FRAME_DUMP + nsresult GetFrameName(nsAString& aResult) const override; +#endif + + // nsContainerFrame overrides + bool DrainSelfOverflowList() override; + void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override; + void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, + nsFrameList& aFrameList) override; + void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override; + uint16_t CSSAlignmentForAbsPosChild( + const ReflowInput& aChildRI, + mozilla::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. This is just a helper method for + * nsAbsoluteContainingBlock::Reflow - it's not meant to be used elsewhere. + */ + 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 = Properties().Get(GridColTrackInfo()); + MOZ_ASSERT(info, "Property generation wasn't requested."); + return info; + } + + NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo) + const ComputedGridTrackInfo* GetComputedTemplateRows() + { + const ComputedGridTrackInfo* info = Properties().Get(GridRowTrackInfo()); + MOZ_ASSERT(info, "Property generation wasn't requested."); + return info; + } + + NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColumnLineInfo, ComputedGridLineInfo) + const ComputedGridLineInfo* GetComputedTemplateColumnLines() + { + const ComputedGridLineInfo* info = Properties().Get(GridColumnLineInfo()); + MOZ_ASSERT(info, "Property generation wasn't requested."); + return info; + } + + NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo) + const ComputedGridLineInfo* GetComputedTemplateRowLines() + { + const ComputedGridLineInfo* info = Properties().Get(GridRowLineInfo()); + MOZ_ASSERT(info, "Property generation wasn't requested."); + return info; + } + + typedef nsBaseHashtable<nsStringHashKey, + mozilla::css::GridNamedArea, + mozilla::css::GridNamedArea> ImplicitNamedAreas; + NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty, + ImplicitNamedAreas) + ImplicitNamedAreas* GetImplicitNamedAreas() const { + return Properties().Get(ImplicitNamedAreasProperty()); + } + + typedef nsTArray<mozilla::css::GridNamedArea> ExplicitNamedAreas; + NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty, + ExplicitNamedAreas) + ExplicitNamedAreas* GetExplicitNamedAreas() const { + return Properties().Get(ExplicitNamedAreasProperty()); + } + + /** + * Return a containing 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 + */ + static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame); + + struct TrackSize; + struct GridItemInfo; + struct GridReflowInput; + template<typename Iterator> class GridItemCSSOrderIteratorT; + typedef GridItemCSSOrderIteratorT<nsFrameList::iterator> + GridItemCSSOrderIterator; + typedef GridItemCSSOrderIteratorT<nsFrameList::reverse_iterator> + ReverseGridItemCSSOrderIterator; + struct FindItemInGridOrderResult + { + // The first(last) item in (reverse) grid order. + const GridItemInfo* mItem; + // Does the above item span the first(last) track? + bool mIsInEdgeTrack; + }; +protected: + static const uint32_t kAutoLine; + // The maximum line number, in the zero-based translated grid. + static const uint32_t kTranslatedMaxLine; + typedef mozilla::LogicalPoint LogicalPoint; + typedef mozilla::LogicalRect LogicalRect; + typedef mozilla::LogicalSize LogicalSize; + typedef mozilla::WritingMode WritingMode; + typedef mozilla::css::GridNamedArea GridNamedArea; + typedef mozilla::layout::AutoFrameListPtr AutoFrameListPtr; + typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType; + struct Grid; + struct GridArea; + class LineNameMap; + struct LineRange; + struct SharedGridData; + struct TrackSizingFunctions; + struct Tracks; + struct TranslatedLineRange; + friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); + explicit nsGridContainerFrame(nsStyleContext* aContext) + : nsContainerFrame(aContext) + , mCachedMinISize(NS_INTRINSIC_WIDTH_UNKNOWN) + , mCachedPrefISize(NS_INTRINSIC_WIDTH_UNKNOWN) + { + mBaseline[0][0] = NS_INTRINSIC_WIDTH_UNKNOWN; + mBaseline[0][1] = NS_INTRINSIC_WIDTH_UNKNOWN; + mBaseline[1][0] = NS_INTRINSIC_WIDTH_UNKNOWN; + mBaseline[1][1] = NS_INTRINSIC_WIDTH_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); + void AddImplicitNamedAreas(const nsTArray<nsTArray<nsString>>& aLineNameLists); + + /** + * 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, + ReflowOutput& aDesiredSize, + nsReflowStatus& aStatus); + + /** + * Helper for GetMinISize / GetPrefISize. + */ + nscoord IntrinsicISize(nsRenderingContext* aRenderingContext, + IntrinsicISizeType aConstraint); + + // Helper for AppendFrames / InsertFrames. + void NoteNewChildren(ChildListID aListID, const nsFrameList& aFrameList); + + // Helper to move child frames into the kOverflowList. + void MergeSortedOverflow(nsFrameList& aList); + // Helper to move child frames into the kExcessOverflowContainersList:. + void MergeSortedExcessOverflowContainers(nsFrameList& aList); + + bool GetBBaseline(BaselineSharingGroup aBaselineGroup, nscoord* aResult) const + { + *aResult = mBaseline[mozilla::eLogicalAxisBlock][aBaselineGroup]; + return true; + } + bool GetIBaseline(BaselineSharingGroup aBaselineGroup, nscoord* aResult) const + { + *aResult = mBaseline[mozilla::eLogicalAxisInline][aBaselineGroup]; + return true; + } + + /** + * 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, + GridItemCSSOrderIterator* 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, + mozilla::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(GridItemCSSOrderIterator& 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(ReverseGridItemCSSOrderIterator& aIter, + const nsTArray<GridItemInfo>& aGridItems, + LineRange GridArea::* aMajor, + LineRange GridArea::* aMinor, + uint32_t aFragmentStartTrack, + uint32_t aFirstExcludedTrack); + +#ifdef DEBUG + void SanityCheckGridItemsBeforeReflow() const; +#endif // DEBUG + +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, + mozilla::Maybe<nscoord> aStretchBSize, + const Fragmentainer* aFragmentainer, + const GridReflowInput& aState, + const LogicalRect& aContentArea, + ReflowOutput& aDesiredSize, + nsReflowStatus& aStatus); + + /** + * Cached values to optimize GetMinISize/GetPrefISize. + */ + nscoord mCachedMinISize; + nscoord mCachedPrefISize; + + // Our baselines, one per BaselineSharingGroup per axis. + nscoord mBaseline[2/*LogicalAxis*/][2/*BaselineSharingGroup*/]; + +#ifdef DEBUG + // If true, NS_STATE_GRID_DID_PUSH_ITEMS may be set even though all pushed + // frames may have been removed. This is used to suppress an assertion + // in case RemoveFrame removed all associated child frames. + bool mDidPushItemsBitMayLie; +#endif +}; + +#endif /* nsGridContainerFrame_h___ */ |