Part of the fix for bug 193678 (support exslt:common - allow txXPathNode to hold a strong ref to its root). r/sr=sicking.

This commit is contained in:
peterv%propagandism.org 2006-11-14 23:23:20 +00:00
Родитель ba5ddaa8d2
Коммит 46ea975af9
5 изменённых файлов: 167 добавлений и 50 удалений

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

@ -86,16 +86,13 @@ txXPathTreeWalker::moveToRoot()
mPosition.mNode = root;
}
else {
nsINode *parent, *current = mPosition.mNode;
while ((parent = current->GetNodeParent())) {
current = parent;
}
nsINode *rootNode = mPosition.Root();
NS_ASSERTION(current->IsNodeOfType(nsINode::eCONTENT),
NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT),
"root of subtree wasn't an nsIContent");
mPosition.mIndex = txXPathNode::eContent;
mPosition.mNode = current;
mPosition.mNode = rootNode;
}
mCurrentIndex = kUnknownIndex;
@ -123,16 +120,13 @@ txXPathTreeWalker::moveToElementById(const nsAString& aID)
}
else {
// We're in a disconnected subtree, search only that subtree.
nsINode *parent, *current = mPosition.mNode;
while ((parent = current->GetNodeParent())) {
current = parent;
}
nsINode *rootNode = mPosition.Root();
NS_ASSERTION(current->IsNodeOfType(nsINode::eCONTENT),
NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT),
"root of subtree wasn't an nsIContent");
content = nsContentUtils::MatchElementId(
NS_STATIC_CAST(nsIContent*, current), aID);
NS_STATIC_CAST(nsIContent*, rootNode), aID);
}
if (!content) {
@ -350,17 +344,6 @@ txXPathTreeWalker::moveToSibling(PRInt32 aDir)
return PR_TRUE;
}
txXPathNode::txXPathNode(const txXPathNode& aNode) : mIndex(aNode.mIndex),
mNode(aNode.mNode)
{
}
PRBool
txXPathNode::operator==(const txXPathNode& aNode) const
{
return mIndex == aNode.mIndex && mNode == aNode.mNode;
}
/* static */
PRBool
txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsIAtom* aLocalName,
@ -695,7 +678,6 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
nsINode* node = aNode.mNode;
nsINode* otherNode = aOtherNode.mNode;
nsINode* parent, *otherParent;
PRInt32 index, otherIndex;
while (node && otherNode) {
parent = node->GetNodeParent();
otherParent = otherNode->GetNodeParent();
@ -764,7 +746,7 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
/* static */
txXPathNode*
txXPathNativeNode::createXPathNode(nsIDOMNode* aNode)
txXPathNativeNode::createXPathNode(nsIDOMNode* aNode, PRBool aKeepRootAlive)
{
PRUint16 nodeType;
aNode->GetNodeType(&nodeType);
@ -779,11 +761,13 @@ txXPathNativeNode::createXPathNode(nsIDOMNode* aNode)
return nsnull;
}
nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nsnull;
PRUint32 i, total = parent->GetAttrCount();
for (i = 0; i < total; ++i) {
const nsAttrName* name = parent->GetAttrNameAt(i);
if (nodeInfo->Equals(name->LocalName(), name->NamespaceID())) {
return new txXPathNode(parent, i);
return new txXPathNode(parent, i, root);
}
}
@ -792,13 +776,21 @@ txXPathNativeNode::createXPathNode(nsIDOMNode* aNode)
return nsnull;
}
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
PRUint32 index;
nsINode* root = aKeepRootAlive ? node : nsnull;
if (nodeType == nsIDOMNode::DOCUMENT_NODE) {
nsCOMPtr<nsIDocument> document = do_QueryInterface(aNode);
return new txXPathNode(document);
index = txXPathNode::eDocument;
}
else {
index = txXPathNode::eContent;
if (root) {
root = txXPathNode::RootOf(root);
}
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
return new txXPathNode(content);
return new txXPathNode(node, index, root);
}
/* static */

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

