#387: pulled nsGenConList.* with relevant deps up to mozilla-central

This commit is contained in:
Cameron Kaiser 2017-05-06 12:29:55 -07:00
parent 922a327382
commit b1831fc750
7 changed files with 206 additions and 154 deletions

View File

@ -186,11 +186,7 @@ nsCounterList::RecalcAll()
{ {
mDirty = false; mDirty = false;
nsCounterNode *node = First(); for (nsCounterNode* node = First(); node; node = Next(node)) {
if (!node)
return;
do {
SetScope(node); SetScope(node);
node->Calc(this); node->Calc(this);
@ -205,7 +201,7 @@ nsCounterList::RecalcAll()
useNode->mText->SetData(text); useNode->mText->SetData(text);
} }
} }
} while ((node = Next(node)) != First()); }
} }
nsCounterManager::nsCounterManager() nsCounterManager::nsCounterManager()
@ -291,21 +287,17 @@ nsCounterManager::SetAllCounterStylesDirty()
{ {
for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) { for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
nsCounterList* list = iter.UserData(); nsCounterList* list = iter.UserData();
nsCounterNode* first = list->First(); bool changed = false;
if (first) { for (nsCounterNode* node = list->First(); node; node = list->Next(node)) {
bool changed = false; if (node->mType == nsCounterNode::USE) {
nsCounterNode* node = first; node->UseNode()->SetCounterStyleDirty();
do { changed = true;
if (node->mType == nsCounterNode::USE) {
node->UseNode()->SetCounterStyleDirty();
changed = true;
}
} while ((node = list->Next(node)) != first);
if (changed) {
list->SetDirty();
} }
} }
if (changed) {
list->SetDirty();
}
} }
} }
@ -327,32 +319,29 @@ nsCounterManager::DestroyNodesFor(nsIFrame *aFrame)
void void
nsCounterManager::Dump() nsCounterManager::Dump()
{ {
printf("\n\nCounter Manager Lists:\n"); printf("\n\nCounter Manager Lists:\n");
for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) { for (auto iter = mNames.Iter(); !iter.Done(); iter.Next()) {
printf("Counter named \"%s\":\n", printf("Counter named \"%s\":\n",
NS_ConvertUTF16toUTF8(iter.Key()).get()); NS_ConvertUTF16toUTF8(iter.Key()).get());
nsCounterList* list = iter.UserData(); nsCounterList* list = iter.UserData();
nsCounterNode* node = list->First(); int32_t i = 0;
if (node) { for (nsCounterNode* node = list->First(); node; node = list->Next(node)) {
int32_t i = 0; const char* types[] = { "RESET", "INCREMENT", "USE" };
do { printf(" Node #%d @%p frame=%p index=%d type=%s valAfter=%d\n"
const char* types[] = { "RESET", "INCREMENT", "USE" }; " scope-start=%p scope-prev=%p",
printf(" Node #%d @%p frame=%p index=%d type=%s valAfter=%d\n" i++, (void*)node, (void*)node->mPseudoFrame,
" scope-start=%p scope-prev=%p", node->mContentIndex, types[node->mType],
i++, (void*)node, (void*)node->mPseudoFrame, node->mValueAfter, (void*)node->mScopeStart,
node->mContentIndex, types[node->mType], (void*)node->mScopePrev);
node->mValueAfter, (void*)node->mScopeStart, if (node->mType == nsCounterNode::USE) {
(void*)node->mScopePrev); nsAutoString text;
if (node->mType == nsCounterNode::USE) { node->UseNode()->GetText(text);
nsAutoString text; printf(" text=%s", NS_ConvertUTF16toUTF8(text).get());
node->UseNode()->GetText(text); }
printf(" text=%s", NS_ConvertUTF16toUTF8(text).get()); printf("\n");
}
printf("\n");
} while ((node = list->Next(node)) != list->First());
}
} }
printf("\n\n"); }
printf("\n\n");
} }
#endif #endif

View File

