зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3c0294cc84
Коммит
f3a3af9cca
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче