Make nsRange::ToString and nsContentIterator deal with ranges with endpoint containers being the document. Patch by bz. r/sr=sicking b=358660

This commit is contained in:
cvshook%sicking.cc 2006-11-02 07:41:45 +00:00
Родитель 3c0294cc84
Коммит f3a3af9cca
3 изменённых файлов: 104 добавлений и 79 удалений

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

@ -115,12 +115,12 @@ GetChildAt(nsIDOMNode *aParent, PRInt32 aOffset)
}
///////////////////////////////////////////////////////////////////////////
// ContentHasChildren: returns true if the content has children
// ContentHasChildren: returns true if the node has children
//
static inline PRBool
ContentHasChildren(nsIContent *aContent)
NodeHasChildren(nsINode *aNode)
{
return aContent->GetChildCount() > 0;
return aNode->GetChildCount() > 0;
}
///////////////////////////////////////////////////////////////////////////
@ -220,8 +220,13 @@ protected:
nsIContent *GetDeepFirstChild(nsIContent *aRoot, nsVoidArray *aIndexes);
nsIContent *GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes);
nsIContent *GetNextSibling(nsIContent *aNode, nsVoidArray *aIndexes);
nsIContent *GetPrevSibling(nsIContent *aNode, nsVoidArray *aIndexes);
// Get the next sibling of aNode. Note that this will generally return null
// if aNode happens not to be a content node. That's OK.
nsIContent *GetNextSibling(nsINode *aNode, nsVoidArray *aIndexes);
// Get the prev sibling of aNode. Note that this will generally return null
// if aNode happens not to be a content node. That's OK.
nsIContent *GetPrevSibling(nsINode *aNode, nsVoidArray *aIndexes);
nsIContent *NextNode(nsIContent *aNode, nsVoidArray *aIndexes);
nsIContent *PrevNode(nsIContent *aNode, nsVoidArray *aIndexes);
@ -234,7 +239,7 @@ protected:
nsCOMPtr<nsIContent> mCurNode;
nsCOMPtr<nsIContent> mFirst;
nsCOMPtr<nsIContent> mLast;
nsCOMPtr<nsIContent> mCommonParent;
nsCOMPtr<nsINode> mCommonParent;
// used by nsContentIterator to cache indices
nsAutoVoidArray mIndexes;
@ -370,39 +375,26 @@ nsContentIterator::Init(nsIDOMRange* aRange)
nsCOMPtr<nsIRange> range = do_QueryInterface(aRange);
NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIContent> startCon;
nsCOMPtr<nsIContent> endCon;
PRInt32 startIndx;
PRInt32 endIndx;
mIsDone = PR_FALSE;
// get common content parent
nsINode* ancestor = range->GetCommonAncestor();
mCommonParent = ancestor && ancestor->IsNodeOfType(nsINode::eCONTENT) ?
NS_STATIC_CAST(nsIContent*, ancestor) : nsnull;
mCommonParent = range->GetCommonAncestor();
NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);
// get the start node and offset, convert to nsIContent
startIndx = range->StartOffset();
// get the start node and offset
PRInt32 startIndx = range->StartOffset();
nsINode* startNode = range->GetStartParent();
if (!startNode || !startNode->IsNodeOfType(nsINode::eCONTENT)) {
return NS_ERROR_FAILURE;
}
startCon = NS_STATIC_CAST(nsIContent*, startNode);
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
// get the end node and offset, convert to nsIContent
endIndx = range->EndOffset();
// get the end node and offset
PRInt32 endIndx = range->EndOffset();
nsINode* endNode = range->GetEndParent();
if (!endNode || !endNode->IsNodeOfType(nsINode::eCONTENT)) {
return NS_ERROR_FAILURE;
}
endCon = NS_STATIC_CAST(nsIContent*, endNode);
NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
PRBool startIsData = startCon->IsNodeOfType(nsINode::eDATA_NODE);
PRBool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
// short circuit when start node == end node
if (startCon == endCon)
if (startNode == endNode)
{
// Check to see if we have a collapsed range, if so,
// there is nothing to iterate over.
@ -420,10 +412,12 @@ nsContentIterator::Init(nsIDOMRange* aRange)
if (startIsData)
{
// It's a textnode.
NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
"Data node that's not content?");
mFirst = startCon;
mLast = startCon;
mCurNode = startCon;
mFirst = NS_STATIC_CAST(nsIContent*, startNode);
mLast = mFirst;
mCurNode = mFirst;
RebuildIndexStack();
return NS_OK;
@ -434,11 +428,13 @@ nsContentIterator::Init(nsIDOMRange* aRange)
nsIContent *cChild = nsnull;
if (!startIsData && ContentHasChildren(startCon))
cChild = startCon->GetChildAt(startIndx);
if (!startIsData && NodeHasChildren(startNode))
cChild = startNode->GetChildAt(startIndx);
if (!cChild) // no children, must be a text node
{
// XXXbz no children might also just mean no children. So I'm not
// sure what that comment above is talking about.
if (mPre)
{
// XXX: In the future, if start offset is after the last
@ -447,20 +443,34 @@ nsContentIterator::Init(nsIDOMRange* aRange)
if (!startIsData)
{
mFirst = GetNextSibling(startCon, nsnull);
mFirst = GetNextSibling(startNode, nsnull);
// Does mFirst node really intersect the range?
// The range could be 'degenerate', ie not collapsed
// but still contain no content.
if (mFirst && !ContentIsInTraversalRange(mFirst, mPre, startCon, startIndx, endCon, endIndx))
if (mFirst &&
!ContentIsInTraversalRange(mFirst, mPre, startNode, startIndx,
endNode, endIndx)) {
mFirst = nsnull;
}
}
else {
NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
"Data node that's not content?");
mFirst = NS_STATIC_CAST(nsIContent*, startNode);
}
}
else {
// post-order
if (startNode->IsNodeOfType(nsINode::eCONTENT)) {
mFirst = NS_STATIC_CAST(nsIContent*, startNode);
} else {
// What else can we do?
mFirst = nsnull;
}
else
mFirst = startCon;
}
else // post-order
mFirst = startCon;
}
else
{
@ -474,7 +484,9 @@ nsContentIterator::Init(nsIDOMRange* aRange)
// The range could be 'degenerate', ie not collapsed
// but still contain no content.
if (mFirst && !ContentIsInTraversalRange(mFirst, mPre, startCon, startIndx, endCon, endIndx))
if (mFirst &&
!ContentIsInTraversalRange(mFirst, mPre, startNode, startIndx,
endNode, endIndx))
mFirst = nsnull;
}
}
@ -482,12 +494,18 @@ nsContentIterator::Init(nsIDOMRange* aRange)
// Find last node in range.
PRBool endIsData = endCon->IsNodeOfType(nsINode::eDATA_NODE);
PRBool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);
if (endIsData || !ContentHasChildren(endCon) || endIndx == 0)
if (endIsData || !NodeHasChildren(endNode) || endIndx == 0)
{
if (mPre)
mLast = endCon;
if (mPre) {
if (endNode->IsNodeOfType(nsINode::eCONTENT)) {
mLast = NS_STATIC_CAST(nsIContent*, endNode);
} else {
// Not much else to do here...
mLast = nsnull;
}
}
else // post-order
{
// XXX: In the future, if end offset is before the first
@ -496,20 +514,25 @@ nsContentIterator::Init(nsIDOMRange* aRange)
if (!endIsData)
{
mLast = GetPrevSibling(endCon, nsnull);
mLast = GetPrevSibling(endNode, nsnull);
if (!ContentIsInTraversalRange(mLast, mPre, startCon, startIndx, endCon, endIndx))
if (!ContentIsInTraversalRange(mLast, mPre, startNode, startIndx,
endNode, endIndx))
mLast = nsnull;
}
else
mLast = endCon;
else {
NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT),
"Data node that's not content?");
mLast = NS_STATIC_CAST(nsIContent*, endNode);
}
}
}
else
{
PRInt32 indx = endIndx;
cChild = endCon->GetChildAt(--indx);
cChild = endNode->GetChildAt(--indx);
if (!cChild) // No child at offset!
{
@ -521,11 +544,14 @@ nsContentIterator::Init(nsIDOMRange* aRange)
{
mLast = GetDeepLastChild(cChild, nsnull);
if (!ContentIsInTraversalRange(mLast, mPre, startCon, startIndx, endCon, endIndx))
if (!ContentIsInTraversalRange(mLast, mPre, startNode, startIndx,
endNode, endIndx)) {
mLast = nsnull;
}
}
else // post-order
else { // post-order
mLast = cChild;
}
}
// If either first or last is null, they both
@ -648,13 +674,13 @@ nsContentIterator::GetDeepLastChild(nsIContent *aRoot, nsVoidArray *aIndexes)
// Get the next sibling, or parents next sibling, or grandpa's next sibling...
nsIContent *
nsContentIterator::GetNextSibling(nsIContent *aNode,
nsContentIterator::GetNextSibling(nsINode *aNode,
nsVoidArray *aIndexes)
{
if (!aNode)
return nsnull;
nsIContent *parent = aNode->GetParent();
nsINode *parent = aNode->GetNodeParent();
if (!parent)
return nsnull;
@ -712,13 +738,13 @@ nsContentIterator::GetNextSibling(nsIContent *aNode,
// Get the prev sibling, or parents prev sibling, or grandpa's prev sibling...
nsIContent *
nsContentIterator::GetPrevSibling(nsIContent *aNode,
nsContentIterator::GetPrevSibling(nsINode *aNode,
nsVoidArray *aIndexes)
{
if (!aNode)
return nsnull;
nsIContent *parent = aNode->GetParent();
nsINode *parent = aNode->GetNodeParent();
if (!parent)
return nsnull;
@ -774,7 +800,7 @@ nsContentIterator::NextNode(nsIContent *aNode, nsVoidArray *aIndexes)
if (mPre) // if we are a Pre-order iterator, use pre-order
{
// if it has children then next node is first child
if (ContentHasChildren(cN))
if (NodeHasChildren(cN))
{
nsIContent *cFirstChild = cN->GetChildAt(0);

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

@ -138,6 +138,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsIDOMUserDataHandler.h"
#include "nsIFragmentContentSink.h"
#include "nsContentCreatorFunctions.h"
#include "nsTPtrArray.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@ -1228,7 +1229,7 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1,
}
// Build the chain of parents
nsAutoVoidArray parents1, parents2;
nsAutoTPtrArray<nsINode, 30> parents1, parents2;
do {
parents1.AppendElement(aNode1);
aNode1 = aNode1->GetNodeParent();
@ -1239,13 +1240,13 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1,
} while (aNode2);
// Find where the parent chain differs
PRUint32 pos1 = parents1.Count();
PRUint32 pos2 = parents2.Count();
PRUint32 pos1 = parents1.Length();
PRUint32 pos2 = parents2.Length();
nsINode* parent = nsnull;
PRUint32 len;
for (len = PR_MIN(pos1, pos2); len > 0; --len) {
nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1));
nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2));
nsINode* child1 = parents1.ElementAt(--pos1);
nsINode* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
break;
}
@ -1265,7 +1266,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
return 0;
}
nsAutoVoidArray parents1, parents2;
nsAutoTPtrArray<nsINode, 30> parents1, parents2;
// Check if either node is an attribute
nsIAttribute* attr1 = nsnull;
@ -1276,7 +1277,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
// to the chain and walk up to the element
if (elem) {
aNode1 = elem;
parents1.AppendElement(attr1);
parents1.AppendElement(NS_STATIC_CAST(nsINode*, attr1));
}
}
if (aNode2->IsNodeOfType(nsINode::eATTRIBUTE)) {
@ -1306,7 +1307,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
if (elem) {
aNode2 = elem;
parents2.AppendElement(attr2);
parents2.AppendElement(NS_STATIC_CAST(nsINode*, attr2));
}
}
@ -1326,10 +1327,10 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
} while (aNode2);
// Check if the nodes are disconnected.
PRUint32 pos1 = parents1.Count();
PRUint32 pos2 = parents2.Count();
nsINode* top1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1));
nsINode* top2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2));
PRUint32 pos1 = parents1.Length();
PRUint32 pos2 = parents2.Length();
nsINode* top1 = parents1.ElementAt(--pos1);
nsINode* top2 = parents2.ElementAt(--pos2);
if (top1 != top2) {
return top1 < top2 ?
(nsIDOM3Node::DOCUMENT_POSITION_PRECEDING |
@ -1344,8 +1345,8 @@ nsContentUtils::ComparePosition(nsINode* aNode1,
nsINode* parent = top1;
PRUint32 len;
for (len = PR_MIN(pos1, pos2); len > 0; --len) {
nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1));
nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2));
nsINode* child1 = parents1.ElementAt(--pos1);
nsINode* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
// child1 or child2 can be an attribute here. This will work fine since
// IndexOf will return -1 for the attribute making the attribute be

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