@ -187,7 +187,7 @@ public:
} }
nsCounterNode* First() { nsCounterNode* First() {
return static_cast<nsCounterNode*>(mFirstNode); return static_cast<nsCounterNode*>(mList.getFirst());
} }
static nsCounterNode* Next(nsCounterNode* aNode) { static nsCounterNode* Next(nsCounterNode* aNode) {

View File

@ -13,55 +13,39 @@
void void
nsGenConList::Clear() nsGenConList::Clear()
{ {
//Delete entire list // Delete entire list.
if (!mFirstNode) mNodes.Clear();
return; while (nsGenConNode* node = mList.popFirst()) {
for (nsGenConNode *node = Next(mFirstNode); node != mFirstNode;
node = Next(mFirstNode))
{
Remove(node);
delete node; delete node;
} }
delete mFirstNode;
mFirstNode = nullptr;
mSize = 0; mSize = 0;
mLastInserted = nullptr;
} }
bool bool
nsGenConList::DestroyNodesFor(nsIFrame* aFrame) nsGenConList::DestroyNodesFor(nsIFrame* aFrame)
{ {
if (!mFirstNode) // This algorithm relies on the invariant that nodes of a frame are
return false; // list empty // put contiguously in the linked list. This is guaranteed because
nsGenConNode* node; // each frame is mapped to only one (nsIContent, pseudoType) pair,
bool destroyed = false; // and the nodes in the linked list are put in the tree order based
while (mFirstNode->mPseudoFrame == aFrame) { // on that pair and offset inside frame.
destroyed = true; nsGenConNode* node = mNodes.GetAndRemove(aFrame).valueOr(nullptr);
node = Next(mFirstNode); if (!node) {
bool isLastNode = node == mFirstNode; // before they're dangling return false;
Remove(mFirstNode);
delete mFirstNode;
if (isLastNode) {
mFirstNode = nullptr;
return true;
}
else {
mFirstNode = node;
}
} }
node = Next(mFirstNode); MOZ_ASSERT(node->mPseudoFrame == aFrame);
while (node != mFirstNode) {
if (node->mPseudoFrame == aFrame) { while (node && node->mPseudoFrame == aFrame) {
destroyed = true; nsGenConNode* nextNode = Next(node);
nsGenConNode *nextNode = Next(node); Destroy(node);
Remove(node); node = nextNode;
delete node;
node = nextNode;
} else {
node = Next(node);
}
} }
return destroyed;
// Modification of the list invalidates the cached pointer.
mLastInserted = nullptr;
return true;
} }
/** /**
@ -118,62 +102,101 @@ nsGenConList::NodeAfter(const nsGenConNode* aNode1, const nsGenConNode* aNode2)
// XXX Switch to the frame version of DoCompareTreePosition? // XXX Switch to the frame version of DoCompareTreePosition?
int32_t cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2, int32_t cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2,
pseudoType1, -pseudoType2); pseudoType1, -pseudoType2);
NS_ASSERTION(cmp != 0, "same content, different frames"); MOZ_ASSERT(cmp != 0, "same content, different frames");
return cmp > 0; return cmp > 0;
} }
void void
nsGenConList::Insert(nsGenConNode* aNode) nsGenConList::Insert(nsGenConNode* aNode)
{ {
if (mFirstNode) { // Check for append.
// Check for append. if (mList.isEmpty() || NodeAfter(aNode, mList.getLast())) {
if (NodeAfter(aNode, Prev(mFirstNode))) { mList.insertBack(aNode);
PR_INSERT_BEFORE(aNode, mFirstNode); } else if (mLastInserted && mLastInserted != mList.getLast() &&
} NodeAfter(aNode, mLastInserted) &&
else { NodeAfter(Next(mLastInserted), aNode)) {
// Binary search. // Fast path for inserting many consecutive nodes in one place
mLastInserted->setNext(aNode);
} else {
// Binary search.
// the range of indices at which |aNode| could end up. // the range of indices at which |aNode| could end up.
// (We already know it can't be at index mSize.) // (We already know it can't be at index mSize.)
uint32_t first = 0, last = mSize - 1; uint32_t first = 0, last = mSize - 1;
// A cursor to avoid walking more than the length of the list. // A cursor to avoid walking more than the length of the list.
nsGenConNode *curNode = Prev(mFirstNode); nsGenConNode* curNode = mList.getLast();
uint32_t curIndex = mSize - 1; uint32_t curIndex = mSize - 1;
while (first != last) { while (first != last) {
uint32_t test = (first + last) / 2; uint32_t test = (first + last) / 2;
if (last == curIndex) { if (last == curIndex) {
for ( ; curIndex != test; --curIndex) for ( ; curIndex != test; --curIndex)
curNode = Prev(curNode); curNode = Prev(curNode);
} else { } else {
for ( ; curIndex != test; ++curIndex) for ( ; curIndex != test; ++curIndex)
curNode = Next(curNode);
}
if (NodeAfter(aNode, curNode)) {
first = test + 1;
// if we exit the loop, we need curNode to be right
++curIndex;
curNode = Next(curNode); curNode = Next(curNode);
} else {
last = test;
}
} }
PR_INSERT_BEFORE(aNode, curNode);
if (curNode == mFirstNode) { if (NodeAfter(aNode, curNode)) {
mFirstNode = aNode; first = test + 1;
// if we exit the loop, we need curNode to be right
++curIndex;
curNode = Next(curNode);
} else {
last = test;
} }
} }
} curNode->setPrevious(aNode);
else {
// initialize list with first node
PR_INIT_CLIST(aNode);
mFirstNode = aNode;
} }
++mSize; ++mSize;
NS_ASSERTION(aNode == mFirstNode || NodeAfter(aNode, Prev(aNode)), mLastInserted = aNode;
// Set the mapping only if it is the first node of the frame.
// The DEBUG blocks below are for ensuring the invariant required by
// nsGenConList::DestroyNodesFor. See comment there.
if (IsFirst(aNode) ||
Prev(aNode)->mPseudoFrame != aNode->mPseudoFrame) {
#ifdef DEBUG
if (nsGenConNode* oldFrameFirstNode = mNodes.Get(aNode->mPseudoFrame)) {
MOZ_ASSERT(Next(aNode) == oldFrameFirstNode,
"oldFrameFirstNode should now be immediately after "
"the newly-inserted one.");
} else {
// If the node is not the only node in the list.
if (!IsFirst(aNode) || !IsLast(aNode)) {
nsGenConNode* nextNode = Next(aNode);
MOZ_ASSERT(!nextNode || nextNode->mPseudoFrame != aNode->mPseudoFrame,
"There shouldn't exist any node for this frame.");
// If the node is neither the first nor the last node
if (!IsFirst(aNode) && !IsLast(aNode)) {
MOZ_ASSERT(Prev(aNode)->mPseudoFrame != nextNode->mPseudoFrame,
"New node should not break contiguity of nodes of "
"the same frame.");
}
}
}
#endif
mNodes.Put(aNode->mPseudoFrame, aNode);
} else {
#ifdef DEBUG
nsGenConNode* frameFirstNode = mNodes.Get(aNode->mPseudoFrame);
MOZ_ASSERT(frameFirstNode, "There should exist node map for the frame.");
for (nsGenConNode* curNode = Prev(aNode);
curNode != frameFirstNode; curNode = Prev(curNode)) {
MOZ_ASSERT(curNode->mPseudoFrame == aNode->mPseudoFrame,
"Every node between frameFirstNode and the new node inserted "
"should refer to the same frame.");
MOZ_ASSERT(!IsFirst(curNode),
"The newly-inserted node should be in a contiguous run after "
"frameFirstNode, thus frameFirstNode should be reached before "
"the first node of mList.");
}
#endif
}
NS_ASSERTION(IsFirst(aNode) || NodeAfter(aNode, Prev(aNode)),
"sorting error"); "sorting error");
NS_ASSERTION(IsLast(aNode) || NodeAfter(Next(aNode), aNode), NS_ASSERTION(IsLast(aNode) || NodeAfter(Next(aNode), aNode),
"sorting error"); "sorting error");

View File

@ -8,15 +8,15 @@
#ifndef nsGenConList_h___ #ifndef nsGenConList_h___
#define nsGenConList_h___ #define nsGenConList_h___
#include "mozilla/LinkedList.h"
#include "nsIFrame.h" #include "nsIFrame.h"
#include "nsStyleStruct.h" #include "nsStyleStruct.h"
#include "prclist.h"
#include "nsCSSPseudoElements.h" #include "nsCSSPseudoElements.h"
#include "nsTextNode.h" #include "nsTextNode.h"
class nsGenConList; class nsGenConList;
struct nsGenConNode : public PRCList { struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
// The wrapper frame for all of the pseudo-element's content. This // The wrapper frame for all of the pseudo-element's content. This
// frame generally has useful style data and has the // frame generally has useful style data and has the
// NS_FRAME_GENERATED_CONTENT bit set (so we use it to track removal), // NS_FRAME_GENERATED_CONTENT bit set (so we use it to track removal),
@ -51,7 +51,7 @@ struct nsGenConNode : public PRCList {
* @return true iff this marked the list dirty * @return true iff this marked the list dirty
*/ */
virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame, virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
nsIFrame* aTextFrame) nsIFrame* aTextFrame)
{ {
mPseudoFrame = aPseudoFrame; mPseudoFrame = aPseudoFrame;
CheckFrameAssertions(); CheckFrameAssertions();
@ -82,28 +82,55 @@ protected:
class nsGenConList { class nsGenConList {
protected: protected:
nsGenConNode* mFirstNode; mozilla::LinkedList<nsGenConNode> mList;
uint32_t mSize; uint32_t mSize;
public: public:
nsGenConList() : mFirstNode(nullptr), mSize(0) {} nsGenConList() : mSize(0), mLastInserted(nullptr) {}
~nsGenConList() { Clear(); } ~nsGenConList() { Clear(); }
void Clear(); void Clear();
static nsGenConNode* Next(nsGenConNode* aNode) { static nsGenConNode* Next(nsGenConNode* aNode) {
return static_cast<nsGenConNode*>(PR_NEXT_LINK(aNode)); MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
return aNode->getNext();
} }
static nsGenConNode* Prev(nsGenConNode* aNode) { static nsGenConNode* Prev(nsGenConNode* aNode) {
return static_cast<nsGenConNode*>(PR_PREV_LINK(aNode)); MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
return aNode->getPrevious();
} }
void Insert(nsGenConNode* aNode); void Insert(nsGenConNode* aNode);
// returns whether any nodes have been destroyed
bool DestroyNodesFor(nsIFrame* aFrame); //destroy all nodes with aFrame as parent // Destroy all nodes with aFrame as parent. Returns true if some nodes
// have been destroyed; otherwise false.
bool DestroyNodesFor(nsIFrame* aFrame);
// Return true if |aNode1| is after |aNode2|. // Return true if |aNode1| is after |aNode2|.
static bool NodeAfter(const nsGenConNode* aNode1, static bool NodeAfter(const nsGenConNode* aNode1,
const nsGenConNode* aNode2); const nsGenConNode* aNode2);
void Remove(nsGenConNode* aNode) { PR_REMOVE_LINK(aNode); mSize--; } bool IsFirst(nsGenConNode* aNode) {
bool IsLast(nsGenConNode* aNode) { return (Next(aNode) == mFirstNode); } MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
return aNode == mList.getFirst();
}
bool IsLast(nsGenConNode* aNode) {
MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
return aNode == mList.getLast();
}
private:
void Destroy(nsGenConNode* aNode)
{
MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
delete aNode;
mSize--;
}
// Map from frame to the first nsGenConNode of it in the list.
nsDataHashtable<nsPtrHashKey<nsIFrame>, nsGenConNode*> mNodes;
// A weak pointer to the node most recently inserted, used to avoid repeated
// list traversals in Insert().
nsGenConNode* mLastInserted;
}; };
#endif /* nsGenConList_h___ */ #endif /* nsGenConList_h___ */

View File

@ -73,20 +73,13 @@ nsQuoteList::Calc(nsQuoteNode* aNode)
void void
nsQuoteList::RecalcAll() nsQuoteList::RecalcAll()
{ {
nsQuoteNode *node = FirstNode(); for (nsQuoteNode* node = FirstNode(); node; node = Next(node)) {
if (!node)
return;
do {
int32_t oldDepth = node->mDepthBefore; int32_t oldDepth = node->mDepthBefore;
Calc(node); Calc(node);
if (node->mDepthBefore != oldDepth && node->mText && node->IsRealQuote()) if (node->mDepthBefore != oldDepth && node->mText && node->IsRealQuote())
node->mText->SetData(*node->Text()); node->mText->SetData(*node->Text());
}
// Next node
node = Next(node);
} while (node != FirstNode());
} }
#ifdef DEBUG #ifdef DEBUG
@ -94,11 +87,7 @@ void
nsQuoteList::PrintChain() nsQuoteList::PrintChain()
{ {
printf("Chain: \n"); printf("Chain: \n");
if (!FirstNode()) { for (nsQuoteNode* node = FirstNode(); node; node = Next(node)) {
return;
}
nsQuoteNode* node = FirstNode();
do {
printf(" %p %d - ", static_cast<void*>(node), node->mDepthBefore); printf(" %p %d - ", static_cast<void*>(node), node->mDepthBefore);
switch(node->mType) { switch(node->mType) {
case (eStyleContentType_OpenQuote): case (eStyleContentType_OpenQuote):
@ -123,7 +112,6 @@ nsQuoteList::PrintChain()
printf(" \"%s\",", NS_ConvertUTF16toUTF8(data).get()); printf(" \"%s\",", NS_ConvertUTF16toUTF8(data).get());
} }
printf("\n"); printf("\n");
node = Next(node); }
} while (node != FirstNode());
} }
#endif #endif

View File

@ -70,7 +70,7 @@ struct nsQuoteNode : public nsGenConNode {
class nsQuoteList : public nsGenConList { class nsQuoteList : public nsGenConList {
private: private:
nsQuoteNode* FirstNode() { return static_cast<nsQuoteNode*>(mFirstNode); } nsQuoteNode* FirstNode() { return static_cast<nsQuoteNode*>(mList.getFirst()); }
public: public:
// assign the correct |mDepthBefore| value to a node that has been inserted // assign the correct |mDepthBefore| value to a node that has been inserted
// Should be called immediately after calling |Insert|. // Should be called immediately after calling |Insert|.

View File

@ -9,6 +9,7 @@
#include "nsHashKeys.h" #include "nsHashKeys.h"
#include "nsBaseHashtable.h" #include "nsBaseHashtable.h"
#include "mozilla/Maybe.h"
/** /**
* templated hashtable class maps keys to simple datatypes. * templated hashtable class maps keys to simple datatypes.
@ -22,12 +23,36 @@ template<class KeyClass, class DataType>
class nsDataHashtable class nsDataHashtable
: public nsBaseHashtable<KeyClass, DataType, DataType> : public nsBaseHashtable<KeyClass, DataType, DataType>
{ {
private:
typedef nsBaseHashtable<KeyClass, DataType, DataType> BaseClass;
public: public:
using typename BaseClass::KeyType;
using typename BaseClass::EntryType;
nsDataHashtable() {} nsDataHashtable() {}
explicit nsDataHashtable(uint32_t aInitLength) explicit nsDataHashtable(uint32_t aInitLength)
: nsBaseHashtable<KeyClass, DataType, DataType>(aInitLength) : BaseClass(aInitLength)
{ {
} }
/**
* Retrieve the value for a key and remove the corresponding entry at
* the same time.
*
* @param aKey the key to retrieve and remove
* @return the found value, or Nothing if no entry was found with the
* given key.
*/
mozilla::Maybe<DataType> GetAndRemove(KeyType aKey)
{
mozilla::Maybe<DataType> value;
if (EntryType* ent = this->GetEntry(aKey)) {
value.emplace(mozilla::Move(ent->mData));
this->RemoveEntry(ent);
}
return value;
}
}; };
#endif // nsDataHashtable_h__ #endif // nsDataHashtable_h__