@ -45,6 +45,24 @@
* Implementation of an XPath nodeset
*/
#ifdef NS_BUILD_REFCNT_LOGGING
#define LOG_CHUNK_MOVE(_start, _new_start, _count) \
{ \
txXPathNode *start = NS_CONST_CAST(txXPathNode*, _start); \
while (start < _start + _count) { \
NS_LogDtor(start, "txXPathNode", sizeof(*start)); \
++start; \
} \
start = NS_CONST_CAST(txXPathNode*, _new_start); \
while (start < _new_start + _count) { \
NS_LogCtor(start, "txXPathNode", sizeof(*start)); \
++start; \
} \
}
#else
#define LOG_CHUNK_MOVE(_start, _new_start, _count)
#endif
static const PRInt32 kTxNodeSetMinSize = 4;
static const PRInt32 kTxNodeSetGrowFactor = 2;
@ -96,10 +114,7 @@ txNodeSet::~txNodeSet()
delete [] mMarks;
if (mStartBuffer) {
while (mStart < mEnd) {
mStart->~txXPathNode();
++mStart;
}
destroyElements(mStart, mEnd);
nsMemory::Free(mStartBuffer);
}
@ -131,6 +146,7 @@ nsresult txNodeSet::add(const txXPathNode& aNode)
pos = mStart + offset;
if (moveSize > 0) {
LOG_CHUNK_MOVE(pos, pos + 1, moveSize);
memmove(pos + 1, pos, moveSize * sizeof(txXPathNode));
}
@ -142,13 +158,13 @@ nsresult txNodeSet::add(const txXPathNode& aNode)
nsresult txNodeSet::add(const txNodeSet& aNodes)
{
return add(aNodes, copyElements);
return add(aNodes, copyElements, nsnull);
}
nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes)
{
// failure is out-of-memory, transfer didn't happen
nsresult rv = add(*aNodes, transferElements);
nsresult rv = add(*aNodes, transferElements, destroyElements);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef TX_DONT_RECYCLE_BUFFER
@ -203,7 +219,8 @@ nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes)
* check for sequences of duplicate nodes, which can be optimized.
*
*/
nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer,
destroyOp aDestroy)
{
NS_ASSERTION(mDirection == kForward,
"only append(aNode) is supported on reversed nodesets");
@ -244,6 +261,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
pos = findPosition(thisPos[-1], aNodes.mStart, otherPos, dupe);
if (dupe) {
const txXPathNode *deletePos = thisPos;
--thisPos; // this is already added
// check dupe sequence
while (thisPos > mStart && pos > aNodes.mStart &&
@ -251,6 +269,10 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
--thisPos;
--pos;
}
if (aDestroy) {
aDestroy(thisPos, deletePos);
}
}
}
else {
@ -271,6 +293,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
pos = findPosition(otherPos[-1], mStart, thisPos, dupe);
if (dupe) {
const txXPathNode *deletePos = otherPos;
--otherPos; // this is already added
// check dupe sequence
while (otherPos > aNodes.mStart && pos > mStart &&
@ -278,6 +301,10 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
--otherPos;
--pos;
}
if (aDestroy) {
aDestroy(otherPos, deletePos);
}
}
}
else {
@ -289,6 +316,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer)
count = thisPos - pos;
if (count > 0) {
insertPos -= count;
LOG_CHUNK_MOVE(pos, insertPos, count);
memmove(insertPos, pos, count * sizeof(txXPathNode));
thisPos -= count;
}
@ -396,6 +424,7 @@ txNodeSet::sweep()
}
// move chunk
if (chunk > 0) {
LOG_CHUNK_MOVE(mStart + pos - chunk, insertion, chunk);
memmove(insertion, mStart + pos - chunk,
chunk * sizeof(txXPathNode));
insertion += chunk;
@ -412,10 +441,7 @@ txNodeSet::sweep()
void
txNodeSet::clear()
{
while (mStart < mEnd) {
mStart->~txXPathNode();
++mStart;
}
destroyElements(mStart, mEnd);
#ifdef TX_DONT_RECYCLE_BUFFER
if (mStartBuffer) {
nsMemory::Free(mStartBuffer);
@ -517,6 +543,7 @@ PRBool txNodeSet::ensureGrowSize(PRInt32 aSize)
if (mDirection == kReversed) {
dest = mEndBuffer - oldSize;
}
LOG_CHUNK_MOVE(mStart, dest, oldSize);
memmove(dest, mStart, oldSize * sizeof(txXPathNode));
mStart = dest;
mEnd = dest + oldSize;
@ -545,6 +572,7 @@ PRBool txNodeSet::ensureGrowSize(PRInt32 aSize)
}
if (oldSize > 0) {
LOG_CHUNK_MOVE(mStart, dest, oldSize);
memcpy(dest, mStart, oldSize * sizeof(txXPathNode));
}
@ -623,5 +651,6 @@ void
txNodeSet::transferElements(txXPathNode* aDest,
const txXPathNode* aStart, const txXPathNode* aEnd)
{
LOG_CHUNK_MOVE(aStart, aDest, (aEnd - aStart));
memcpy(aDest, aStart, (aEnd - aStart) * sizeof(txXPathNode));
}

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

@ -227,10 +227,21 @@ private:
const txXPathNode* aEnd);
static void transferElements(txXPathNode* aDest, const txXPathNode* aStart,
const txXPathNode* aEnd);
static void destroyElements(const txXPathNode* aStart,
const txXPathNode* aEnd)
{
while (aStart < aEnd) {
aStart->~txXPathNode();
++aStart;
}
}
typedef void (*transferOp) (txXPathNode* aDest, const txXPathNode* aStart,
const txXPathNode* aEnd);
nsresult add(const txNodeSet& aNodes, transferOp aTransfer);
typedef void (*destroyOp) (const txXPathNode* aStart,
const txXPathNode* aEnd);
nsresult add(const txNodeSet& aNodes, transferOp aTransfer,
destroyOp aDestroy);
txXPathNode *mStart, *mEnd, *mStartBuffer, *mEndBuffer;
PRInt32 mDirection;

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

@ -64,6 +64,7 @@ public:
{
return !(*this == aNode);
}
~txXPathNode();
private:
friend class txNodeSet;
@ -71,24 +72,48 @@ private:
friend class txXPathNodeUtils;
friend class txXPathTreeWalker;
txXPathNode(const txXPathNode& aNode);
#ifdef TX_EXE
txXPathNode(NodeDefinition* aNode) : mInner(aNode)
{
}
txXPathNode(const txXPathNode& aNode);
NodeDefinition* mInner;
#else
txXPathNode(nsIDocument* aDocument) : mNode(aDocument),
mRefCountRoot(0),
mIndex(eDocument)
{
MOZ_COUNT_CTOR(txXPathNode);
}
txXPathNode(nsIContent* aContent, PRUint32 aIndex = eContent)
: mNode(aContent),
txXPathNode(nsINode *aNode, PRUint32 aIndex, nsINode *aRoot)
: mNode(aNode),
mRefCountRoot(aRoot ? 1 : 0),
mIndex(aIndex)
{
MOZ_COUNT_CTOR(txXPathNode);
if (aRoot) {
NS_ADDREF(aRoot);
}
}
static nsINode *RootOf(nsINode *aNode)
{
nsINode *ancestor, *root = aNode;
while ((ancestor = root->GetNodeParent())) {
root = ancestor;
}
return root;
}
nsINode *Root() const
{
return RootOf(mNode);
}
nsINode *GetRootToAddRef() const
{
return mRefCountRoot ? Root() : nsnull;
}
txXPathNode(const txXPathNode& aNode);
PRBool isDocument() const
{
@ -116,11 +141,13 @@ private:
enum PositionType
{
eDocument = (PRUint32)-2,
eContent = (PRUint32)-1
eDocument = (1 << 30),
eContent = eDocument - 1
};
nsINode* mNode;
PRUint32 mIndex;
PRUint32 mRefCountRoot : 1;
PRUint32 mIndex : 31;
#endif
};
@ -157,4 +184,47 @@ txNamespaceManager::getNamespaceURI(const PRInt32 aID, nsAString& aResult)
#endif
}
#ifdef TX_EXE
inline
txXPathNode::txXPathNode(const txXPathNode& aNode)
: mInner(aNode.mInner)
{
}
#else
inline
txXPathNode::txXPathNode(const txXPathNode& aNode)
: mNode(aNode.mNode),
mRefCountRoot(aNode.mRefCountRoot),
mIndex(aNode.mIndex)
{
MOZ_COUNT_CTOR(txXPathNode);
if (mRefCountRoot) {
NS_ADDREF(Root());
}
}
#endif
inline
txXPathNode::~txXPathNode()
{
#ifdef TX_EXE
#else
MOZ_COUNT_DTOR(txXPathNode);
if (mRefCountRoot) {
nsINode *root = Root();
NS_RELEASE(root);
}
#endif
}
inline PRBool
txXPathNode::operator==(const txXPathNode& aNode) const
{
#ifdef TX_EXE
return (mInner == aNode.mInner);
#else
return mIndex == aNode.mIndex && mNode == aNode.mNode;
#endif
}
#endif /* txXPathNode_h__ */

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