@ -1653,14 +1653,11 @@ nsresult nsRange::ToString(nsAString& aReturn)
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
nsCOMPtr<nsIContent> cStart( do_QueryInterface(mStartParent) );
nsCOMPtr<nsIContent> cEnd( do_QueryInterface(mEndParent) );
// clear the string
aReturn.Truncate();
// If we're unpositioned, return the empty string
if (!cStart || !cEnd) {
if (!mIsPositioned) {
return NS_OK;
}
@ -1669,7 +1666,7 @@ nsresult nsRange::ToString(nsAString& aReturn)
#endif /* DEBUG */
// effeciency hack for simple case
if (cStart == cEnd)
if (mStartParent == mEndParent)
{
nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(mStartParent) );
@ -1689,13 +1686,14 @@ nsresult nsRange::ToString(nsAString& aReturn)
}
}
/* complex case: cStart != cEnd, or cStart not a text node
/* complex case: mStartParent != mEndParent, or mStartParent not a text node
revisit - there are potential optimizations here and also tradeoffs.
*/
nsCOMPtr<nsIContentIterator> iter;
NS_NewContentIterator(getter_AddRefs(iter));
iter->Init(this);
nsresult rv = iter->Init(this);
NS_ENSURE_SUCCESS(rv, rv);
nsString tempString;
@ -1712,14 +1710,14 @@ nsresult nsRange::ToString(nsAString& aReturn)
nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(cN) );
if (textNode) // if it's a text node, get the text
{
if (cN == cStart) // only include text past start offset
if (cN == mStartParent) // only include text past start offset
{
PRUint32 strLength;
textNode->GetLength(&strLength);
textNode->SubstringData(mStartOffset,strLength-mStartOffset,tempString);
aReturn += tempString;
}
else if (cN == cEnd) // only include text before end offset
else if (cN == mEndParent) // only include text before end offset
{
textNode->SubstringData(0,mEndOffset,tempString);
aReturn += tempString;