mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1107786 - part 1, [css-grid] Implement layout and painting per the CSS 'order' property for normal flow grid items. r=dholbert
This commit is contained in:
parent
8022fc884e
commit
ee70e64e09
@ -8,9 +8,12 @@
|
||||
|
||||
#include "nsGridContainerFrame.h"
|
||||
|
||||
#include <algorithm> // for std::stable_sort
|
||||
#include <limits>
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsAbsoluteContainingBlock.h"
|
||||
#include "nsAlgorithm.h" // for clamped()
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsDisplayList.h"
|
||||
@ -24,6 +27,106 @@
|
||||
using namespace mozilla;
|
||||
typedef nsGridContainerFrame::TrackSize TrackSize;
|
||||
|
||||
class nsGridContainerFrame::GridItemCSSOrderIterator
|
||||
{
|
||||
public:
|
||||
enum OrderState { eUnknownOrder, eKnownOrdered, eKnownUnordered };
|
||||
GridItemCSSOrderIterator(nsIFrame* aGridContainer,
|
||||
nsIFrame::ChildListID aListID,
|
||||
OrderState aState = eUnknownOrder)
|
||||
: mChildren(aGridContainer->GetChildList(aListID))
|
||||
, mArrayIndex(0)
|
||||
#ifdef DEBUG
|
||||
, mGridContainer(aGridContainer)
|
||||
, mListID(aListID)
|
||||
#endif
|
||||
{
|
||||
size_t count = 0;
|
||||
bool isOrdered = aState != eKnownUnordered;
|
||||
if (aState == eUnknownOrder) {
|
||||
auto maxOrder = std::numeric_limits<int32_t>::min();
|
||||
for (nsFrameList::Enumerator e(mChildren); !e.AtEnd(); e.Next()) {
|
||||
++count;
|
||||
int32_t order = e.get()->StylePosition()->mOrder;
|
||||
if (order < maxOrder) {
|
||||
isOrdered = false;
|
||||
break;
|
||||
}
|
||||
maxOrder = order;
|
||||
}
|
||||
}
|
||||
if (isOrdered) {
|
||||
mEnumerator.emplace(mChildren);
|
||||
} else {
|
||||
count *= 2; // XXX somewhat arbitrary estimate for now...
|
||||
mArray.emplace(count);
|
||||
for (nsFrameList::Enumerator e(mChildren); !e.AtEnd(); e.Next()) {
|
||||
mArray->AppendElement(e.get());
|
||||
}
|
||||
// XXX replace this with nsTArray::StableSort when bug 1147091 is fixed.
|
||||
std::stable_sort(mArray->begin(), mArray->end(), IsCSSOrderLessThan);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* operator*() const
|
||||
{
|
||||
MOZ_ASSERT(!AtEnd());
|
||||
if (mEnumerator) {
|
||||
return mEnumerator->get();
|
||||
}
|
||||
return (*mArray)[mArrayIndex];
|
||||
}
|
||||
|
||||
bool AtEnd() const
|
||||
{
|
||||
MOZ_ASSERT(mEnumerator || mArrayIndex <= mArray->Length());
|
||||
return mEnumerator ? mEnumerator->AtEnd() : mArrayIndex >= mArray->Length();
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsFrameList list = mGridContainer->GetChildList(mListID);
|
||||
MOZ_ASSERT(list.FirstChild() == mChildren.FirstChild() &&
|
||||
list.LastChild() == mChildren.LastChild(),
|
||||
"the list of child frames must not change while iterating!");
|
||||
#endif
|
||||
if (mEnumerator) {
|
||||
mEnumerator->Next();
|
||||
} else {
|
||||
MOZ_ASSERT(mArrayIndex < mArray->Length(), "iterating past end");
|
||||
++mArrayIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (mEnumerator) {
|
||||
mEnumerator.reset();
|
||||
mEnumerator.emplace(mChildren);
|
||||
} else {
|
||||
mArrayIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemsAreAlreadyInOrder() const { return mEnumerator.isSome(); }
|
||||
|
||||
private:
|
||||
static bool IsCSSOrderLessThan(nsIFrame* const& a, nsIFrame* const& b)
|
||||
{ return a->StylePosition()->mOrder < b->StylePosition()->mOrder; }
|
||||
|
||||
nsFrameList mChildren;
|
||||
// Used if child list is already in ascending 'order'.
|
||||
Maybe<nsFrameList::Enumerator> mEnumerator;
|
||||
// Used if child list is *not* in ascending 'order'.
|
||||
Maybe<nsTArray<nsIFrame*>> mArray;
|
||||
size_t mArrayIndex;
|
||||
#ifdef DEBUG
|
||||
nsIFrame* mGridContainer;
|
||||
nsIFrame::ChildListID mListID;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Search for the aNth occurrence of aName in aNameList (forward), starting at
|
||||
* the zero-based aFromIndex, and return the 1-based index (line number).
|
||||
@ -690,15 +793,16 @@ nsGridContainerFrame::InitializeGridBounds(const nsStylePosition* aStyle)
|
||||
}
|
||||
|
||||
void
|
||||
nsGridContainerFrame::PlaceGridItems(const nsStylePosition* aStyle)
|
||||
nsGridContainerFrame::PlaceGridItems(GridItemCSSOrderIterator& aIter,
|
||||
const nsStylePosition* aStyle)
|
||||
{
|
||||
mCellMap.ClearOccupied();
|
||||
InitializeGridBounds(aStyle);
|
||||
|
||||
// http://dev.w3.org/csswg/css-grid/#line-placement
|
||||
// Resolve definite positions per spec chap 9.2.
|
||||
for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
for (; !aIter.AtEnd(); aIter.Next()) {
|
||||
nsIFrame* child = *aIter;
|
||||
const GridArea& area = PlaceDefinite(child, aStyle);
|
||||
GridArea* prop = GetGridAreaForChild(child);
|
||||
if (prop) {
|
||||
@ -726,8 +830,9 @@ nsGridContainerFrame::PlaceGridItems(const nsStylePosition* aStyle)
|
||||
}
|
||||
auto placeAutoMinorFunc = isRowOrder ? &nsGridContainerFrame::PlaceAutoCol
|
||||
: &nsGridContainerFrame::PlaceAutoRow;
|
||||
for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
aIter.Reset();
|
||||
for (; !aIter.AtEnd(); aIter.Next()) {
|
||||
nsIFrame* child = *aIter;
|
||||
GridArea* area = GetGridAreaForChild(child);
|
||||
LineRange& major = isRowOrder ? area->mRows : area->mCols;
|
||||
LineRange& minor = isRowOrder ? area->mCols : area->mRows;
|
||||
@ -760,8 +865,9 @@ nsGridContainerFrame::PlaceGridItems(const nsStylePosition* aStyle)
|
||||
uint32_t cursorMinor = 1;
|
||||
auto placeAutoMajorFunc = isRowOrder ? &nsGridContainerFrame::PlaceAutoRow
|
||||
: &nsGridContainerFrame::PlaceAutoCol;
|
||||
for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
aIter.Reset();
|
||||
for (; !aIter.AtEnd(); aIter.Next()) {
|
||||
nsIFrame* child = *aIter;
|
||||
GridArea* area = GetGridAreaForChild(child);
|
||||
LineRange& major = isRowOrder ? area->mRows : area->mCols;
|
||||
LineRange& minor = isRowOrder ? area->mCols : area->mRows;
|
||||
@ -988,7 +1094,8 @@ nsGridContainerFrame::ContainingBlockForAbsPos(
|
||||
}
|
||||
|
||||
void
|
||||
nsGridContainerFrame::ReflowChildren(const LogicalRect& aContentArea,
|
||||
nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter,
|
||||
const LogicalRect& aContentArea,
|
||||
const nsTArray<TrackSize>& aColSizes,
|
||||
const nsTArray<TrackSize>& aRowSizes,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
@ -999,8 +1106,8 @@ nsGridContainerFrame::ReflowChildren(const LogicalRect& aContentArea,
|
||||
const LogicalPoint gridOrigin(aContentArea.Origin(wm));
|
||||
const nscoord gridWidth = aContentArea.Width(wm);
|
||||
nsPresContext* pc = PresContext();
|
||||
for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
for (; !aIter.AtEnd(); aIter.Next()) {
|
||||
nsIFrame* child = *aIter;
|
||||
GridArea* area = GetGridAreaForChild(child);
|
||||
MOZ_ASSERT(area && area->IsDefinite());
|
||||
LogicalRect cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
|
||||
@ -1088,7 +1195,9 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
bp.ApplySkipSides(GetLogicalSkipSides());
|
||||
const nsStylePosition* stylePos = aReflowState.mStylePosition;
|
||||
InitImplicitNamedAreas(stylePos);
|
||||
PlaceGridItems(stylePos);
|
||||
GridItemCSSOrderIterator normalFlowIter(this, kPrincipalList);
|
||||
mIsNormalFlowInCSSOrder = normalFlowIter.ItemsAreAlreadyInOrder();
|
||||
PlaceGridItems(normalFlowIter, stylePos);
|
||||
|
||||
nsAutoTArray<TrackSize, 32> colSizes;
|
||||
nsAutoTArray<TrackSize, 32> rowSizes;
|
||||
@ -1115,7 +1224,8 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
|
||||
LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
|
||||
computedISize, bSize);
|
||||
ReflowChildren(contentArea, colSizes, rowSizes, aDesiredSize,
|
||||
normalFlowIter.Reset();
|
||||
ReflowChildren(normalFlowIter, contentArea, colSizes, rowSizes, aDesiredSize,
|
||||
aReflowState, aStatus);
|
||||
|
||||
FinishAndStoreOverflow(&aDesiredSize);
|
||||
@ -1140,8 +1250,12 @@ nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// inline-blocks in painting, so their borders/backgrounds all go on
|
||||
// the BlockBorderBackgrounds list.
|
||||
nsDisplayListSet childLists(aLists, aLists.BlockBorderBackgrounds());
|
||||
for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
typedef GridItemCSSOrderIterator::OrderState OrderState;
|
||||
OrderState order = mIsNormalFlowInCSSOrder ? OrderState::eKnownOrdered
|
||||
: OrderState::eKnownUnordered;
|
||||
GridItemCSSOrderIterator iter(this, kPrincipalList, order);
|
||||
for (; !iter.AtEnd(); iter.Next()) {
|
||||
nsIFrame* child = *iter;
|
||||
BuildDisplayListForChild(aBuilder, child, aDirtyRect, childLists,
|
||||
::GetDisplayFlagsForGridItem(child));
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ protected:
|
||||
typedef mozilla::LogicalRect LogicalRect;
|
||||
typedef mozilla::WritingMode WritingMode;
|
||||
typedef mozilla::css::GridNamedArea GridNamedArea;
|
||||
class GridItemCSSOrderIterator;
|
||||
friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
explicit nsGridContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
|
||||
@ -303,9 +304,11 @@ protected:
|
||||
* 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 aIter a grid item iterator
|
||||
* @param aStyle the StylePosition() for the grid container
|
||||
*/
|
||||
void PlaceGridItems(const nsStylePosition* aStyle);
|
||||
void PlaceGridItems(GridItemCSSOrderIterator& aIter,
|
||||
const nsStylePosition* aStyle);
|
||||
|
||||
/**
|
||||
* Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
|
||||
@ -405,7 +408,8 @@ protected:
|
||||
/**
|
||||
* Reflow and place our children.
|
||||
*/
|
||||
void ReflowChildren(const LogicalRect& aContentArea,
|
||||
void ReflowChildren(GridItemCSSOrderIterator& aIter,
|
||||
const LogicalRect& aContentArea,
|
||||
const nsTArray<TrackSize>& aColSizes,
|
||||
const nsTArray<TrackSize>& aRowSizes,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
@ -435,6 +439,11 @@ private:
|
||||
// Same for the implicit grid
|
||||
uint32_t mGridColEnd; // always >= mExplicitGridColEnd
|
||||
uint32_t mGridRowEnd; // always >= mExplicitGridRowEnd
|
||||
/**
|
||||
* True iff the normal flow children are already in CSS 'order' in the
|
||||
* order they occur in the child frame list.
|
||||
*/
|
||||
bool mIsNormalFlowInCSSOrder : 1;
|
||||
};
|
||||
|
||||
#endif /* nsGridContainerFrame_h___ */
|
||||
|
Loading…
Reference in New Issue
Block a user