@ -160,7 +160,8 @@ public:
class txXPathNativeNode
{
public:
static txXPathNode* createXPathNode(nsIDOMNode* aNode);
static txXPathNode* createXPathNode(nsIDOMNode* aNode,
PRBool aKeepRootAlive = PR_FALSE);
static txXPathNode* createXPathNode(nsIDOMDocument* aDocument);
static nsresult getNode(const txXPathNode& aNode, nsIDOMNode** aResult);
static nsIContent* getContent(const txXPathNode& aNode);
@ -215,8 +216,22 @@ txXPathTreeWalker::moveTo(const txXPathTreeWalker& aWalker)
#ifdef TX_EXE
mPosition.mInner = aWalker.mPosition.mInner;
#else
nsINode *root = nsnull;
if (mPosition.mRefCountRoot) {
root = mPosition.Root();
}
mPosition.mIndex = aWalker.mPosition.mIndex;
mPosition.mRefCountRoot = aWalker.mPosition.mRefCountRoot;
mPosition.mNode = aWalker.mPosition.mNode;
nsINode *newRoot = nsnull;
if (mPosition.mRefCountRoot) {
newRoot = mPosition.Root();
}
if (root != newRoot) {
NS_IF_ADDREF(newRoot);
NS_IF_RELEASE(root);
}
mCurrentIndex = aWalker.mCurrentIndex;
mDescendants.Clear();
#endif