# HG changeset patch # User Jorg K # Parent 0a46652bd992eb3fdd3ef48f6b066650c33210a5 Bug 1154791 - Remember all ranges for all selections when splitting nodes in the editor transactions; r=ehsan diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -2592,33 +2592,52 @@ nsEditor::CreateTxnForJoinNode(nsINode& } // END nsEditor core implementation // BEGIN nsEditor public helper methods +struct SavedRange { + nsRefPtr mSelection; + nsCOMPtr mStartNode; + nsCOMPtr mEndNode; + int32_t mStartOffset; + int32_t mEndOffset; +}; + nsresult nsEditor::SplitNodeImpl(nsIContent& aExistingRightNode, int32_t aOffset, nsIContent& aNewLeftNode) { - // Get selection - nsRefPtr selection = GetSelection(); - NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); - - // Remember some selection points, if selection is set - nsCOMPtr selStartNode, selEndNode; - int32_t selStartOffset = 0, selEndOffset = 0; - if (selection->GetRangeAt(0)) { - selStartNode = selection->GetRangeAt(0)->GetStartParent(); - selStartOffset = selection->GetRangeAt(0)->StartOffset(); - selEndNode = selection->GetRangeAt(0)->GetEndParent(); - selEndOffset = selection->GetRangeAt(0)->EndOffset(); + // Remember all selection points. + nsAutoTArray savedRanges; + for (size_t i = 0; i < nsISelectionController::NUM_SELECTIONTYPES - 1; ++i) { + SelectionType type(1 << i); + SavedRange range; + range.mSelection = GetSelection(type); + if (type == nsISelectionController::SELECTION_NORMAL) { + NS_ENSURE_TRUE(range.mSelection, NS_ERROR_NULL_POINTER); + } else if (!range.mSelection) { + // For non-normal selections, skip over the non-existing ones. + continue; + } + + for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) { + nsRefPtr r = range.mSelection->GetRangeAt(j); + MOZ_ASSERT(r->IsPositioned()); + range.mStartNode = r->GetStartParent(); + range.mStartOffset = r->StartOffset(); + range.mEndNode = r->GetEndParent(); + range.mEndOffset = r->EndOffset(); + + savedRanges.AppendElement(range); + } } nsCOMPtr parent = aExistingRightNode.GetParentNode(); NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); ErrorResult rv; parent->InsertBefore(aNewLeftNode, &aExistingRightNode, rv); NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode()); @@ -2659,51 +2678,74 @@ nsEditor::SplitNodeImpl(nsIContent& aExi } // Handle selection nsCOMPtr ps = GetPresShell(); if (ps) { ps->FlushPendingNotifications(Flush_Frames); } - if (GetShouldTxnSetSelection()) { - // Editor wants us to set selection at split point - selection->Collapse(&aNewLeftNode, aOffset); - } else if (selStartNode) { - // Else adjust the selection if needed. If selStartNode is null, then - // there was no selection. - if (selStartNode == &aExistingRightNode) { - if (selStartOffset < aOffset) { - selStartNode = &aNewLeftNode; + bool shouldSetSelection = GetShouldTxnSetSelection(); + + nsRefPtr previousSelection; + for (size_t i = 0; i < savedRanges.Length(); ++i) { + // Adjust the selection if needed. + SavedRange& range = savedRanges[i]; + + // If we have not seen the selection yet, clear all of its ranges. + if (range.mSelection != previousSelection) { + nsresult rv = range.mSelection->RemoveAllRanges(); + NS_ENSURE_SUCCESS(rv, rv); + previousSelection = range.mSelection; + } + + if (shouldSetSelection && + range.mSelection->Type() == + nsISelectionController::SELECTION_NORMAL) { + // If the editor should adjust the selection, don't bother restoring + // the ranges for the normal selection here. + continue; + } + + // Split the selection into existing node and new node. + if (range.mStartNode == &aExistingRightNode) { + if (range.mStartOffset < aOffset) { + range.mStartNode = &aNewLeftNode; } else { - selStartOffset -= aOffset; + range.mStartOffset -= aOffset; } } - if (selEndNode == &aExistingRightNode) { - if (selEndOffset < aOffset) { - selEndNode = &aNewLeftNode; + + if (range.mEndNode == &aExistingRightNode) { + if (range.mEndOffset < aOffset) { + range.mEndNode = &aNewLeftNode; } else { - selEndOffset -= aOffset; + range.mEndOffset -= aOffset; } } - selection->Collapse(selStartNode, selStartOffset); - selection->Extend(selEndNode, selEndOffset); + + nsRefPtr newRange; + nsresult rv = nsRange::CreateRange(range.mStartNode, range.mStartOffset, + range.mEndNode, range.mEndOffset, + getter_AddRefs(newRange)); + NS_ENSURE_SUCCESS(rv, rv); + rv = range.mSelection->AddRange(newRange); + NS_ENSURE_SUCCESS(rv, rv); } + if (shouldSetSelection) { + // Editor wants us to set selection at split point. + nsRefPtr selection = GetSelection(); + NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); + selection->Collapse(&aNewLeftNode, aOffset); + } + return NS_OK; } -struct SavedRange { - nsRefPtr mSelection; - nsCOMPtr mStartNode; - nsCOMPtr mEndNode; - int32_t mStartOffset; - int32_t mEndOffset; -}; - nsresult nsEditor::JoinNodesImpl(nsINode* aNodeToKeep, nsINode* aNodeToJoin, nsINode* aParent) { MOZ_ASSERT(aNodeToKeep); MOZ_ASSERT(aNodeToJoin); MOZ_ASSERT(aParent); @@ -2725,19 +2767,17 @@ nsEditor::JoinNodesImpl(nsINode* aNodeTo NS_ENSURE_TRUE(range.mSelection, NS_ERROR_NULL_POINTER); } else if (!range.mSelection) { // For non-normal selections, skip over the non-existing ones. continue; } for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) { nsRefPtr r = range.mSelection->GetRangeAt(j); - if (!r->IsPositioned()) { - continue; - } + MOZ_ASSERT(r->IsPositioned()); range.mStartNode = r->GetStartParent(); range.mStartOffset = r->StartOffset(); range.mEndNode = r->GetEndParent(); range.mEndOffset = r->EndOffset(); // 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. diff --git a/editor/libeditor/tests/chrome.ini b/editor/libeditor/tests/chrome.ini --- a/editor/libeditor/tests/chrome.ini +++ b/editor/libeditor/tests/chrome.ini @@ -18,16 +18,17 @@ skip-if = buildapp == 'mulet' [test_bug636465.xul] [test_bug646194.xul] [test_bug780908.xul] [test_bug830600.html] [test_bug1053048.html] [test_bug1100966.html] [test_bug1102906.html] [test_bug1101392.html] +[test_bug1154791.html] [test_composition_event_created_in_chrome.html] [test_contenteditable_text_input_handling.html] [test_dragdrop.html] skip-if = buildapp == 'mulet' [test_htmleditor_keyevent_handling.html] [test_selection_move_commands.xul] [test_texteditor_keyevent_handling.html] skip-if = (debug && os=='win') || (os == 'linux') # Bug 1116205, leaks on windows debug, fails delete key on linux diff --git a/editor/libeditor/tests/test_bug1154791.html b/editor/libeditor/tests/test_bug1154791.html new file mode 100644 --- /dev/null +++ b/editor/libeditor/tests/test_bug1154791.html @@ -0,0 +1,64 @@ + + + + + Test for Bug 1154791 + + + + + +
+
+ +
+thiss onee is stilll a +
+ +
+
+ + + + +