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

View File

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

View File

@ -13,55 +13,39 @@
void
nsGenConList::Clear()
{
//Delete entire list
if (!mFirstNode)
return;
for (nsGenConNode *node = Next(mFirstNode); node != mFirstNode;
node = Next(mFirstNode))
{
Remove(node);
// Delete entire list.
mNodes.Clear();
while (nsGenConNode* node = mList.popFirst()) {
delete node;
}
delete mFirstNode;
mFirstNode = nullptr;
mSize = 0;
mLastInserted = nullptr;
}
bool
nsGenConList::DestroyNodesFor(nsIFrame* aFrame)
{
if (!mFirstNode)
return false; // list empty
nsGenConNode* node;
bool destroyed = false;
while (mFirstNode->mPseudoFrame == aFrame) {
destroyed = true;
node = Next(mFirstNode);
bool isLastNode = node == mFirstNode; // before they're dangling
Remove(mFirstNode);
delete mFirstNode;
if (isLastNode) {
mFirstNode = nullptr;
return true;
}
else {
mFirstNode = node;
}
// This algorithm relies on the invariant that nodes of a frame are
// put contiguously in the linked list. This is guaranteed because
// each frame is mapped to only one (nsIContent, pseudoType) pair,
// and the nodes in the linked list are put in the tree order based
// on that pair and offset inside frame.
nsGenConNode* node = mNodes.GetAndRemove(aFrame).valueOr(nullptr);
if (!node) {
return false;
}
node = Next(mFirstNode);
while (node != mFirstNode) {
if (node->mPseudoFrame == aFrame) {
destroyed = true;
nsGenConNode *nextNode = Next(node);
Remove(node);
delete node;
node = nextNode;
} else {
node = Next(node);
}
MOZ_ASSERT(node->mPseudoFrame == aFrame);
while (node && node->mPseudoFrame == aFrame) {
nsGenConNode* nextNode = Next(node);
Destroy(node);
node = nextNode;
}
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?
int32_t cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2,
pseudoType1, -pseudoType2);
NS_ASSERTION(cmp != 0, "same content, different frames");
MOZ_ASSERT(cmp != 0, "same content, different frames");
return cmp > 0;
}
void
nsGenConList::Insert(nsGenConNode* aNode)
{
if (mFirstNode) {
// Check for append.
if (NodeAfter(aNode, Prev(mFirstNode))) {
PR_INSERT_BEFORE(aNode, mFirstNode);
}
else {
// Binary search.
// Check for append.
if (mList.isEmpty() || NodeAfter(aNode, mList.getLast())) {
mList.insertBack(aNode);
} else if (mLastInserted && mLastInserted != mList.getLast() &&
NodeAfter(aNode, mLastInserted) &&
NodeAfter(Next(mLastInserted), aNode)) {
// 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.
// (We already know it can't be at index mSize.)
uint32_t first = 0, last = mSize - 1;
// the range of indices at which |aNode| could end up.
// (We already know it can't be at index mSize.)
uint32_t first = 0, last = mSize - 1;
// A cursor to avoid walking more than the length of the list.
nsGenConNode *curNode = Prev(mFirstNode);
uint32_t curIndex = mSize - 1;
// A cursor to avoid walking more than the length of the list.
nsGenConNode* curNode = mList.getLast();
uint32_t curIndex = mSize - 1;
while (first != last) {
uint32_t test = (first + last) / 2;
if (last == curIndex) {
for ( ; curIndex != test; --curIndex)
curNode = Prev(curNode);
} else {
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;
while (first != last) {
uint32_t test = (first + last) / 2;
if (last == curIndex) {
for ( ; curIndex != test; --curIndex)
curNode = Prev(curNode);
} else {
for ( ; curIndex != test; ++curIndex)
curNode = Next(curNode);
} else {
last = test;
}
}
PR_INSERT_BEFORE(aNode, curNode);
if (curNode == mFirstNode) {
mFirstNode = aNode;
if (NodeAfter(aNode, curNode)) {
first = test + 1;
// if we exit the loop, we need curNode to be right
++curIndex;
curNode = Next(curNode);
} else {
last = test;
}
}
}
else {
// initialize list with first node
PR_INIT_CLIST(aNode);
mFirstNode = aNode;
curNode->setPrevious(aNode);
}
++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");
NS_ASSERTION(IsLast(aNode) || NodeAfter(Next(aNode), aNode),
"sorting error");

View File

@ -8,15 +8,15 @@
#ifndef nsGenConList_h___
#define nsGenConList_h___
#include "mozilla/LinkedList.h"
#include "nsIFrame.h"
#include "nsStyleStruct.h"
#include "prclist.h"
#include "nsCSSPseudoElements.h"
#include "nsTextNode.h"
class nsGenConList;
struct nsGenConNode : public PRCList {
struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
// The wrapper frame for all of the pseudo-element's content. This
// frame generally has useful style data and has the
// 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
*/
virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
nsIFrame* aTextFrame)
nsIFrame* aTextFrame)
{
mPseudoFrame = aPseudoFrame;
CheckFrameAssertions();
@ -82,28 +82,55 @@ protected:
class nsGenConList {
protected:
nsGenConNode* mFirstNode;
mozilla::LinkedList<nsGenConNode> mList;
uint32_t mSize;
public:
nsGenConList() : mFirstNode(nullptr), mSize(0) {}
nsGenConList() : mSize(0), mLastInserted(nullptr) {}
~nsGenConList() { Clear(); }
void Clear();
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) {
return static_cast<nsGenConNode*>(PR_PREV_LINK(aNode));
MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
return aNode->getPrevious();
}
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|.
static bool NodeAfter(const nsGenConNode* aNode1,
const nsGenConNode* aNode2);
const nsGenConNode* aNode2);
void Remove(nsGenConNode* aNode) { PR_REMOVE_LINK(aNode); mSize--; }
bool IsLast(nsGenConNode* aNode) { return (Next(aNode) == mFirstNode); }
bool IsFirst(nsGenConNode* aNode) {
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___ */

View File

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

View File

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

View File

@ -9,6 +9,7 @@
#include "nsHashKeys.h"
#include "nsBaseHashtable.h"
#include "mozilla/Maybe.h"
/**
* templated hashtable class maps keys to simple datatypes.
@ -22,12 +23,36 @@ template<class KeyClass, class DataType>
class nsDataHashtable
: public nsBaseHashtable<KeyClass, DataType, DataType>
{
private:
typedef nsBaseHashtable<KeyClass, DataType, DataType> BaseClass;
public:
using typename BaseClass::KeyType;
using typename BaseClass::EntryType;
nsDataHashtable() {}
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__