/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef RETAINEDDISPLAYLISTHELPERS_H_ #define RETAINEDDISPLAYLISTHELPERS_H_ #include "mozilla/Span.h" #include "PLDHashTable.h" class nsIFrame; namespace mozilla { struct DisplayItemKey { bool operator==(const DisplayItemKey& aOther) const { return mFrame == aOther.mFrame && mPerFrameKey == aOther.mPerFrameKey; } nsIFrame* mFrame; uint32_t mPerFrameKey; }; class DisplayItemHashEntry : public PLDHashEntryHdr { public: typedef DisplayItemKey KeyType; typedef const DisplayItemKey* KeyTypePointer; explicit DisplayItemHashEntry(KeyTypePointer aKey) : mKey(*aKey) {} DisplayItemHashEntry(DisplayItemHashEntry&&) = default; ~DisplayItemHashEntry() = default; KeyType GetKey() const { return mKey; } bool KeyEquals(KeyTypePointer aKey) const { return mKey == *aKey; } static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; } static PLDHashNumber HashKey(KeyTypePointer aKey) { if (!aKey) { return 0; } return mozilla::HashGeneric(aKey->mFrame, aKey->mPerFrameKey); } enum { ALLOW_MEMMOVE = true }; DisplayItemKey mKey; }; template bool SpanContains(mozilla::Span& aSpan, T aItem) { for (const T& i : aSpan) { if (i == aItem) { return true; } } return false; } class OldListUnits {}; class MergedListUnits {}; template struct Index { Index() : val(0) {} explicit Index(size_t aVal) : val(aVal) { MOZ_RELEASE_ASSERT(aVal < std::numeric_limits::max(), "List index overflowed"); } bool operator==(const Index& aOther) const { return val == aOther.val; } uint32_t val; }; typedef Index OldListIndex; typedef Index MergedListIndex; template class DirectedAcyclicGraph { public: DirectedAcyclicGraph() = default; DirectedAcyclicGraph(DirectedAcyclicGraph&& aOther) : mNodesInfo(std::move(aOther.mNodesInfo)), mDirectPredecessorList(std::move(aOther.mDirectPredecessorList)) {} DirectedAcyclicGraph& operator=(DirectedAcyclicGraph&& aOther) { mNodesInfo = std::move(aOther.mNodesInfo); mDirectPredecessorList = std::move(aOther.mDirectPredecessorList); return *this; } Index AddNode( mozilla::Span> aDirectPredecessors, const mozilla::Maybe>& aExtraPredecessor = mozilla::Nothing()) { size_t index = mNodesInfo.Length(); mNodesInfo.AppendElement(NodeInfo(mDirectPredecessorList.Length(), aDirectPredecessors.Length())); if (aExtraPredecessor && !SpanContains(aDirectPredecessors, aExtraPredecessor.value())) { mNodesInfo.LastElement().mDirectPredecessorCount++; mDirectPredecessorList.SetCapacity(mDirectPredecessorList.Length() + aDirectPredecessors.Length() + 1); mDirectPredecessorList.AppendElements(aDirectPredecessors); mDirectPredecessorList.AppendElement(aExtraPredecessor.value()); } else { mDirectPredecessorList.AppendElements(aDirectPredecessors); } return Index(index); } size_t Length() { return mNodesInfo.Length(); } mozilla::Span> GetDirectPredecessors(Index aNodeIndex) { NodeInfo& node = mNodesInfo[aNodeIndex.val]; const auto span = mozilla::Span{mDirectPredecessorList}; return span.Subspan(node.mIndexInDirectPredecessorList, node.mDirectPredecessorCount); } template void EnsureCapacityFor(const DirectedAcyclicGraph& aOther) { mNodesInfo.SetCapacity(aOther.mNodesInfo.Length()); mDirectPredecessorList.SetCapacity(aOther.mDirectPredecessorList.Length()); } void Clear() { mNodesInfo.Clear(); mDirectPredecessorList.Clear(); } struct NodeInfo { NodeInfo(size_t aIndexInDirectPredecessorList, size_t aDirectPredecessorCount) : mIndexInDirectPredecessorList(aIndexInDirectPredecessorList), mDirectPredecessorCount(aDirectPredecessorCount) {} size_t mIndexInDirectPredecessorList; size_t mDirectPredecessorCount; }; nsTArray mNodesInfo; nsTArray> mDirectPredecessorList; }; class RetainedDisplayListBuilder; class nsDisplayItem; struct OldItemInfo { explicit OldItemInfo(nsDisplayItem* aItem); void AddedToMergedList(MergedListIndex aIndex) { MOZ_ASSERT(!IsUsed()); mUsed = true; mIndex = aIndex; mItem = nullptr; } void AddedMatchToMergedList(RetainedDisplayListBuilder* aBuilder, MergedListIndex aIndex); void Discard(RetainedDisplayListBuilder* aBuilder, nsTArray&& aDirectPredecessors); bool IsUsed() { return mUsed; } bool IsDiscarded() { MOZ_ASSERT(IsUsed()); return mDiscarded; } bool IsChanged(); nsDisplayItem* mItem; nsTArray mDirectPredecessors; MergedListIndex mIndex; bool mUsed; bool mDiscarded; bool mOwnsItem; }; bool AnyContentAncestorModified(nsIFrame* aFrame, nsIFrame* aStopAtFrame = nullptr); } // namespace mozilla #endif // RETAINEDDISPLAYLISTHELPERS_H_