diff --git a/editor/libeditor/nsEditorUtils.cpp b/editor/libeditor/nsEditorUtils.cpp index ee894a4191d..b7f37f578ff 100644 --- a/editor/libeditor/nsEditorUtils.cpp +++ b/editor/libeditor/nsEditorUtils.cpp @@ -95,6 +95,23 @@ nsDOMIterator::Init(nsIDOMNode* aNode) return mIter->Init(content); } +nsresult +nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor, + nsTArray>& arrayOfNodes) const +{ + // Iterate through dom and build list + while (!mIter->IsDone()) { + nsCOMPtr node = mIter->GetCurrentNode(); + NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); + + if (functor(node)) { + arrayOfNodes.AppendElement(node); + } + mIter->Next(); + } + return NS_OK; +} + nsresult nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor, nsCOMArray& arrayOfNodes) const diff --git a/editor/libeditor/nsEditorUtils.h b/editor/libeditor/nsEditorUtils.h index 65f919dfc1e..868572d9232 100644 --- a/editor/libeditor/nsEditorUtils.h +++ b/editor/libeditor/nsEditorUtils.h @@ -168,6 +168,10 @@ class nsBoolDomIterFunctor { public: virtual bool operator()(nsIDOMNode* aNode)=0; + bool operator()(nsINode* aNode) + { + return operator()(GetAsDOMNode(aNode)); + } }; class MOZ_STACK_CLASS nsDOMIterator @@ -178,6 +182,8 @@ class MOZ_STACK_CLASS nsDOMIterator nsresult Init(nsRange* aRange); nsresult Init(nsIDOMNode* aNode); + nsresult AppendList(nsBoolDomIterFunctor& functor, + nsTArray>& arrayOfNodes) const; nsresult AppendList(nsBoolDomIterFunctor& functor, nsCOMArray& arrayOfNodes) const; protected: diff --git a/editor/libeditor/nsHTMLEditRules.cpp b/editor/libeditor/nsHTMLEditRules.cpp index 3d3be2569ad..c2920ca6461 100644 --- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -1882,35 +1882,23 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, MOZ_ASSERT(aStripWrappers == nsIEditor::eStrip || aStripWrappers == nsIEditor::eNoStrip); - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - // initialize out param + if (!aSelection || !aCancel || !aHandled) { + return NS_ERROR_NULL_POINTER; + } + // Initialize out params *aCancel = false; *aHandled = false; - // remember that we did a selection deletion. Used by CreateStyleForInsertText() + // Remember that we did a selection deletion. Used by CreateStyleForInsertText() mDidDeleteSelection = true; - - // if there is only bogus content, cancel the operation - if (mBogusNode) - { + + // If there is only bogus content, cancel the operation + if (mBogusNode) { *aCancel = true; return NS_OK; } - bool bCollapsed = aSelection->Collapsed(), join = false; - - // origCollapsed is used later to determine whether we should join - // blocks. We don't really care about bCollapsed because it will be - // modified by ExtendSelectionForDelete later. JoinBlocks should - // happen if the original selection is collapsed and the cursor is - // at the end of a block element, in which case ExtendSelectionForDelete - // would always make the selection not collapsed. - bool origCollapsed = bCollapsed; - nsCOMPtr startNode, selNode; - int32_t startOffset, selOffset; - - // first check for table selection mode. If so, - // hand off to table editor. + // First check for table selection mode. If so, hand off to table editor. nsCOMPtr cell; NS_ENSURE_STATE(mHTMLEditor); nsresult res = mHTMLEditor->GetFirstSelectedCell(nullptr, getter_AddRefs(cell)); @@ -1922,91 +1910,110 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, } cell = nullptr; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset); - NS_ENSURE_SUCCESS(res, res); + // origCollapsed is used later to determine whether we should join blocks. We + // don't really care about bCollapsed because it will be modified by + // ExtendSelectionForDelete later. JoinBlocks should happen if the original + // selection is collapsed and the cursor is at the end of a block element, in + // which case ExtendSelectionForDelete would always make the selection not + // collapsed. + bool bCollapsed = aSelection->Collapsed(); + bool join = false; + bool origCollapsed = bCollapsed; + + nsCOMPtr selNode; + int32_t selOffset; + + NS_ENSURE_STATE(aSelection->GetRangeAt(0)); + nsCOMPtr startNode = aSelection->GetRangeAt(0)->GetStartParent(); + int32_t startOffset = aSelection->GetRangeAt(0)->StartOffset(); NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); - if (bCollapsed) - { - // if we are inside an empty block, delete it. + + if (bCollapsed) { + // If we are inside an empty block, delete it. NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr host = mHTMLEditor->GetActiveEditingHost(); NS_ENSURE_TRUE(host, NS_ERROR_FAILURE); - nsCOMPtr startNode_ = do_QueryInterface(startNode); - NS_ENSURE_STATE(startNode_ || !startNode); - res = CheckForEmptyBlock(startNode_, host, aSelection, aHandled); + res = CheckForEmptyBlock(startNode, host, aSelection, aHandled); NS_ENSURE_SUCCESS(res, res); - if (*aHandled) return NS_OK; + if (*aHandled) { + return NS_OK; + } // Test for distance between caret and text that will be deleted - res = CheckBidiLevelForDeletion(aSelection, startNode, startOffset, aAction, aCancel); + res = CheckBidiLevelForDeletion(aSelection, GetAsDOMNode(startNode), + startOffset, aAction, aCancel); NS_ENSURE_SUCCESS(res, res); - if (*aCancel) return NS_OK; + if (*aCancel) { + return NS_OK; + } NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->ExtendSelectionForDelete(aSelection, &aAction); NS_ENSURE_SUCCESS(res, res); // We should delete nothing. - if (aAction == nsIEditor::eNone) + if (aAction == nsIEditor::eNone) { return NS_OK; + } // ExtendSelectionForDelete() may have changed the selection, update it - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_STATE(aSelection->GetRangeAt(0)); + startNode = aSelection->GetRangeAt(0)->GetStartParent(); + startOffset = aSelection->GetRangeAt(0)->StartOffset(); NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); - + bCollapsed = aSelection->Collapsed(); } - if (bCollapsed) - { - // what's in the direction we are deleting? + if (bCollapsed) { + // What's in the direction we are deleting? NS_ENSURE_STATE(mHTMLEditor); nsWSRunObject wsObj(mHTMLEditor, startNode, startOffset); - nsCOMPtr visNode_; + nsCOMPtr visNode; int32_t visOffset; WSType wsType; - // find next visible node - nsCOMPtr startNode_(do_QueryInterface(startNode)); - if (aAction == nsIEditor::eNext) - wsObj.NextVisibleNode(startNode_, startOffset, address_of(visNode_), + // Find next visible node + if (aAction == nsIEditor::eNext) { + wsObj.NextVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType); - else - wsObj.PriorVisibleNode(startNode_, startOffset, address_of(visNode_), + } else { + wsObj.PriorVisibleNode(startNode, startOffset, address_of(visNode), &visOffset, &wsType); - - if (!visNode_) // can't find anything to delete! - { + } + + if (!visNode) { + // Can't find anything to delete! *aCancel = true; return res; } - - nsCOMPtr visNode(GetAsDOMNode(visNode_)); + if (wsType == WSType::normalWS) { - // we found some visible ws to delete. Let ws code handle it. - if (aAction == nsIEditor::eNext) + // We found some visible ws to delete. Let ws code handle it. + if (aAction == nsIEditor::eNext) { res = wsObj.DeleteWSForward(); - else + } else { res = wsObj.DeleteWSBackward(); + } *aHandled = true; NS_ENSURE_SUCCESS(res, res); res = InsertBRIfNeeded(aSelection); return res; - } else if (wsType == WSType::text) { - // found normal text to delete. - nsRefPtr nodeAsText = visNode_->GetAsText(); + } + + if (wsType == WSType::text) { + // Found normal text to delete. + nsRefPtr nodeAsText = visNode->GetAsText(); int32_t so = visOffset; - int32_t eo = visOffset+1; - if (aAction == nsIEditor::ePrevious) - { - if (so == 0) return NS_ERROR_UNEXPECTED; + int32_t eo = visOffset + 1; + if (aAction == nsIEditor::ePrevious) { + if (so == 0) { + return NS_ERROR_UNEXPECTED; + } so--; eo--; - // bug 1068979: delete both codepoints if surrogate pair + // Bug 1068979: delete both codepoints if surrogate pair if (so > 0) { const nsTextFragment *text = nodeAsText->GetText(); if (NS_IS_LOW_SURROGATE(text->CharAt(so)) && @@ -2014,15 +2021,13 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, so--; } } - } - else - { + } else { nsRefPtr range = aSelection->GetRangeAt(0); NS_ENSURE_STATE(range); - NS_ASSERTION(GetAsDOMNode(range->GetStartParent()) == visNode, + NS_ASSERTION(range->GetStartParent() == visNode, "selection start not in visNode"); - NS_ASSERTION(GetAsDOMNode(range->GetEndParent()) == visNode, + NS_ASSERTION(range->GetEndParent() == visNode, "selection end not in visNode"); so = range->StartOffset(); @@ -2030,87 +2035,81 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, } NS_ENSURE_STATE(mHTMLEditor); res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, - address_of(visNode_), &so, address_of(visNode_), &eo); + address_of(visNode), &so, address_of(visNode), &eo); NS_ENSURE_SUCCESS(res, res); - visNode = GetAsDOMNode(visNode_); NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteText(*nodeAsText, std::min(so, eo), DeprecatedAbs(eo - so)); *aHandled = true; - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_SUCCESS(res, res); res = InsertBRIfNeeded(aSelection); - return res; - } else if (wsType == WSType::special || wsType == WSType::br || - nsHTMLEditUtils::IsHR(visNode)) { - // short circuit for invisible breaks. delete them and recurse. - if (nsTextEditUtils::IsBreak(visNode) && - (!mHTMLEditor || !mHTMLEditor->IsVisBreak(visNode))) - { + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; + } + + if (wsType == WSType::special || wsType == WSType::br || + visNode->Tag() == nsGkAtoms::hr) { + // Short circuit for invisible breaks. delete them and recurse. + if (visNode->Tag() == nsGkAtoms::br && + (!mHTMLEditor || !mHTMLEditor->IsVisBreak(visNode))) { NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(visNode); NS_ENSURE_SUCCESS(res, res); return WillDeleteSelection(aSelection, aAction, aStripWrappers, aCancel, aHandled); } - - // special handling for backspace when positioned after
- if (aAction == nsIEditor::ePrevious && nsHTMLEditUtils::IsHR(visNode)) - { - /* - Only if the caret is positioned at the end-of-hr-line position, - we want to delete the
. - - In other words, we only want to delete, if - our selection position (indicated by startNode and startOffset) - is the position directly after the
, - on the same line as the
. - - To detect this case we check: - startNode == parentOfVisNode - and - startOffset -1 == visNodeOffsetToVisNodeParent - and - interline position is false (left) - - In any other case we set the position to - startnode -1 and interlineposition to false, - only moving the caret to the end-of-hr-line position. - */ + // Special handling for backspace when positioned after
+ if (aAction == nsIEditor::ePrevious && visNode->Tag() == nsGkAtoms::hr) { + // Only if the caret is positioned at the end-of-hr-line position, we + // want to delete the
. + // + // In other words, we only want to delete, if our selection position + // (indicated by startNode and startOffset) is the position directly + // after the
, on the same line as the
. + // + // To detect this case we check: + // startNode == parentOfVisNode + // and + // startOffset -1 == visNodeOffsetToVisNodeParent + // and + // interline position is false (left) + // + // In any other case we set the position to startnode -1 and + // interlineposition to false, only moving the caret to the + // end-of-hr-line position. bool moveOnly = true; - selNode = nsEditor::GetNodeLocation(visNode, &selOffset); + selNode = visNode->GetParentNode(); + selOffset = selNode ? selNode->IndexOf(visNode) : -1; bool interLineIsRight; res = aSelection->GetInterlinePosition(&interLineIsRight); NS_ENSURE_SUCCESS(res, res); - if (startNode == selNode && - startOffset -1 == selOffset && - !interLineIsRight) - { + if (startNode == selNode && startOffset - 1 == selOffset && + !interLineIsRight) { moveOnly = false; } - - if (moveOnly) - { + + if (moveOnly) { // Go to the position after the
, but to the end of the
line // by setting the interline position to left. ++selOffset; - res = aSelection->Collapse(selNode, selOffset); + aSelection->Collapse(selNode, selOffset); aSelection->SetInterlinePosition(false); mDidExplicitlySetInterline = true; *aHandled = true; - // There is one exception to the move only case. - // If the
is followed by a
we want to delete the
. + // There is one exception to the move only case. If the
is + // followed by a
we want to delete the
. WSType otherWSType; nsCOMPtr otherNode; int32_t otherOffset; - nsCOMPtr startNode_(do_QueryInterface(startNode)); - wsObj.NextVisibleNode(startNode_, startOffset, address_of(otherNode), + wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); if (otherWSType == WSType::br) { @@ -2127,361 +2126,321 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, return NS_OK; } - // else continue with normal delete code + // Else continue with normal delete code } - // found break or image, or hr. + // Found break or image, or hr. NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr visContent(do_QueryInterface(visNode)); - res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, visContent); + NS_ENSURE_STATE(visNode->IsContent()); + res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, + visNode->AsContent()); NS_ENSURE_SUCCESS(res, res); - // remember sibling to visnode, if any - nsCOMPtr sibling, stepbrother; + // Remember sibling to visnode, if any NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLSibling(visNode, address_of(sibling)); - // delete the node, and join like nodes if appropriate + nsCOMPtr sibling = mHTMLEditor->GetPriorHTMLSibling(visNode); + // Delete the node, and join like nodes if appropriate NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(visNode); NS_ENSURE_SUCCESS(res, res); - // we did something, so lets say so. + // We did something, so let's say so. *aHandled = true; - // is there a prior node and are they siblings? + // Is there a prior node and are they siblings? + nsCOMPtr stepbrother; if (sibling) { NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetNextHTMLSibling(sibling, address_of(stepbrother)); + stepbrother = mHTMLEditor->GetNextHTMLSibling(sibling); } - if (startNode == stepbrother) - { - // are they both text nodes? - NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->IsTextNode(startNode) && - (!mHTMLEditor || mHTMLEditor->IsTextNode(sibling))) - { - NS_ENSURE_STATE(mHTMLEditor); - // if so, join them! - nsCOMPtr sibling_ = do_QueryInterface(sibling); - NS_ENSURE_STATE(sibling_); - nsCOMPtr startNode_ = do_QueryInterface(startNode); - NS_ENSURE_STATE(startNode_); - ::DOMPoint pt = JoinNodesSmart(*sibling_, *startNode_); - NS_ENSURE_STATE(pt.node); - // fix up selection - res = aSelection->Collapse(pt.node, pt.offset); - } + // Are they both text nodes? If so, join them! + if (startNode == stepbrother && startNode->GetAsText() && + sibling->GetAsText()) { + ::DOMPoint pt = JoinNodesSmart(*sibling, *startNode->AsContent()); + NS_ENSURE_STATE(pt.node); + // Fix up selection + res = aSelection->Collapse(pt.node, pt.offset); + NS_ENSURE_SUCCESS(res, res); } - NS_ENSURE_SUCCESS(res, res); res = InsertBRIfNeeded(aSelection); - return res; - } else if (wsType == WSType::otherBlock) { - // make sure it's not a table element. If so, cancel the operation + NS_ENSURE_SUCCESS(res, res); + return NS_OK; + } + + if (wsType == WSType::otherBlock) { + // Make sure it's not a table element. If so, cancel the operation // (translation: users cannot backspace or delete across table cells) - if (nsHTMLEditUtils::IsTableElement(visNode)) - { + if (nsHTMLEditUtils::IsTableElement(visNode)) { *aCancel = true; return NS_OK; } - - // next to a block. See if we are between a block and a br. If so, we really - // want to delete the br. Else join content at selection to the block. - + + // Next to a block. See if we are between a block and a br. If so, we + // really want to delete the br. Else join content at selection to the + // block. bool bDeletedBR = false; WSType otherWSType; nsCOMPtr otherNode; int32_t otherOffset; - - // find node in other direction - nsCOMPtr startNode_(do_QueryInterface(startNode)); - if (aAction == nsIEditor::eNext) - wsObj.PriorVisibleNode(startNode_, startOffset, address_of(otherNode), + + // Find node in other direction + if (aAction == nsIEditor::eNext) { + wsObj.PriorVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); - else - wsObj.NextVisibleNode(startNode_, startOffset, address_of(otherNode), + } else { + wsObj.NextVisibleNode(startNode, startOffset, address_of(otherNode), &otherOffset, &otherWSType); - - // first find the adjacent node in the block - nsCOMPtr leafNode, leftNode, rightNode; - if (aAction == nsIEditor::ePrevious) - { + } + + // First find the adjacent node in the block + nsCOMPtr leafNode; + nsCOMPtr leftNode, rightNode; + if (aAction == nsIEditor::ePrevious) { NS_ENSURE_STATE(mHTMLEditor); - leafNode = GetAsDOMNode(mHTMLEditor->GetLastEditableLeaf(*visNode_)); + leafNode = mHTMLEditor->GetLastEditableLeaf(*visNode); leftNode = leafNode; rightNode = startNode; - } - else - { + } else { NS_ENSURE_STATE(mHTMLEditor); - leafNode = GetAsDOMNode(mHTMLEditor->GetFirstEditableLeaf(*visNode_)); + leafNode = mHTMLEditor->GetFirstEditableLeaf(*visNode); leftNode = startNode; rightNode = leafNode; } - - if (nsTextEditUtils::IsBreak(otherNode)) - { + + if (otherNode->Tag() == nsGkAtoms::br) { NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(otherNode); NS_ENSURE_SUCCESS(res, res); *aHandled = true; bDeletedBR = true; } - - // don't cross table boundaries - if (leftNode && rightNode && InDifferentTableElements(leftNode, rightNode)) { + + // Don't cross table boundaries + if (leftNode && rightNode && + InDifferentTableElements(leftNode, rightNode)) { return NS_OK; } - - if (bDeletedBR) - { - // put selection at edge of block and we are done. - nsCOMPtr leafNode_ = do_QueryInterface(leafNode); - NS_ENSURE_STATE(leafNode_ || !leafNode); - ::DOMPoint newSel = GetGoodSelPointForNode(*leafNode_, aAction); + + if (bDeletedBR) { + // Put selection at edge of block and we are done. + ::DOMPoint newSel = GetGoodSelPointForNode(*leafNode, aAction); NS_ENSURE_STATE(newSel.node); aSelection->Collapse(newSel.node, newSel.offset); return NS_OK; } - - // else we are joining content to block - nsCOMPtr selPointNode = startNode; + // Else we are joining content to block + + nsCOMPtr selPointNode = startNode; int32_t selPointOffset = startOffset; { NS_ENSURE_STATE(mHTMLEditor); - nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset); - res = JoinBlocks(leftNode, rightNode, aCancel); + nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, + address_of(selPointNode), &selPointOffset); + res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode), + aCancel); *aHandled = true; NS_ENSURE_SUCCESS(res, res); } aSelection->Collapse(selPointNode, selPointOffset); - return res; - } else if (wsType == WSType::thisBlock) { - // at edge of our block. Look beside it and see if we can join to an adjacent block - - // make sure it's not a table element. If so, cancel the operation + return NS_OK; + } + + if (wsType == WSType::thisBlock) { + // At edge of our block. Look beside it and see if we can join to an + // adjacent block + + // Make sure it's not a table element. If so, cancel the operation // (translation: users cannot backspace or delete across table cells) - if (nsHTMLEditUtils::IsTableElement(visNode)) - { + if (nsHTMLEditUtils::IsTableElement(visNode)) { *aCancel = true; return NS_OK; } - - // first find the relavent nodes - nsCOMPtr leftNode, rightNode; - if (aAction == nsIEditor::ePrevious) - { + + // First find the relevant nodes + nsCOMPtr leftNode, rightNode; + if (aAction == nsIEditor::ePrevious) { NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetPriorHTMLNode(visNode, address_of(leftNode)); - NS_ENSURE_SUCCESS(res, res); + leftNode = mHTMLEditor->GetPriorHTMLNode(visNode); rightNode = startNode; - } - else - { + } else { NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLNode( visNode, address_of(rightNode)); - NS_ENSURE_SUCCESS(res, res); + rightNode = mHTMLEditor->GetNextHTMLNode(visNode); leftNode = startNode; } - // nothing to join - if (!leftNode || !rightNode) - { + // Nothing to join + if (!leftNode || !rightNode) { *aCancel = true; return NS_OK; } - // don't cross table boundaries -- cancel it + // Don't cross table boundaries -- cancel it if (InDifferentTableElements(leftNode, rightNode)) { *aCancel = true; return NS_OK; } - nsCOMPtr selPointNode = startNode; + nsCOMPtr selPointNode = startNode; int32_t selPointOffset = startOffset; { NS_ENSURE_STATE(mHTMLEditor); - nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset); - res = JoinBlocks(leftNode, rightNode, aCancel); + nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, + address_of(selPointNode), &selPointOffset); + res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode), + aCancel); *aHandled = true; NS_ENSURE_SUCCESS(res, res); } aSelection->Collapse(selPointNode, selPointOffset); - return res; + return NS_OK; } } - - // else we have a non collapsed selection - // first adjust the selection + + // Else we have a non-collapsed selection. First adjust the selection. res = ExpandSelectionForDeletion(aSelection); NS_ENSURE_SUCCESS(res, res); - - // remember that we did a ranged delete for the benefit of AfterEditInner(). + + // Remember that we did a ranged delete for the benefit of AfterEditInner(). mDidRangedDelete = true; - - // refresh start and end points - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), &startOffset); - NS_ENSURE_SUCCESS(res, res); + + // Refresh start and end points + NS_ENSURE_STATE(aSelection->GetRangeAt(0)); + startNode = aSelection->GetRangeAt(0)->GetStartParent(); + startOffset = aSelection->GetRangeAt(0)->StartOffset(); NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE); - nsCOMPtr endNode; - int32_t endOffset; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetEndNodeAndOffset(aSelection, getter_AddRefs(endNode), &endOffset); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr endNode = aSelection->GetRangeAt(0)->GetEndParent(); + int32_t endOffset = aSelection->GetRangeAt(0)->EndOffset(); NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE); - // figure out if the endpoints are in nodes that can be merged - // adjust surrounding whitespace in preperation to delete selection - if (!IsPlaintextEditor()) - { + // Figure out if the endpoints are in nodes that can be merged. Adjust + // surrounding whitespace in preparation to delete selection. + if (!IsPlaintextEditor()) { NS_ENSURE_STATE(mHTMLEditor); nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); - nsCOMPtr startNode_(do_QueryInterface(startNode)), - endNode_(do_QueryInterface(endNode)); res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, - address_of(startNode_), &startOffset, - address_of(endNode_), &endOffset); - NS_ENSURE_SUCCESS(res, res); - startNode = GetAsDOMNode(startNode_); - endNode = GetAsDOMNode(endNode_); + address_of(startNode), &startOffset, + address_of(endNode), &endOffset); + NS_ENSURE_SUCCESS(res, res); } - + { - // track location of where we are deleting + // Track location of where we are deleting NS_ENSURE_STATE(mHTMLEditor); nsAutoTrackDOMPoint startTracker(mHTMLEditor->mRangeUpdater, address_of(startNode), &startOffset); nsAutoTrackDOMPoint endTracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset); - // we are handling all ranged deletions directly now. + // We are handling all ranged deletions directly now. *aHandled = true; - - if (endNode == startNode) - { + + if (endNode == startNode) { NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers); - NS_ENSURE_SUCCESS(res, res); - } - else - { - // figure out mailcite ancestors - nsCOMPtr startNode_ = do_QueryInterface(startNode); - NS_ENSURE_STATE(startNode_ || !startNode); - nsCOMPtr endNode_ = do_QueryInterface(endNode); - NS_ENSURE_STATE(endNode_ || !endNode); - nsCOMPtr endCiteNode, startCiteNode; - startCiteNode = GetAsDOMNode(GetTopEnclosingMailCite(*startNode_)); - endCiteNode = GetAsDOMNode(GetTopEnclosingMailCite(*endNode_)); - - // if we only have a mailcite at one of the two endpoints, set the directionality - // of the deletion so that the selection will end up outside the mailcite. - if (startCiteNode && !endCiteNode) - { + NS_ENSURE_SUCCESS(res, res); + } else { + // Figure out mailcite ancestors + nsCOMPtr startCiteNode = GetTopEnclosingMailCite(*startNode); + nsCOMPtr endCiteNode = GetTopEnclosingMailCite(*endNode); + + // If we only have a mailcite at one of the two endpoints, set the + // directionality of the deletion so that the selection will end up + // outside the mailcite. + if (startCiteNode && !endCiteNode) { aAction = nsIEditor::eNext; - } - else if (!startCiteNode && endCiteNode) - { + } else if (!startCiteNode && endCiteNode) { aAction = nsIEditor::ePrevious; } - - // figure out block parents - nsCOMPtr leftParent; - nsCOMPtr rightParent; - if (IsBlockNode(startNode)) - leftParent = startNode; - else { + + // Figure out block parents + nsCOMPtr leftParent; + if (IsBlockNode(GetAsDOMNode(startNode))) { + leftParent = startNode->AsElement(); + } else { NS_ENSURE_STATE(mHTMLEditor); leftParent = mHTMLEditor->GetBlockNodeParent(startNode); } - if (IsBlockNode(endNode)) - rightParent = endNode; - else { + nsCOMPtr rightParent; + if (IsBlockNode(GetAsDOMNode(endNode))) { + rightParent = endNode->AsElement(); + } else { NS_ENSURE_STATE(mHTMLEditor); rightParent = mHTMLEditor->GetBlockNodeParent(endNode); } - - // are endpoint block parents the same? use default deletion + + // Are endpoint block parents the same? Use default deletion if (leftParent && leftParent == rightParent) { NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers); - } - else - { - // deleting across blocks - // are the blocks of same type? + } else { + // Deleting across blocks. Are the blocks of same type? NS_ENSURE_STATE(leftParent && rightParent); - - // are the blocks siblings? - nsCOMPtr leftBlockParent; - nsCOMPtr rightBlockParent; - leftParent->GetParentNode(getter_AddRefs(leftBlockParent)); - rightParent->GetParentNode(getter_AddRefs(rightBlockParent)); + + // Are the blocks siblings? + nsCOMPtr leftBlockParent = leftParent->GetParentNode(); + nsCOMPtr rightBlockParent = rightParent->GetParentNode(); // MOOSE: this could conceivably screw up a table.. fix me. - if ( (leftBlockParent == rightBlockParent) - && (!mHTMLEditor || mHTMLEditor->NodesSameType(leftParent, rightParent)) ) - { - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr leftParent_ = do_QueryInterface(leftParent); - nsCOMPtr rightParent_ = do_QueryInterface(rightParent); - NS_ENSURE_STATE(leftParent_ && rightParent_); - if (nsHTMLEditUtils::IsParagraph(leftParent)) - { - // first delete the selection + NS_ENSURE_STATE(mHTMLEditor); + if (leftBlockParent == rightBlockParent && + mHTMLEditor->NodesSameType(GetAsDOMNode(leftParent), + GetAsDOMNode(rightParent))) { + if (leftParent->Tag() == nsGkAtoms::p) { + // First delete the selection NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers); NS_ENSURE_SUCCESS(res, res); - // then join para's, insert break + // Then join paragraphs, insert break NS_ENSURE_STATE(mHTMLEditor); - ::DOMPoint pt = mHTMLEditor->JoinNodeDeep(*leftParent_, *rightParent_); + ::DOMPoint pt = mHTMLEditor->JoinNodeDeep(*leftParent, *rightParent); NS_ENSURE_STATE(pt.node); - // fix up selection + // Fix up selection res = aSelection->Collapse(pt.node, pt.offset); - return res; + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } - if (nsHTMLEditUtils::IsListItem(leftParent) - || nsHTMLEditUtils::IsHeader(leftParent)) - { - // first delete the selection + if (nsHTMLEditUtils::IsListItem(leftParent) || + nsHTMLEditUtils::IsHeader(*leftParent)) { + // First delete the selection NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers); NS_ENSURE_SUCCESS(res, res); - // join blocks + // Join blocks NS_ENSURE_STATE(mHTMLEditor); - ::DOMPoint pt = mHTMLEditor->JoinNodeDeep(*leftParent_, *rightParent_); + ::DOMPoint pt = mHTMLEditor->JoinNodeDeep(*leftParent, *rightParent); NS_ENSURE_STATE(pt.node); - // fix up selection + // Fix up selection res = aSelection->Collapse(pt.node, pt.offset); - return res; + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } } - - // else blocks not same type, or not siblings. Delete everything except - // table elements. + + // Else blocks not same type, or not siblings. Delete everything + // except table elements. join = true; uint32_t rangeCount = aSelection->GetRangeCount(); for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { nsRefPtr range = aSelection->GetRangeAt(rangeIdx); - // build a list of nodes in the range - nsCOMArray arrayOfNodes; + // Build a list of nodes in the range + nsTArray> arrayOfNodes; nsTrivialFunctor functor; nsDOMSubtreeIterator iter; res = iter.Init(range); NS_ENSURE_SUCCESS(res, res); res = iter.AppendList(functor, arrayOfNodes); NS_ENSURE_SUCCESS(res, res); - - // now that we have the list, delete non table elements - int32_t listCount = arrayOfNodes.Count(); + + // Now that we have the list, delete non-table elements + int32_t listCount = arrayOfNodes.Length(); for (int32_t j = 0; j < listCount; j++) { nsCOMPtr somenode = do_QueryInterface(arrayOfNodes[0]); NS_ENSURE_STATE(somenode); DeleteNonTableElements(somenode); - arrayOfNodes.RemoveObjectAt(0); - // If something visible is deleted, no need to join. - // Visible means all nodes except non-visible textnodes and breaks. + arrayOfNodes.RemoveElementAt(0); + // If something visible is deleted, no need to join. Visible means + // all nodes except non-visible textnodes and breaks. if (join && origCollapsed) { if (!somenode->IsContent()) { join = false; @@ -2494,73 +2453,59 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, } else { NS_ENSURE_STATE(mHTMLEditor); join = content->IsHTML(nsGkAtoms::br) && - !mHTMLEditor->IsVisBreak(somenode->AsDOMNode()); + !mHTMLEditor->IsVisBreak(somenode); } } } } - - // check endopints for possible text deletion. - // we can assume that if text node is found, we can - // delete to end or to begining as appropriate, - // since the case where both sel endpoints in same - // text node was already handled (we wouldn't be here) - NS_ENSURE_STATE(mHTMLEditor); - if ( mHTMLEditor->IsTextNode(startNode) ) - { - // delete to last character - nsCOMPtr node = do_QueryInterface(startNode); - uint32_t len = node->Length(); - if (len > (uint32_t)startOffset) - { - nsRefPtr dataNode = - static_cast(node.get()); - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteText(*dataNode, startOffset, - len - startOffset); - NS_ENSURE_SUCCESS(res, res); - } + + // Check endpoints for possible text deletion. We can assume that if + // text node is found, we can delete to end or to begining as + // appropriate, since the case where both sel endpoints in same text + // node was already handled (we wouldn't be here) + if (startNode->GetAsText() && + startNode->Length() > uint32_t(startOffset)) { + // Delete to last character + nsRefPtr dataNode = + static_cast(startNode.get()); + NS_ENSURE_STATE(mHTMLEditor); + res = mHTMLEditor->DeleteText(*dataNode, startOffset, + startNode->Length() - startOffset); + NS_ENSURE_SUCCESS(res, res); } - NS_ENSURE_STATE(mHTMLEditor); - if ( mHTMLEditor->IsTextNode(endNode) ) - { - // delete to first character - nsCOMPtr node = do_QueryInterface(endNode); - if (endOffset) - { - NS_ENSURE_STATE(mHTMLEditor); - nsRefPtr dataNode = - static_cast(node.get()); - res = mHTMLEditor->DeleteText(*dataNode, 0, endOffset); - NS_ENSURE_SUCCESS(res, res); - } + if (endNode->GetAsText() && endOffset) { + // Delete to first character + NS_ENSURE_STATE(mHTMLEditor); + nsRefPtr dataNode = + static_cast(endNode.get()); + res = mHTMLEditor->DeleteText(*dataNode, 0, endOffset); + NS_ENSURE_SUCCESS(res, res); } if (join) { - res = JoinBlocks(leftParent, rightParent, aCancel); + res = JoinBlocks(GetAsDOMNode(leftParent), GetAsDOMNode(rightParent), + aCancel); NS_ENSURE_SUCCESS(res, res); } } } } - //If we're joining blocks: if deleting forward the selection should be - //collapsed to the end of the selection, if deleting backward the selection - //should be collapsed to the beginning of the selection. But if we're not - //joining then the selection should collapse to the beginning of the - //selection if we'redeleting forward, because the end of the selection will - //still be in the next block. And same thing for deleting backwards - //(selection should collapse to the end, because the beginning will still - //be in the first block). See Bug 507936 - if (join ? aAction == nsIEditor::eNext : aAction == nsIEditor::ePrevious) - { - res = aSelection->Collapse(endNode,endOffset); + // If we're joining blocks: if deleting forward the selection should be + // collapsed to the end of the selection, if deleting backward the selection + // should be collapsed to the beginning of the selection. But if we're not + // joining then the selection should collapse to the beginning of the + // selection if we'redeleting forward, because the end of the selection will + // still be in the next block. And same thing for deleting backwards + // (selection should collapse to the end, because the beginning will still be + // in the first block). See Bug 507936 + if (aAction == (join ? nsIEditor::eNext : nsIEditor::ePrevious)) { + res = aSelection->Collapse(endNode, endOffset); + } else { + res = aSelection->Collapse(startNode, startOffset); } - else - { - res = aSelection->Collapse(startNode,startOffset); - } - return res; -} + NS_ENSURE_SUCCESS(res, res); + return NS_OK; +} /***************************************************************************************************** diff --git a/editor/libeditor/nsHTMLEditUtils.cpp b/editor/libeditor/nsHTMLEditUtils.cpp index f6fe61e0571..3c868a66e8b 100644 --- a/editor/libeditor/nsHTMLEditUtils.cpp +++ b/editor/libeditor/nsHTMLEditUtils.cpp @@ -124,10 +124,9 @@ nsHTMLEditUtils::IsSmall(nsIDOMNode* aNode) // IsHeader: true if node an html header // bool -nsHTMLEditUtils::IsHeader(nsIDOMNode* aNode) +nsHTMLEditUtils::IsHeader(nsINode& aNode) { - NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsHeader"); - nsCOMPtr nodeAtom = nsEditor::GetTag(aNode); + nsCOMPtr nodeAtom = aNode.Tag(); return (nodeAtom == nsGkAtoms::h1) || (nodeAtom == nsGkAtoms::h2) || (nodeAtom == nsGkAtoms::h3) @@ -136,6 +135,14 @@ nsHTMLEditUtils::IsHeader(nsIDOMNode* aNode) || (nodeAtom == nsGkAtoms::h6); } +bool +nsHTMLEditUtils::IsHeader(nsIDOMNode* aNode) +{ + nsCOMPtr node = do_QueryInterface(aNode); + NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsHeader"); + return IsHeader(*node); +} + /////////////////////////////////////////////////////////////////////////// // IsParagraph: true if node an html paragraph diff --git a/editor/libeditor/nsHTMLEditUtils.h b/editor/libeditor/nsHTMLEditUtils.h index b746516a9c5..ab08c274a64 100644 --- a/editor/libeditor/nsHTMLEditUtils.h +++ b/editor/libeditor/nsHTMLEditUtils.h @@ -23,6 +23,7 @@ public: static bool IsFormatNode(nsINode* aNode); static bool IsFormatNode(nsIDOMNode *aNode); static bool IsNodeThatCanOutdent(nsIDOMNode *aNode); + static bool IsHeader(nsINode& aNode); static bool IsHeader(nsIDOMNode *aNode); static bool IsParagraph(nsIDOMNode *aNode); static bool IsHR(nsIDOMNode *aNode);