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:
Mats Palmgren 2016-10-01 02:26:39 +02:00
Родитель 17c865d7bc
Коммит fd54eb1633
2 изменённых файлов: 127 добавлений и 31 удалений

Просмотреть файл

@ -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,15 +324,16 @@ 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)
: mChildren(aGridContainer->GetChildList(aListID)) : mChildren(aGridContainer->GetChildList(aListID))
, mArrayIndex(0) , mArrayIndex(0)
, mGridItemIndex(0) , mGridItemIndex(0)
@ -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;