Bug 896283 - Part c: Use nsINode in nsEditor::JoinNodesImpl; r=ehsan

This commit is contained in:
Ms2ger 2013-07-24 09:39:08 +02:00
parent 7ecb7f9c85
commit 971cd2e7d5
4 changed files with 135 additions and 126 deletions

View File

@ -67,18 +67,12 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg");
if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; }
nsCOMPtr<nsINode> leftNode = do_QueryInterface(mLeftNode);
NS_ENSURE_STATE(leftNode);
nsCOMPtr<nsINode> rightNode = do_QueryInterface(mRightNode);
NS_ENSURE_STATE(rightNode);
// get the parent node
nsCOMPtr<nsINode> leftParent = leftNode->GetParentNode();
nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
// verify that mLeftNode and mRightNode have the same parent
nsCOMPtr<nsINode> rightParent = rightNode->GetParentNode();
nsCOMPtr<nsINode> rightParent = mRightNode->GetParentNode();
NS_ENSURE_TRUE(rightParent, NS_ERROR_NULL_POINTER);
if (leftParent != rightParent) {
@ -89,11 +83,9 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
// set this instance mParent.
// Other methods will see a non-null mParent and know all is well
mParent = leftParent;
mOffset = leftNode->Length();
mOffset = mLeftNode->Length();
nsresult rv = mEditor->JoinNodesImpl(mRightNode->AsDOMNode(),
mLeftNode->AsDOMNode(),
mParent->AsDOMNode());
nsresult rv = mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
#ifdef DEBUG
if (NS_SUCCEEDED(rv) && gNoisy) {

View File

@ -129,9 +129,8 @@ NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
}
// this assumes Do inserted the new node in front of the prior existing node
nsresult result = mEditor->JoinNodesImpl(mExistingRightNode->AsDOMNode(),
mNewLeftNode->AsDOMNode(),
mParent->AsDOMNode());
nsresult rv = mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode,
mParent);
#ifdef DEBUG
if (gNoisy)
{
@ -140,7 +139,7 @@ NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
static_cast<void*>(mExistingRightNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
if (NS_SUCCEEDED(rv))
{
if (gNoisy)
{
@ -150,7 +149,7 @@ NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
}
#endif
return result;
return rv;
}
/* redo cannot simply resplit the right node, because subsequent transactions

View File

@ -2839,153 +2839,127 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
}
nsresult
nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep,
nsIDOMNode * aNodeToJoin,
nsIDOMNode * aParent)
nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
nsINode* aNodeToJoin,
nsINode* aParent)
{
MOZ_ASSERT(aNodeToKeep);
MOZ_ASSERT(aNodeToJoin);
MOZ_ASSERT(aParent);
// get selection
nsCOMPtr<nsISelection> selection;
GetSelection(getter_AddRefs(selection));
nsRefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// remember some selection points
nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
int32_t selStartOffset, selEndOffset, joinOffset, keepOffset;
nsCOMPtr<nsINode> selStartNode;
int32_t selStartOffset;
nsresult result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
if (NS_FAILED(result)) selStartNode = nullptr;
if (NS_FAILED(result)) {
selStartNode = nullptr;
}
nsCOMPtr<nsINode> selEndNode;
int32_t selEndOffset;
result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
// Joe or Kin should comment here on why the following line is not a copy/paste error
if (NS_FAILED(result)) selStartNode = nullptr;
if (NS_FAILED(result)) {
selStartNode = nullptr;
}
nsCOMPtr<nsIDOMNode> leftNode = aNodeToJoin;
uint32_t firstNodeLength = aNodeToJoin->Length();
uint32_t firstNodeLength;
result = GetLengthOfDOMNode(leftNode, firstNodeLength);
NS_ENSURE_SUCCESS(result, result);
nsCOMPtr<nsIDOMNode> parent = GetNodeLocation(aNodeToJoin, &joinOffset);
parent = GetNodeLocation(aNodeToKeep, &keepOffset);
int32_t joinOffset;
GetNodeLocation(aNodeToJoin, &joinOffset);
int32_t keepOffset;
nsINode* parent = GetNodeLocation(aNodeToKeep, &keepOffset);
// if selection endpoint is between the nodes, remember it as being
// in the one that is going away instead. This simplifies later selection
// adjustment logic at end of this method.
if (selStartNode)
{
if (selStartNode == parent)
{
if ((selStartOffset > joinOffset) && (selStartOffset <= keepOffset))
{
selStartNode = aNodeToJoin;
selStartOffset = firstNodeLength;
}
if (selStartNode) {
if (selStartNode == parent &&
joinOffset < selStartOffset && selStartOffset <= keepOffset) {
selStartNode = aNodeToJoin;
selStartOffset = firstNodeLength;
}
if (selEndNode == parent)
{
if ((selEndOffset > joinOffset) && (selEndOffset <= keepOffset))
{
selEndNode = aNodeToJoin;
selEndOffset = firstNodeLength;
}
if (selEndNode == parent &&
joinOffset < selEndOffset && selEndOffset <= keepOffset) {
selEndNode = aNodeToJoin;
selEndOffset = firstNodeLength;
}
}
// ok, ready to do join now.
// if it's a text node, just shuffle around some text
nsCOMPtr<nsIDOMCharacterData> keepNodeAsText( do_QueryInterface(aNodeToKeep) );
nsCOMPtr<nsIDOMCharacterData> joinNodeAsText( do_QueryInterface(aNodeToJoin) );
if (keepNodeAsText && joinNodeAsText)
{
if (keepNodeAsText && joinNodeAsText) {
nsAutoString rightText;
nsAutoString leftText;
keepNodeAsText->GetData(rightText);
joinNodeAsText->GetData(leftText);
leftText += rightText;
keepNodeAsText->SetData(leftText);
}
else
{ // otherwise it's an interior node, so shuffle around the children
nsCOMPtr<nsIDOMNodeList> childNodes;
result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes));
NS_ENSURE_TRUE(childNodes, NS_ERROR_NULL_POINTER);
NS_ENSURE_SUCCESS(result, result);
} else {
// otherwise it's an interior node, so shuffle around the children
nsCOMPtr<nsINodeList> childNodes = aNodeToJoin->ChildNodes();
MOZ_ASSERT(childNodes);
int32_t i; // must be signed int!
uint32_t childCount=0;
nsCOMPtr<nsIDOMNode> firstNode;
childNodes->GetLength(&childCount);
// remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
result = aNodeToKeep->GetFirstChild(getter_AddRefs(firstNode));
NS_ENSURE_SUCCESS(result, result);
// GetFirstChild returns nullptr firstNode if aNodeToKeep has no children, that's ok.
nsCOMPtr<nsIDOMNode> resultNode;
// have to go through the list backwards to keep deletes from interfering with iteration
nsCOMPtr<nsIDOMNode> previousChild;
for (i = childCount - 1; i >= 0; i--)
{
nsCOMPtr<nsIDOMNode> childNode;
result = childNodes->Item(i, getter_AddRefs(childNode));
NS_ENSURE_SUCCESS(result, result);
nsCOMPtr<nsIContent> firstNode = aNodeToKeep->GetFirstChild();
// have to go through the list backwards to keep deletes from interfering with iteration
for (uint32_t i = childNodes->Length(); i > 0; --i) {
nsCOMPtr<nsIContent> childNode = childNodes->Item(i - 1);
if (childNode) {
// prepend children of aNodeToJoin
result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode));
NS_ENSURE_SUCCESS(result, result);
firstNode = do_QueryInterface(childNode);
ErrorResult err;
aNodeToKeep->InsertBefore(*childNode, firstNode, err);
NS_ENSURE_SUCCESS(err.ErrorCode(), err.ErrorCode());
firstNode = childNode.forget();
}
}
}
// delete the extra node
nsCOMPtr<nsIDOMNode> resultNode;
result = aParent->RemoveChild(aNodeToJoin, getter_AddRefs(resultNode));
ErrorResult err;
aParent->RemoveChild(*aNodeToJoin, err);
if (GetShouldTxnSetSelection())
{
if (GetShouldTxnSetSelection()) {
// editor wants us to set selection at join point
selection->Collapse(aNodeToKeep, firstNodeLength);
}
else if (selStartNode)
{
selection->Collapse(aNodeToKeep, SafeCast<int32_t>(firstNodeLength));
} else if (selStartNode) {
// and adjust the selection if needed
// HACK: this is overly simplified - multi-range selections need more work than this
bool bNeedToAdjust = false;
// check to see if we joined nodes where selection starts
if (selStartNode.get() == aNodeToJoin)
{
if (selStartNode == aNodeToJoin) {
bNeedToAdjust = true;
selStartNode = aNodeToKeep;
}
else if (selStartNode.get() == aNodeToKeep)
{
} else if (selStartNode == aNodeToKeep) {
bNeedToAdjust = true;
selStartOffset += firstNodeLength;
}
// check to see if we joined nodes where selection ends
if (selEndNode.get() == aNodeToJoin)
{
if (selEndNode == aNodeToJoin) {
bNeedToAdjust = true;
selEndNode = aNodeToKeep;
}
else if (selEndNode.get() == aNodeToKeep)
{
} else if (selEndNode == aNodeToKeep) {
bNeedToAdjust = true;
selEndOffset += firstNodeLength;
}
// adjust selection if needed
if (bNeedToAdjust)
{
selection->Collapse(selStartNode,selStartOffset);
selection->Extend(selEndNode,selEndOffset);
if (bNeedToAdjust) {
selection->Collapse(selStartNode, selStartOffset);
selection->Extend(selEndNode, selEndOffset);
}
}
return result;
return err.ErrorCode();
}
@ -3802,21 +3776,40 @@ nsEditor::GetStartNodeAndOffset(nsISelection *aSelection,
{
NS_ENSURE_TRUE(outStartNode && outStartOffset && aSelection, NS_ERROR_NULL_POINTER);
*outStartNode = nullptr;
*outStartOffset = 0;
nsCOMPtr<nsINode> startNode;
nsresult rv = GetStartNodeAndOffset(static_cast<Selection*>(aSelection),
getter_AddRefs(startNode),
outStartOffset);
NS_ENSURE_SUCCESS(rv, rv);
Selection* selection = static_cast<Selection*>(aSelection);
NS_ENSURE_TRUE(selection->GetRangeCount(), NS_ERROR_FAILURE);
if (startNode) {
NS_ADDREF(*outStartNode = startNode->AsDOMNode());
} else {
*outStartNode = nullptr;
}
return NS_OK;
}
nsRange* range = selection->GetRangeAt(0);
nsresult
nsEditor::GetStartNodeAndOffset(Selection* aSelection, nsINode** aStartNode,
int32_t* aStartOffset)
{
MOZ_ASSERT(aSelection);
MOZ_ASSERT(aStartNode);
MOZ_ASSERT(aStartOffset);
*aStartNode = nullptr;
*aStartOffset = 0;
NS_ENSURE_TRUE(aSelection->GetRangeCount(), NS_ERROR_FAILURE);
const nsRange* range = aSelection->GetRangeAt(0);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
nsresult result = range->GetStartContainer(outStartNode);
NS_ENSURE_SUCCESS(result, result);
result = range->GetStartOffset(outStartOffset);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_TRUE(range->IsPositioned(), NS_ERROR_FAILURE);
NS_IF_ADDREF(*aStartNode = range->GetStartParent());
*aStartOffset = range->StartOffset();
return NS_OK;
}
@ -3829,23 +3822,42 @@ nsEditor::GetEndNodeAndOffset(nsISelection *aSelection,
nsIDOMNode **outEndNode,
int32_t *outEndOffset)
{
NS_ENSURE_TRUE(outEndNode && outEndOffset, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(outEndNode && outEndOffset && aSelection, NS_ERROR_NULL_POINTER);
*outEndNode = nullptr;
Selection* selection = static_cast<Selection*>(aSelection);
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(selection->GetRangeCount(), NS_ERROR_FAILURE);
nsCOMPtr<nsINode> endNode;
nsresult rv = GetEndNodeAndOffset(static_cast<Selection*>(aSelection),
getter_AddRefs(endNode),
outEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsRange* range = selection->GetRangeAt(0);
if (endNode) {
NS_ADDREF(*outEndNode = endNode->AsDOMNode());
} else {
*outEndNode = nullptr;
}
return NS_OK;
}
nsresult
nsEditor::GetEndNodeAndOffset(Selection* aSelection, nsINode** aEndNode,
int32_t* aEndOffset)
{
MOZ_ASSERT(aSelection);
MOZ_ASSERT(aEndNode);
MOZ_ASSERT(aEndOffset);
*aEndNode = nullptr;
*aEndOffset = 0;
NS_ENSURE_TRUE(aSelection->GetRangeCount(), NS_ERROR_FAILURE);
const nsRange* range = aSelection->GetRangeAt(0);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
if (NS_FAILED(range->GetEndContainer(outEndNode)))
return NS_ERROR_FAILURE;
if (NS_FAILED(range->GetEndOffset(outEndOffset)))
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(range->IsPositioned(), NS_ERROR_FAILURE);
NS_IF_ADDREF(*aEndNode = range->GetEndParent());
*aEndOffset = range->EndOffset();
return NS_OK;
}

View File

@ -451,9 +451,9 @@ public:
* There is no requirement that the two nodes be of the same type.
* @param aParent The parent of aNodeToKeep
*/
nsresult JoinNodesImpl(nsIDOMNode *aNodeToKeep,
nsIDOMNode *aNodeToJoin,
nsIDOMNode *aParent);
nsresult JoinNodesImpl(nsINode* aNodeToKeep,
nsINode* aNodeToJoin,
nsINode* aParent);
/**
* Return the offset of aChild in aParent. Asserts fatally if parent or
@ -611,7 +611,13 @@ public:
static nsCOMPtr<nsIDOMNode> GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset);
static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outStartNode, int32_t *outStartOffset);
static nsresult GetStartNodeAndOffset(mozilla::Selection* aSelection,
nsINode** aStartNode,
int32_t* aStartOffset);
static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outEndNode, int32_t *outEndOffset);
static nsresult GetEndNodeAndOffset(mozilla::Selection* aSelection,
nsINode** aEndNode,
int32_t* aEndOffset);
#if DEBUG_JOE
static void DumpNode(nsIDOMNode *aNode, int32_t indent=0);
#endif