зеркало из https://github.com/mozilla/gecko-dev.git
370 строки
15 KiB
C++
370 строки
15 KiB
C++
/* -*- 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 "nsContainerFrame.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsTHashtable.h"
|
|
|
|
/**
|
|
* Factory function.
|
|
* @return a newly allocated nsGridContainerFrame (infallible)
|
|
*/
|
|
nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
|
|
nsStyleContext* aContext);
|
|
|
|
class nsGridContainerFrame final : public nsContainerFrame
|
|
{
|
|
public:
|
|
NS_DECL_FRAMEARENA_HELPERS
|
|
NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame)
|
|
NS_DECL_QUERYFRAME
|
|
|
|
// nsIFrame overrides
|
|
void Reflow(nsPresContext* aPresContext,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus) override;
|
|
virtual nsIAtom* GetType() const override;
|
|
|
|
#ifdef DEBUG_FRAME_DUMP
|
|
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
|
#endif
|
|
|
|
struct TrackSize {
|
|
nscoord mBase;
|
|
nscoord mLimit;
|
|
};
|
|
|
|
protected:
|
|
typedef mozilla::LogicalRect LogicalRect;
|
|
typedef mozilla::WritingMode WritingMode;
|
|
typedef mozilla::css::GridNamedArea GridNamedArea;
|
|
friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
|
|
nsStyleContext* aContext);
|
|
explicit nsGridContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
|
|
|
|
/**
|
|
* A LineRange can be definite or auto - when it's definite it represents
|
|
* a consecutive set of tracks between a starting line and an ending line
|
|
* (both 1-based) where mStart < mEnd. Before it's definite it can also
|
|
* represent an auto position with a span, where mStart == 0 and mEnd is
|
|
* the (non-zero positive) span.
|
|
* In both states the invariant mEnd > mStart holds.
|
|
*/
|
|
struct LineRange {
|
|
LineRange(uint32_t aStart, uint32_t aEnd)
|
|
: mStart(aStart), mEnd(aEnd) {}
|
|
bool IsAuto() const { return mStart == 0; }
|
|
bool IsDefinite() const { return mStart != 0; }
|
|
uint32_t Extent() const { return mEnd - mStart; }
|
|
/**
|
|
* Resolve this auto range to start at aStart, making it definite.
|
|
* Precondition: this range IsAuto()
|
|
*/
|
|
void ResolveAutoPosition(uint32_t aStart)
|
|
{
|
|
MOZ_ASSERT(IsAuto(), "Why call me?");
|
|
MOZ_ASSERT(aStart > 0, "expected a 1-based line number");
|
|
MOZ_ASSERT(Extent() == mEnd, "'auto' representation changed?");
|
|
mStart = aStart;
|
|
mEnd += aStart;
|
|
}
|
|
/**
|
|
* Return the contribution of this line range for step 2 in
|
|
* http://dev.w3.org/csswg/css-grid/#auto-placement-algo
|
|
*/
|
|
uint32_t HypotheticalEnd() const { return IsAuto() ? mEnd + 1 : mEnd; }
|
|
/**
|
|
* Given an array of track sizes, return the starting position and length
|
|
* of the tracks in this line range.
|
|
*/
|
|
void ToPositionAndLength(const nsTArray<TrackSize>& aTrackSizes,
|
|
nscoord* aPos, nscoord* aLength) const;
|
|
|
|
uint32_t mStart; // the start line, or zero for 'auto'
|
|
uint32_t mEnd; // the end line, or the span length for 'auto'
|
|
};
|
|
|
|
/**
|
|
* A GridArea is the area in the grid for a grid item.
|
|
* The area is represented by two LineRanges, both of which can be auto
|
|
* (@see LineRange) in intermediate steps while the item is being placed.
|
|
* @see PlaceGridItems
|
|
*/
|
|
struct GridArea {
|
|
GridArea(const LineRange& aCols, const LineRange& aRows)
|
|
: mCols(aCols), mRows(aRows) {}
|
|
bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
|
|
LineRange mCols;
|
|
LineRange mRows;
|
|
};
|
|
|
|
/**
|
|
* A CellMap holds state for each cell in the grid.
|
|
* It's row major. It's sparse in the sense that it only has enough rows to
|
|
* cover the last row that has a grid item. Each row only has enough entries
|
|
* to cover columns that are occupied *on that row*, i.e. it's not a full
|
|
* matrix covering the entire implicit grid. An absent Cell means that it's
|
|
* unoccupied by any grid item.
|
|
*/
|
|
struct CellMap {
|
|
struct Cell {
|
|
Cell() : mIsOccupied(false) {}
|
|
bool mIsOccupied : 1;
|
|
};
|
|
void Fill(const GridArea& aGridArea);
|
|
void ClearOccupied();
|
|
#if DEBUG
|
|
void Dump() const;
|
|
#endif
|
|
nsTArray<nsTArray<Cell>> mCells;
|
|
};
|
|
|
|
enum LineRangeSide {
|
|
eLineRangeSideStart, eLineRangeSideEnd
|
|
};
|
|
/**
|
|
* Return a line number for (non-auto) aLine, per:
|
|
* http://dev.w3.org/csswg/css-grid/#line-placement
|
|
* @param aLine style data for the line (must be non-auto)
|
|
* @param aNth a number of lines to find from aFromIndex, negative if the
|
|
* search should be in reverse order. In the case aLine has
|
|
* a specified line name, it's permitted to pass in zero which
|
|
* will be treated as one.
|
|
* @param aFromIndex the zero-based index to start counting from
|
|
* @param aLineNameList the explicit named lines
|
|
* @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
|
|
* @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
|
|
* @param aExplicitGridEnd the last line in the explicit grid
|
|
* @param aEdge indicates whether we are resolving a start or end line
|
|
* @param aStyle the StylePosition() for the grid container
|
|
* @return a definite line number, or zero in case aLine is a <custom-ident>
|
|
* that can't be found.
|
|
*/
|
|
uint32_t ResolveLine(const nsStyleGridLine& aLine,
|
|
int32_t aNth,
|
|
uint32_t aFromIndex,
|
|
const nsTArray<nsTArray<nsString>>& aLineNameList,
|
|
uint32_t GridNamedArea::* aAreaStart,
|
|
uint32_t GridNamedArea::* aAreaEnd,
|
|
uint32_t aExplicitGridEnd,
|
|
LineRangeSide aEdge,
|
|
const nsStylePosition* aStyle);
|
|
/**
|
|
* Return a LineRange based on the given style data. Non-auto lines
|
|
* are resolved to a definite line number per:
|
|
* http://dev.w3.org/csswg/css-grid/#line-placement
|
|
* with placement errors corrected per:
|
|
* http://dev.w3.org/csswg/css-grid/#grid-placement-errors
|
|
* @param aStyle the StylePosition() for the grid container
|
|
* @param aStart style data for the start line
|
|
* @param aEnd style data for the end line
|
|
* @param aLineNameList the explicit named lines
|
|
* @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
|
|
* @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
|
|
* @param aExplicitGridEnd the last line in the explicit grid
|
|
* @param aStyle the StylePosition() for the grid container
|
|
*/
|
|
LineRange ResolveLineRange(const nsStyleGridLine& aStart,
|
|
const nsStyleGridLine& aEnd,
|
|
const nsTArray<nsTArray<nsString>>& aLineNameList,
|
|
uint32_t GridNamedArea::* aAreaStart,
|
|
uint32_t GridNamedArea::* aAreaEnd,
|
|
uint32_t aExplicitGridEnd,
|
|
const nsStylePosition* aStyle);
|
|
|
|
/**
|
|
* Return a GridArea with non-auto lines placed at a definite line number
|
|
* and with placement errors resolved. One or both positions may still be
|
|
* 'auto'.
|
|
* @param aChild the grid item
|
|
* @param aStyle the StylePosition() for the grid container
|
|
*/
|
|
GridArea PlaceDefinite(nsIFrame* aChild, const nsStylePosition* aStyle);
|
|
|
|
/**
|
|
* Place aArea in the first column (in row aArea->mRows.mStart) starting at
|
|
* aStartCol without overlapping other items. The resulting aArea may
|
|
* overflow the current implicit grid bounds.
|
|
* Pre-condition: aArea->mRows.IsDefinite() is true.
|
|
* Post-condition: aArea->IsDefinite() is true.
|
|
*/
|
|
void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea) const;
|
|
|
|
/**
|
|
* Find the first column in row aLockedRow starting at aStartCol where aArea
|
|
* could be placed without overlapping other items. The returned column may
|
|
* cause aArea to overflow the current implicit grid bounds if placed there.
|
|
*/
|
|
uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
|
|
const GridArea* aArea) const;
|
|
|
|
/**
|
|
* Place aArea in the first row (in column aArea->mCols.mStart) starting at
|
|
* aStartRow without overlapping other items. The resulting aArea may
|
|
* overflow the current implicit grid bounds.
|
|
* Pre-condition: aArea->mCols.IsDefinite() is true.
|
|
* Post-condition: aArea->IsDefinite() is true.
|
|
*/
|
|
void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea) const;
|
|
|
|
/**
|
|
* Find the first row in column aLockedCol starting at aStartRow where aArea
|
|
* could be placed without overlapping other items. The returned row may
|
|
* cause aArea to overflow the current implicit grid bounds if placed there.
|
|
*/
|
|
uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
|
|
const GridArea* aArea) const;
|
|
|
|
/**
|
|
* Place aArea in the first column starting at aStartCol,aStartRow without
|
|
* causing it to overlap other items or overflow mGridColEnd.
|
|
* If there's no such column in aStartRow, continue in position 1,aStartRow+1.
|
|
* Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
|
|
* Post-condition: aArea->IsDefinite() is true.
|
|
*/
|
|
void PlaceAutoAutoInRowOrder(uint32_t aStartCol, uint32_t aStartRow,
|
|
GridArea* aArea) const;
|
|
|
|
/**
|
|
* Place aArea in the first row starting at aStartCol,aStartRow without
|
|
* causing it to overlap other items or overflow mGridRowEnd.
|
|
* If there's no such row in aStartCol, continue in position aStartCol+1,1.
|
|
* Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
|
|
* Post-condition: aArea->IsDefinite() is true.
|
|
*/
|
|
void PlaceAutoAutoInColOrder(uint32_t aStartCol, uint32_t aStartRow,
|
|
GridArea* aArea) const;
|
|
|
|
/**
|
|
* Place all child frames into the grid and expand the (implicit) grid as
|
|
* needed. The allocated GridAreas are stored in the GridAreaProperty
|
|
* frame property on the child frame.
|
|
* @param aStyle the StylePosition() for the grid container
|
|
*/
|
|
void PlaceGridItems(const nsStylePosition* aStyle);
|
|
|
|
/**
|
|
* Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
|
|
* This is determined by the larger of the number of rows/columns defined
|
|
* by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
|
|
* Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
|
|
* @param aStyle the StylePosition() for the grid container
|
|
*/
|
|
void InitializeGridBounds(const nsStylePosition* aStyle);
|
|
|
|
/**
|
|
* Inflate the implicit grid to include aArea.
|
|
* @param aArea may be definite or auto
|
|
*/
|
|
void InflateGridFor(const GridArea& aArea)
|
|
{
|
|
mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
|
|
mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
|
|
}
|
|
|
|
/**
|
|
* Calculate track sizes.
|
|
*/
|
|
void CalculateTrackSizes(const mozilla::LogicalSize& aPercentageBasis,
|
|
const nsStylePosition* aStyle,
|
|
nsTArray<TrackSize>& aColSizes,
|
|
nsTArray<TrackSize>& aRowSizes);
|
|
|
|
/**
|
|
* Helper method for ResolveLineRange.
|
|
* @see ResolveLineRange
|
|
* @return a pair (start,end) of lines
|
|
*/
|
|
typedef std::pair<uint32_t, uint32_t> LinePair;
|
|
LinePair ResolveLineRangeHelper(const nsStyleGridLine& aStart,
|
|
const nsStyleGridLine& aEnd,
|
|
const nsTArray<nsTArray<nsString>>& aLineNameList,
|
|
uint32_t GridNamedArea::* aAreaStart,
|
|
uint32_t GridNamedArea::* aAreaEnd,
|
|
uint32_t aExplicitGridEnd,
|
|
const nsStylePosition* aStyle);
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
NS_DECLARE_FRAME_PROPERTY(ImplicitNamedAreasProperty,
|
|
DeleteValue<ImplicitNamedAreas>)
|
|
void InitImplicitNamedAreas(const nsStylePosition* aStyle);
|
|
void AddImplicitNamedAreas(const nsTArray<nsTArray<nsString>>& aLineNameLists);
|
|
typedef nsTHashtable<nsStringHashKey> ImplicitNamedAreas;
|
|
ImplicitNamedAreas* GetImplicitNamedAreas() const {
|
|
return static_cast<ImplicitNamedAreas*>(Properties().Get(ImplicitNamedAreasProperty()));
|
|
}
|
|
bool HasImplicitNamedArea(const nsString& aName) const {
|
|
ImplicitNamedAreas* areas = GetImplicitNamedAreas();
|
|
return areas && areas->Contains(aName);
|
|
}
|
|
|
|
NS_DECLARE_FRAME_PROPERTY(GridAreaProperty, DeleteValue<GridArea>)
|
|
|
|
/**
|
|
* A convenience method to get the stored GridArea* for a frame.
|
|
*/
|
|
static GridArea* GetGridAreaForChild(nsIFrame* aChild) {
|
|
return static_cast<GridArea*>(aChild->Properties().Get(GridAreaProperty()));
|
|
}
|
|
|
|
/**
|
|
* Return the containing block for a grid item occupying aArea.
|
|
* @param aColSizes column track sizes
|
|
* @param aRowSizes row track sizes
|
|
*/
|
|
LogicalRect ContainingBlockFor(const WritingMode& aWM,
|
|
const GridArea& aArea,
|
|
const nsTArray<TrackSize>& aColSizes,
|
|
const nsTArray<TrackSize>& aRowSizes) const;
|
|
|
|
/**
|
|
* Reflow and place our children.
|
|
*/
|
|
void ReflowChildren(const LogicalRect& aContentArea,
|
|
const nsTArray<TrackSize>& aColSizes,
|
|
const nsTArray<TrackSize>& aRowSizes,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus);
|
|
|
|
#ifdef DEBUG
|
|
void SanityCheckAnonymousGridItems() const;
|
|
#endif // DEBUG
|
|
|
|
private:
|
|
/**
|
|
* State for each cell in the grid.
|
|
*/
|
|
CellMap mCellMap;
|
|
|
|
/**
|
|
* The last column grid line (1-based) in the explicit grid.
|
|
* (i.e. the number of explicit columns + 1)
|
|
*/
|
|
uint32_t mExplicitGridColEnd;
|
|
/**
|
|
* The last row grid line (1-based) in the explicit grid.
|
|
* (i.e. the number of explicit rows + 1)
|
|
*/
|
|
uint32_t mExplicitGridRowEnd;
|
|
// Same for the implicit grid
|
|
uint32_t mGridColEnd; // always >= mExplicitGridColEnd
|
|
uint32_t mGridRowEnd; // always >= mExplicitGridRowEnd
|
|
};
|
|
|
|
#endif /* nsGridContainerFrame_h___ */
|