зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1151204 part 1 - [css-grid] Make GridItemCSSOrderIterator use nsFrameList iterators internally and make the specific type (forward/reverse) a template param. r=dholbert
This commit is contained in:
Родитель
17c865d7bc
Коммит
fd54eb1633
|
@ -13,6 +13,7 @@
|
||||||
#include "mozilla/Function.h"
|
#include "mozilla/Function.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/PodOperations.h" // for PodZero
|
#include "mozilla/PodOperations.h" // for PodZero
|
||||||
|
#include "mozilla/Poison.h"
|
||||||
#include "nsAbsoluteContainingBlock.h"
|
#include "nsAbsoluteContainingBlock.h"
|
||||||
#include "nsAlgorithm.h" // for clamped()
|
#include "nsAlgorithm.h" // for clamped()
|
||||||
#include "nsCSSAnonBoxes.h"
|
#include "nsCSSAnonBoxes.h"
|
||||||
|
@ -28,6 +29,10 @@
|
||||||
#include "nsStyleContext.h"
|
#include "nsStyleContext.h"
|
||||||
#include "mozilla/dom/GridBinding.h"
|
#include "mozilla/dom/GridBinding.h"
|
||||||
|
|
||||||
|
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 6
|
||||||
|
#define CLANG_CRASH_BUG 1
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
|
typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
|
||||||
typedef nsGridContainerFrame::TrackSize TrackSize;
|
typedef nsGridContainerFrame::TrackSize TrackSize;
|
||||||
|
@ -319,12 +324,13 @@ MergeSortedFrameListsFor(nsFrameList& aDest, nsFrameList& aSrc,
|
||||||
MergeSortedFrameLists(aDest, aSrc, aParent->GetContent());
|
MergeSortedFrameLists(aDest, aSrc, aParent->GetContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsGridContainerFrame::GridItemCSSOrderIterator
|
template<typename Iterator>
|
||||||
|
class nsGridContainerFrame::GridItemCSSOrderIteratorT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum OrderState { eUnknownOrder, eKnownOrdered, eKnownUnordered };
|
enum OrderState { eUnknownOrder, eKnownOrdered, eKnownUnordered };
|
||||||
enum ChildFilter { eSkipPlaceholders, eIncludeAll };
|
enum ChildFilter { eSkipPlaceholders, eIncludeAll };
|
||||||
GridItemCSSOrderIterator(nsIFrame* aGridContainer,
|
GridItemCSSOrderIteratorT(nsIFrame* aGridContainer,
|
||||||
nsIFrame::ChildListID aListID,
|
nsIFrame::ChildListID aListID,
|
||||||
ChildFilter aFilter = eSkipPlaceholders,
|
ChildFilter aFilter = eSkipPlaceholders,
|
||||||
OrderState aState = eUnknownOrder)
|
OrderState aState = eUnknownOrder)
|
||||||
|
@ -341,9 +347,9 @@ public:
|
||||||
bool isOrdered = aState != eKnownUnordered;
|
bool isOrdered = aState != eKnownUnordered;
|
||||||
if (aState == eUnknownOrder) {
|
if (aState == eUnknownOrder) {
|
||||||
auto maxOrder = std::numeric_limits<int32_t>::min();
|
auto maxOrder = std::numeric_limits<int32_t>::min();
|
||||||
for (nsFrameList::Enumerator e(mChildren); !e.AtEnd(); e.Next()) {
|
for (auto child : mChildren) {
|
||||||
++count;
|
++count;
|
||||||
int32_t order = e.get()->StylePosition()->mOrder;
|
int32_t order = child->StylePosition()->mOrder;
|
||||||
if (order < maxOrder) {
|
if (order < maxOrder) {
|
||||||
isOrdered = false;
|
isOrdered = false;
|
||||||
break;
|
break;
|
||||||
|
@ -352,27 +358,36 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isOrdered) {
|
if (isOrdered) {
|
||||||
mEnumerator.emplace(mChildren);
|
mIter.emplace(begin(mChildren));
|
||||||
|
mIterEnd.emplace(end(mChildren));
|
||||||
} else {
|
} else {
|
||||||
count *= 2; // XXX somewhat arbitrary estimate for now...
|
count *= 2; // XXX somewhat arbitrary estimate for now...
|
||||||
mArray.emplace(count);
|
mArray.emplace(count);
|
||||||
for (nsFrameList::Enumerator e(mChildren); !e.AtEnd(); e.Next()) {
|
for (Iterator i(begin(mChildren)), iEnd(end(mChildren)); i != iEnd; ++i) {
|
||||||
mArray->AppendElement(e.get());
|
mArray->AppendElement(*i);
|
||||||
}
|
}
|
||||||
// XXX replace this with nsTArray::StableSort when bug 1147091 is fixed.
|
// XXX replace this with nsTArray::StableSort when bug 1147091 is fixed.
|
||||||
std::stable_sort(mArray->begin(), mArray->end(), IsCSSOrderLessThan);
|
std::stable_sort(mArray->begin(), mArray->end(), CSSOrderComparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSkipPlaceholders) {
|
if (mSkipPlaceholders) {
|
||||||
SkipPlaceholders();
|
SkipPlaceholders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
~GridItemCSSOrderIteratorT()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsForward() == mGridItemCount.isNothing());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsForward() const;
|
||||||
|
Iterator begin(const nsFrameList& aList);
|
||||||
|
Iterator end(const nsFrameList& aList);
|
||||||
|
|
||||||
nsIFrame* operator*() const
|
nsIFrame* operator*() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!AtEnd());
|
MOZ_ASSERT(!AtEnd());
|
||||||
if (mEnumerator) {
|
if (mIter.isSome()) {
|
||||||
return mEnumerator->get();
|
return **mIter;
|
||||||
}
|
}
|
||||||
return (*mArray)[mArrayIndex];
|
return (*mArray)[mArrayIndex];
|
||||||
}
|
}
|
||||||
|
@ -386,17 +401,29 @@ public:
|
||||||
MOZ_ASSERT(!AtEnd());
|
MOZ_ASSERT(!AtEnd());
|
||||||
MOZ_ASSERT((**this)->GetType() != nsGkAtoms::placeholderFrame,
|
MOZ_ASSERT((**this)->GetType() != nsGkAtoms::placeholderFrame,
|
||||||
"MUST not call this when at a placeholder");
|
"MUST not call this when at a placeholder");
|
||||||
|
MOZ_ASSERT(IsForward() || mGridItemIndex < *mGridItemCount,
|
||||||
|
"Returning an out-of-range mGridItemIndex...");
|
||||||
return mGridItemIndex;
|
return mGridItemIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetGridItemCount(size_t aGridItemCount)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mIter.isSome() || mArray->Length() == aGridItemCount,
|
||||||
|
"grid item count mismatch");
|
||||||
|
mGridItemCount.emplace(aGridItemCount);
|
||||||
|
// Note: it's OK if mGridItemIndex underflows -- GridItemIndex()
|
||||||
|
// will not be called unless there is at least one item.
|
||||||
|
mGridItemIndex = IsForward() ? 0 : *mGridItemCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip over placeholder children.
|
* Skip over placeholder children.
|
||||||
*/
|
*/
|
||||||
void SkipPlaceholders()
|
void SkipPlaceholders()
|
||||||
{
|
{
|
||||||
if (mEnumerator) {
|
if (mIter.isSome()) {
|
||||||
for (; !mEnumerator->AtEnd(); mEnumerator->Next()) {
|
for (; *mIter != *mIterEnd; ++*mIter) {
|
||||||
nsIFrame* child = mEnumerator->get();
|
nsIFrame* child = **mIter;
|
||||||
if (child->GetType() != nsGkAtoms::placeholderFrame) {
|
if (child->GetType() != nsGkAtoms::placeholderFrame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -413,8 +440,11 @@ public:
|
||||||
|
|
||||||
bool AtEnd() const
|
bool AtEnd() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mEnumerator || mArrayIndex <= mArray->Length());
|
#ifndef CLANG_CRASH_BUG
|
||||||
return mEnumerator ? mEnumerator->AtEnd() : mArrayIndex >= mArray->Length();
|
// Clang 3.6.2 crashes when compiling this assertion:
|
||||||
|
MOZ_ASSERT(mIter.isSome() || mArrayIndex <= mArray->Length());
|
||||||
|
#endif
|
||||||
|
return mIter ? (*mIter == *mIterEnd) : mArrayIndex >= mArray->Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Next()
|
void Next()
|
||||||
|
@ -428,10 +458,10 @@ public:
|
||||||
#endif
|
#endif
|
||||||
if (mSkipPlaceholders ||
|
if (mSkipPlaceholders ||
|
||||||
(**this)->GetType() != nsGkAtoms::placeholderFrame) {
|
(**this)->GetType() != nsGkAtoms::placeholderFrame) {
|
||||||
++mGridItemIndex;
|
IsForward() ? ++mGridItemIndex : --mGridItemIndex;
|
||||||
}
|
}
|
||||||
if (mEnumerator) {
|
if (mIter.isSome()) {
|
||||||
mEnumerator->Next();
|
++*mIter;
|
||||||
} else {
|
} else {
|
||||||
++mArrayIndex;
|
++mArrayIndex;
|
||||||
}
|
}
|
||||||
|
@ -442,33 +472,47 @@ public:
|
||||||
|
|
||||||
void Reset(ChildFilter aFilter = eSkipPlaceholders)
|
void Reset(ChildFilter aFilter = eSkipPlaceholders)
|
||||||
{
|
{
|
||||||
if (mEnumerator) {
|
if (mIter.isSome()) {
|
||||||
mEnumerator.reset();
|
mIter.reset();
|
||||||
mEnumerator.emplace(mChildren);
|
mIter.emplace(begin(mChildren));
|
||||||
|
mIterEnd.reset();
|
||||||
|
mIterEnd.emplace(end(mChildren));
|
||||||
} else {
|
} else {
|
||||||
mArrayIndex = 0;
|
mArrayIndex = 0;
|
||||||
}
|
}
|
||||||
mGridItemIndex = 0;
|
mGridItemIndex = IsForward() ? 0 : *mGridItemCount - 1;
|
||||||
mSkipPlaceholders = aFilter == eSkipPlaceholders;
|
mSkipPlaceholders = aFilter == eSkipPlaceholders;
|
||||||
if (mSkipPlaceholders) {
|
if (mSkipPlaceholders) {
|
||||||
SkipPlaceholders();
|
SkipPlaceholders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemsAreAlreadyInOrder() const { return mEnumerator.isSome(); }
|
bool IsValid() const { return mIter.isSome() || mArray.isSome(); }
|
||||||
|
|
||||||
|
void Invalidate()
|
||||||
|
{
|
||||||
|
mIter.reset();
|
||||||
|
mArray.reset();
|
||||||
|
mozWritePoison(&mChildren, sizeof(mChildren));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemsAreAlreadyInOrder() const { return mIter.isSome(); }
|
||||||
|
|
||||||
|
static bool CSSOrderComparator(nsIFrame* const& a, nsIFrame* const& b);
|
||||||
private:
|
private:
|
||||||
static bool IsCSSOrderLessThan(nsIFrame* const& a, nsIFrame* const& b)
|
|
||||||
{ return a->StylePosition()->mOrder < b->StylePosition()->mOrder; }
|
|
||||||
|
|
||||||
nsFrameList mChildren;
|
nsFrameList mChildren;
|
||||||
// Used if child list is already in ascending 'order'.
|
// Used if child list is already in ascending 'order'.
|
||||||
Maybe<nsFrameList::Enumerator> mEnumerator;
|
Maybe<Iterator> mIter;
|
||||||
|
Maybe<Iterator> mIterEnd;
|
||||||
// Used if child list is *not* in ascending 'order'.
|
// Used if child list is *not* in ascending 'order'.
|
||||||
|
// This array is pre-sorted in reverse order for a reverse iterator.
|
||||||
Maybe<nsTArray<nsIFrame*>> mArray;
|
Maybe<nsTArray<nsIFrame*>> mArray;
|
||||||
size_t mArrayIndex;
|
size_t mArrayIndex;
|
||||||
// The index of the current grid item (placeholders excluded).
|
// The index of the current grid item (placeholders excluded).
|
||||||
size_t mGridItemIndex;
|
size_t mGridItemIndex;
|
||||||
|
// The number of grid items (placeholders excluded).
|
||||||
|
// It's only initialized and used in a reverse iterator.
|
||||||
|
Maybe<size_t> mGridItemCount;
|
||||||
// Skip placeholder children in the iteration?
|
// Skip placeholder children in the iteration?
|
||||||
bool mSkipPlaceholders;
|
bool mSkipPlaceholders;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -477,6 +521,48 @@ private:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using GridItemCSSOrderIterator = nsGridContainerFrame::GridItemCSSOrderIterator;
|
||||||
|
using ReverseGridItemCSSOrderIterator = nsGridContainerFrame::ReverseGridItemCSSOrderIterator;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
GridItemCSSOrderIterator::CSSOrderComparator(nsIFrame* const& a,
|
||||||
|
nsIFrame* const& b)
|
||||||
|
{ return a->StylePosition()->mOrder < b->StylePosition()->mOrder; }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
GridItemCSSOrderIterator::IsForward() const { return true; }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
nsFrameList::iterator
|
||||||
|
GridItemCSSOrderIterator::begin(const nsFrameList& aList)
|
||||||
|
{ return aList.begin(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
nsFrameList::iterator GridItemCSSOrderIterator::end(const nsFrameList& aList)
|
||||||
|
{ return aList.end(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
ReverseGridItemCSSOrderIterator::CSSOrderComparator(nsIFrame* const& a,
|
||||||
|
nsIFrame* const& b)
|
||||||
|
{ return a->StylePosition()->mOrder > b->StylePosition()->mOrder; }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool
|
||||||
|
ReverseGridItemCSSOrderIterator::IsForward() const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
nsFrameList::reverse_iterator
|
||||||
|
ReverseGridItemCSSOrderIterator::begin(const nsFrameList& aList)
|
||||||
|
{ return aList.rbegin(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
nsFrameList::reverse_iterator
|
||||||
|
ReverseGridItemCSSOrderIterator::end(const nsFrameList& aList)
|
||||||
|
{ return aList.rend(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A LineRange can be definite or auto - when it's definite it represents
|
* A LineRange can be definite or auto - when it's definite it represents
|
||||||
|
@ -5436,9 +5522,15 @@ nsGridContainerFrame::ReflowRowsInFragmentainer(
|
||||||
if (!pushedList.IsEmpty()) {
|
if (!pushedList.IsEmpty()) {
|
||||||
MergeSortedOverflow(pushedList);
|
MergeSortedOverflow(pushedList);
|
||||||
AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
|
AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
|
||||||
|
// NOTE since we messed with our child list here, we intentionally
|
||||||
|
// make aState.mIter invalid to avoid any use of it after this point.
|
||||||
|
aState.mIter.Invalidate();
|
||||||
}
|
}
|
||||||
if (!incompleteList.IsEmpty()) {
|
if (!incompleteList.IsEmpty()) {
|
||||||
MergeSortedOverflow(incompleteList);
|
MergeSortedOverflow(incompleteList);
|
||||||
|
// NOTE since we messed with our child list here, we intentionally
|
||||||
|
// make aState.mIter invalid to avoid any use of it after this point.
|
||||||
|
aState.mIter.Invalidate();
|
||||||
}
|
}
|
||||||
if (!overflowIncompleteList.IsEmpty()) {
|
if (!overflowIncompleteList.IsEmpty()) {
|
||||||
MergeSortedExcessOverflowContainers(overflowIncompleteList);
|
MergeSortedExcessOverflowContainers(overflowIncompleteList);
|
||||||
|
|
|
@ -189,6 +189,11 @@ public:
|
||||||
struct TrackSize;
|
struct TrackSize;
|
||||||
struct GridItemInfo;
|
struct GridItemInfo;
|
||||||
struct GridReflowInput;
|
struct GridReflowInput;
|
||||||
|
template<typename Iterator> class GridItemCSSOrderIteratorT;
|
||||||
|
typedef GridItemCSSOrderIteratorT<nsFrameList::iterator>
|
||||||
|
GridItemCSSOrderIterator;
|
||||||
|
typedef GridItemCSSOrderIteratorT<nsFrameList::reverse_iterator>
|
||||||
|
ReverseGridItemCSSOrderIterator;
|
||||||
protected:
|
protected:
|
||||||
static const uint32_t kAutoLine;
|
static const uint32_t kAutoLine;
|
||||||
// The maximum line number, in the zero-based translated grid.
|
// The maximum line number, in the zero-based translated grid.
|
||||||
|
@ -202,7 +207,6 @@ protected:
|
||||||
typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
|
typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
|
||||||
struct Grid;
|
struct Grid;
|
||||||
struct GridArea;
|
struct GridArea;
|
||||||
class GridItemCSSOrderIterator;
|
|
||||||
class LineNameMap;
|
class LineNameMap;
|
||||||
struct LineRange;
|
struct LineRange;
|
||||||
struct SharedGridData;
|
struct SharedGridData;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче