mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1154791 - Remember all ranges for all selections when splitting nodes in the editor transactions; r=ehsan
This commit is contained in:
parent
8e69c92d4c
commit
53e93a2848
@ -2597,23 +2597,42 @@ nsEditor::CreateTxnForJoinNode(nsINode& aLeftNode, nsINode& aRightNode)
|
||||
|
||||
// BEGIN nsEditor public helper methods
|
||||
|
||||
struct SavedRange {
|
||||
nsRefPtr<Selection> mSelection;
|
||||
nsCOMPtr<nsINode> mStartNode;
|
||||
nsCOMPtr<nsINode> mEndNode;
|
||||
int32_t mStartOffset;
|
||||
int32_t mEndOffset;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsEditor::SplitNodeImpl(nsIContent& aExistingRightNode,
|
||||
int32_t aOffset,
|
||||
nsIContent& aNewLeftNode)
|
||||
{
|
||||
// Get selection
|
||||
nsRefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
// Remember all selection points.
|
||||
nsAutoTArray<SavedRange, 10> 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;
|
||||
}
|
||||
|
||||
// Remember some selection points, if selection is set
|
||||
nsCOMPtr<nsINode> 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();
|
||||
for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) {
|
||||
nsRefPtr<nsRange> 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<nsINode> parent = aExistingRightNode.GetParentNode();
|
||||
@ -2664,41 +2683,64 @@ nsEditor::SplitNodeImpl(nsIContent& aExistingRightNode,
|
||||
ps->FlushPendingNotifications(Flush_Frames);
|
||||
}
|
||||
|
||||
if (GetShouldTxnSetSelection()) {
|
||||
// Editor wants us to set selection at split point
|
||||
bool shouldSetSelection = GetShouldTxnSetSelection();
|
||||
|
||||
nsRefPtr<Selection> 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 {
|
||||
range.mStartOffset -= aOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (range.mEndNode == &aExistingRightNode) {
|
||||
if (range.mEndOffset < aOffset) {
|
||||
range.mEndNode = &aNewLeftNode;
|
||||
} else {
|
||||
range.mEndOffset -= aOffset;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<nsRange> 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> selection = GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
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;
|
||||
} else {
|
||||
selStartOffset -= aOffset;
|
||||
}
|
||||
}
|
||||
if (selEndNode == &aExistingRightNode) {
|
||||
if (selEndOffset < aOffset) {
|
||||
selEndNode = &aNewLeftNode;
|
||||
} else {
|
||||
selEndOffset -= aOffset;
|
||||
}
|
||||
}
|
||||
selection->Collapse(selStartNode, selStartOffset);
|
||||
selection->Extend(selEndNode, selEndOffset);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct SavedRange {
|
||||
nsRefPtr<Selection> mSelection;
|
||||
nsCOMPtr<nsINode> mStartNode;
|
||||
nsCOMPtr<nsINode> mEndNode;
|
||||
int32_t mStartOffset;
|
||||
int32_t mEndOffset;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
|
||||
nsINode* aNodeToJoin,
|
||||
@ -2730,9 +2772,7 @@ nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
|
||||
|
||||
for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) {
|
||||
nsRefPtr<nsRange> 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();
|
||||
|
@ -24,6 +24,7 @@ skip-if = buildapp == 'mulet'
|
||||
[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]
|
||||
|
64
editor/libeditor/tests/test_bug1154791.html
Normal file
64
editor/libeditor/tests/test_bug1154791.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1154791
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1154791</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
</div>
|
||||
|
||||
<div id="content" contenteditable>
|
||||
<tt>thiss onee is stilll a</tt>
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
||||
/** Test for Bug 1154791 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var div = document.getElementById("content");
|
||||
div.focus();
|
||||
synthesizeMouseAtCenter(div, {});
|
||||
synthesizeKey("VK_LEFT", {});
|
||||
synthesizeKey("VK_LEFT", {});
|
||||
|
||||
setTimeout(function() {
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
setTimeout(function() {
|
||||
synthesizeKey(" ", {});
|
||||
|
||||
var sel = getSpellCheckSelection();
|
||||
is(sel.rangeCount, 2, "We should have two misspelled words");
|
||||
is(sel.getRangeAt(0), "thiss", "Correct misspelled word");
|
||||
is(sel.getRangeAt(1), "onee", "Correct misspelled word");
|
||||
|
||||
SimpleTest.finish();
|
||||
},0);
|
||||
},0);
|
||||
|
||||
});
|
||||
|
||||
function getSpellCheckSelection() {
|
||||
var Ci = Components.interfaces;
|
||||
var editingSession = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEditingSession);
|
||||
var editor = editingSession.getEditorForWindow(window);
|
||||
var selcon = editor.selectionController;
|
||||
return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user