--- a/dom/base/RangeBoundary.h
+++ b/dom/base/RangeBoundary.h
@@ -211,19 +211,23 @@ public:
void
Set(nsINode* aContainer, int32_t aOffset)
{
mParent = aContainer;
mRef = nullptr;
mOffset = mozilla::Some(aOffset);
}
void
- Set(const nsIContent* aChild)
+ Set(const nsINode* aChild)
{
MOZ_ASSERT(aChild);
+ if (!aChild->IsContent()) {
+ Clear();
+ return;
+ }
mParent = aChild->GetParentNode();
mRef = aChild->GetPreviousSibling();
if (!mRef) {
mOffset = mozilla::Some(0);
} else {
mOffset.reset();
}
}
@@ -241,91 +245,97 @@ public:
/**
* AdvanceOffset() tries to reference next sibling of mRef if its container
* can have children or increments offset if the container is a text node or
* something.
* If the container can have children and there is no next sibling, this
* outputs warning and does nothing. So, callers need to check if there is
* next sibling which you need to refer.
+ *
+ * @return true if there is a next sibling to refer.
*/
- void
+ bool
AdvanceOffset()
{
if (NS_WARN_IF(!mParent)) {
- return;
+ return false;
}
EnsureRef();
if (!mRef) {
if (!mParent->IsContainerNode()) {
// In text node or something, just increment the offset.
MOZ_ASSERT(mOffset.isSome());
if (NS_WARN_IF(mOffset.value() == mParent->Length())) {
// Already referring the end of the node.
- return;
+ return false;
}
mOffset = mozilla::Some(mOffset.value() + 1);
- return;
+ return true;
}
mRef = mParent->GetFirstChild();
if (NS_WARN_IF(!mRef)) {
// No children in the container.
mOffset = mozilla::Some(0);
- } else {
- mOffset = mozilla::Some(1);
+ return false;
}
- return;
+ mOffset = mozilla::Some(1);
+ return true;
}
nsIContent* nextSibling = mRef->GetNextSibling();
if (NS_WARN_IF(!nextSibling)) {
// Already referring the end of the container.
- return;
+ return false;
}
mRef = nextSibling;
if (mOffset.isSome()) {
mOffset = mozilla::Some(mOffset.value() + 1);
}
+ return true;
}
/**
* RewindOffset() tries to reference next sibling of mRef if its container
* can have children or decrements offset if the container is a text node or
* something.
* If the container can have children and there is no next previous, this
* outputs warning and does nothing. So, callers need to check if there is
* previous sibling which you need to refer.
+ *
+ * @return true if there is a previous sibling to refer.
*/
- void
+ bool
RewindOffset()
{
if (NS_WARN_IF(!mParent)) {
- return;
+ return false;
}
EnsureRef();
if (!mRef) {
if (NS_WARN_IF(mParent->IsContainerNode())) {
// Already referring the start of the container
mOffset = mozilla::Some(0);
- return;
+ return false;
}
// In text node or something, just decrement the offset.
MOZ_ASSERT(mOffset.isSome());
if (NS_WARN_IF(mOffset.value() == 0)) {
// Already referring the start of the node.
- return;
+ return false;
}
mOffset = mozilla::Some(mOffset.value() - 1);
- return;
+ return true;
}
mRef = mRef->GetPreviousSibling();
if (mOffset.isSome()) {
mOffset = mozilla::Some(mOffset.value() - 1);
}
+ return true;
}
void
SetAfterRef(nsINode* aParent, nsIContent* aRef)
{
mParent = aParent;
mRef = aRef;
if (!mRef) {
--- a/editor/libeditor/CreateElementTransaction.cpp
+++ b/editor/libeditor/CreateElementTransaction.cpp
@@ -8,16 +8,17 @@
#include <algorithm>
#include <stdio.h>
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/Casting.h"
#include "mozilla/EditorBase.h"
+#include "mozilla/EditorDOMPoint.h"
#include "nsAlgorithm.h"
#include "nsAString.h"
#include "nsDebug.h"
#include "nsError.h"
#include "nsIContent.h"
#include "nsIEditor.h"
#include "nsINode.h"
@@ -98,17 +99,24 @@ CreateElementTransaction::DoTransaction(
if (!mEditorBase->GetShouldTxnSetSelection()) {
// Do nothing - DOM range gravity will adjust selection
return NS_OK;
}
RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
- rv = selection->Collapse(mParent, mParent->IndexOf(mNewNode) + 1);
+ EditorRawDOMPoint afterNewNode(mNewNode);
+ if (NS_WARN_IF(!afterNewNode.AdvanceOffset())) {
+ // If mutation observer or mutation event listener moved or removed the
+ // new node, we hit this case. Should we use script blocker while we're
+ // in this method?
+ return NS_ERROR_FAILURE;
+ }
+ rv = selection->Collapse(afterNewNode);
NS_ASSERTION(!rv.Failed(),
"selection could not be collapsed after insert");
return NS_OK;
}
NS_IMETHODIMP
CreateElementTransaction::UndoTransaction()
{
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -4273,32 +4273,40 @@ EditorBase::DeleteSelectionAndPrepareToC
NS_ASSERTION(node->GetParentNode(),
"It's impossible to insert into chardata with no parent -- "
"fix the caller");
NS_ENSURE_STATE(node->GetParentNode());
uint32_t offset = selection->AnchorOffset();
if (!offset) {
- nsresult rv = selection->Collapse(node->GetParentNode(),
- node->GetParentNode()->IndexOf(node));
+ EditorRawDOMPoint atNode(node);
+ if (NS_WARN_IF(!atNode.IsSetAndValid())) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = selection->Collapse(atNode);
MOZ_ASSERT(NS_SUCCEEDED(rv));
NS_ENSURE_SUCCESS(rv, rv);
} else if (offset == node->Length()) {
- nsresult rv =
- selection->Collapse(node->GetParentNode(),
- node->GetParentNode()->IndexOf(node) + 1);
+ EditorRawDOMPoint afterNode(node);
+ if (NS_WARN_IF(!afterNode.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = selection->Collapse(afterNode);
MOZ_ASSERT(NS_SUCCEEDED(rv));
NS_ENSURE_SUCCESS(rv, rv);
} else {
nsCOMPtr<nsIDOMNode> tmp;
nsresult rv = SplitNode(node->AsDOMNode(), offset, getter_AddRefs(tmp));
NS_ENSURE_SUCCESS(rv, rv);
- rv = selection->Collapse(node->GetParentNode(),
- node->GetParentNode()->IndexOf(node));
+ EditorRawDOMPoint atNode(node);
+ if (NS_WARN_IF(!atNode.IsSetAndValid())) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = selection->Collapse(atNode);
MOZ_ASSERT(NS_SUCCEEDED(rv));
NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK;
}
void
--- a/editor/libeditor/EditorDOMPoint.h
+++ b/editor/libeditor/EditorDOMPoint.h
@@ -44,25 +44,27 @@ public:
int32_t aOffset)
: RangeBoundaryBase<ParentType, RefType>()
{
nsCOMPtr<nsINode> container = do_QueryInterface(aDOMContainer);
this->Set(container, aOffset);
}
/**
- * Different from RangeBoundary, aReferenceChild should be a child node
+ * Different from RangeBoundary, aPointedNode should be a child node
* which you want to refer. So, set non-nullptr if offset is
* 0 - Length() - 1. Otherwise, set nullptr, i.e., if offset is same as
* Length().
*/
- EditorDOMPointBase(nsINode* aContainer,
- nsIContent* aPointedNode)
- : RangeBoundaryBase<ParentType, RefType>(aContainer,
- GetRef(aPointedNode))
+ explicit EditorDOMPointBase(nsINode* aPointedNode)
+ : RangeBoundaryBase<ParentType, RefType>(
+ aPointedNode && aPointedNode->IsContent() ?
+ aPointedNode->GetParentNode() : nullptr,
+ aPointedNode && aPointedNode->IsContent() ?
+ GetRef(aPointedNode->AsContent()) : nullptr)
{
}
EditorDOMPointBase(nsINode* aConatiner,
nsIContent* aPointedNode,
int32_t aOffset)
: RangeBoundaryBase<ParentType, RefType>(aConatiner,
GetRef(aPointedNode),
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1260,19 +1260,18 @@ HTMLEditRules::WillInsert(Selection& aSe
if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
nsCOMPtr<Element> block1 = htmlEditor->GetBlock(selNode);
nsCOMPtr<Element> block2 = htmlEditor->GetBlockNodeParent(priorNode);
if (block1 && block1 == block2) {
// If we are here then the selection is right after a mozBR that is in
// the same block as the selection. We need to move the selection start
// to be before the mozBR.
- selNode = priorNode->GetParentNode();
- selOffset = selNode->IndexOf(priorNode);
- nsresult rv = aSelection.Collapse(selNode, selOffset);
+ EditorRawDOMPoint point(priorNode);
+ nsresult rv = aSelection.Collapse(point.AsRaw());
NS_ENSURE_SUCCESS_VOID(rv);
}
}
if (mDidDeleteSelection &&
(mTheAction == EditAction::insertText ||
mTheAction == EditAction::insertIMEText ||
mTheAction == EditAction::deleteSelection)) {
@@ -1488,17 +1487,19 @@ HTMLEditRules::WillInsertText(EditAction
rv = wsObj.InsertText(subStr, address_of(curNode),
address_of(selChild), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
}
aSelection->SetInterlinePosition(false);
- if (curNode) aSelection->Collapse(curNode, curOffset);
+ if (curNode) {
+ aSelection->Collapse(curNode, curOffset);
+ }
// manually update the doc changed range so that AfterEdit will clean up
// the correct portion of the document.
if (!mDocChangeRange) {
mDocChangeRange = new nsRange(selNode);
}
if (curNode) {
rv = mDocChangeRange->SetStartAndEnd(selNode, selOffset,
@@ -1797,25 +1798,26 @@ HTMLEditRules::StandardBreakImpl(nsINode
NS_ENSURE_STATE(aOffset != -1);
node = linkParent;
}
brNode = wsObj.InsertBreak(address_of(node), &aOffset, nsIEditor::eNone);
NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE);
}
node = brNode->GetParentNode();
NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
- int32_t offset = node->IndexOf(brNode);
if (bAfterBlock && bBeforeBlock) {
// We just placed a br between block boundaries. This is the one case
// where we want the selection to be before the br we just placed, as the
// br will be on a new line, rather than at end of prior line.
aSelection.SetInterlinePosition(true);
- nsresult rv = aSelection.Collapse(node, offset);
+ EditorRawDOMPoint point(brNode);
+ nsresult rv = aSelection.Collapse(point.AsRaw());
NS_ENSURE_SUCCESS(rv, rv);
} else {
+ int32_t offset = node->IndexOf(brNode);
WSRunObject wsObj(htmlEditor, node, offset + 1);
nsCOMPtr<nsINode> secondBR;
int32_t visOffset = 0;
WSType wsType;
wsObj.NextVisibleNode(node, offset + 1, address_of(secondBR),
&visOffset, &wsType);
if (wsType == WSType::br) {
// The next thing after the break we inserted is another break. Move the
@@ -2304,17 +2306,17 @@ HTMLEditRules::WillDeleteSelection(Selec
// Are they both text nodes? If so, join them!
if (startNode == stepbrother && startNode->GetAsText() &&
sibling->GetAsText()) {
EditorDOMPoint pt = JoinNodesSmart(*sibling, *startNode->AsContent());
if (NS_WARN_IF(!pt.IsSet())) {
return NS_ERROR_FAILURE;
}
// Fix up selection
- rv = aSelection->Collapse(pt.Container(), pt.Offset());
+ rv = aSelection->Collapse(pt.AsRaw());
NS_ENSURE_SUCCESS(rv, rv);
}
rv = InsertBRIfNeeded(aSelection);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
if (wsType == WSType::otherBlock) {
@@ -2375,17 +2377,17 @@ HTMLEditRules::WillDeleteSelection(Selec
if (bDeletedBR) {
// Put selection at edge of block and we are done.
NS_ENSURE_STATE(leafNode);
EditorDOMPoint newSel = GetGoodSelPointForNode(*leafNode, aAction);
if (NS_WARN_IF(!newSel.IsSet())) {
return NS_ERROR_FAILURE;
}
- aSelection->Collapse(newSel.Container(), newSel.Offset());
+ aSelection->Collapse(newSel.AsRaw());
return NS_OK;
}
// Else we are joining content to block
nsCOMPtr<nsINode> selPointNode = startNode;
int32_t selPointOffset = startOffset;
{
@@ -2567,17 +2569,17 @@ HTMLEditRules::WillDeleteSelection(Selec
// Join blocks
NS_ENSURE_STATE(mHTMLEditor);
EditorDOMPoint pt =
mHTMLEditor->JoinNodeDeep(*leftParent, *rightParent);
if (NS_WARN_IF(!pt.IsSet())) {
return NS_ERROR_FAILURE;
}
// Fix up selection
- rv = aSelection->Collapse(pt.Container(), pt.Offset());
+ rv = aSelection->Collapse(pt.AsRaw());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// Else blocks not same type, or not siblings. Delete everything
// except table elements.
join = true;
@@ -2787,17 +2789,17 @@ HTMLEditRules::GetGoodSelPointForNode(ns
return EditorDOMPoint(&aNode, isPreviousAction ? aNode.Length() : 0);
}
if (NS_WARN_IF(!mHTMLEditor) ||
NS_WARN_IF(!aNode.IsContent())) {
return EditorDOMPoint();
}
- EditorDOMPoint ret(aNode.GetParentNode(), aNode.AsContent());
+ EditorDOMPoint ret(&aNode);
if ((!aNode.IsHTMLElement(nsGkAtoms::br) ||
mHTMLEditor->IsVisibleBRElement(&aNode)) && isPreviousAction) {
ret.AdvanceOffset();
}
return ret;
}
EditActionResult
@@ -4543,35 +4545,32 @@ HTMLEditRules::WillOutdent(Selection& aS
// Make sure selection didn't stick to last piece of content in old bq (only
// a problem for collapsed selections)
if (rememberedLeftBQ || rememberedRightBQ) {
if (aSelection.Collapsed()) {
// Push selection past end of rememberedLeftBQ
NS_ENSURE_TRUE(aSelection.GetRangeAt(0), NS_OK);
nsCOMPtr<nsINode> startNode =
aSelection.GetRangeAt(0)->GetStartContainer();
- int32_t startOffset = aSelection.GetRangeAt(0)->StartOffset();
if (rememberedLeftBQ &&
(startNode == rememberedLeftBQ ||
EditorUtils::IsDescendantOf(*startNode, *rememberedLeftBQ))) {
// Selection is inside rememberedLeftBQ - push it past it.
- startNode = rememberedLeftBQ->GetParentNode();
- startOffset = startNode ? 1 + startNode->IndexOf(rememberedLeftBQ) : 0;
- aSelection.Collapse(startNode, startOffset);
+ EditorRawDOMPoint afterRememberedLeftBQ(rememberedLeftBQ);
+ afterRememberedLeftBQ.AdvanceOffset();
+ aSelection.Collapse(afterRememberedLeftBQ);
}
// And pull selection before beginning of rememberedRightBQ
startNode = aSelection.GetRangeAt(0)->GetStartContainer();
- startOffset = aSelection.GetRangeAt(0)->StartOffset();
if (rememberedRightBQ &&
(startNode == rememberedRightBQ ||
EditorUtils::IsDescendantOf(*startNode, *rememberedRightBQ))) {
// Selection is inside rememberedRightBQ - push it before it.
- startNode = rememberedRightBQ->GetParentNode();
- startOffset = startNode ? startNode->IndexOf(rememberedRightBQ) : -1;
- aSelection.Collapse(startNode, startOffset);
+ EditorRawDOMPoint atRememberedRightBQ(rememberedRightBQ);
+ aSelection.Collapse(atRememberedRightBQ);
}
}
return NS_OK;
}
return NS_OK;
}
@@ -5179,47 +5178,55 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
// Adjust selection to be right before it
nsresult rv = aSelection->Collapse(listParent, listOffset);
NS_ENSURE_SUCCESS(rv, rv);
}
// Else just let selection percolate up. We'll adjust it in
// AfterEdit()
}
} else {
- int32_t offset = blockParent->IndexOf(emptyBlock);
-
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
aAction == nsIEditor::eToEndOfLine) {
// Move to the start of the next node, if any
nsINode* child = emptyBlock->GetNextSibling();
+ int32_t offset = blockParent->IndexOf(emptyBlock);
nsCOMPtr<nsIContent> nextNode =
htmlEditor->GetNextNode(blockParent, offset + 1, child, true);
if (nextNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
- nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
+ nsresult rv = aSelection->Collapse(pt.AsRaw());
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Adjust selection to be right after it.
- nsresult rv = aSelection->Collapse(blockParent, offset + 1);
+ EditorRawDOMPoint afterEmptyBlock(emptyBlock);
+ if (NS_WARN_IF(!afterEmptyBlock.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = aSelection->Collapse(afterEmptyBlock);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (aAction == nsIEditor::ePrevious ||
aAction == nsIEditor::ePreviousWord ||
aAction == nsIEditor::eToBeginningOfLine) {
// Move to the end of the previous node
+ int32_t offset = blockParent->IndexOf(emptyBlock);
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
offset,
emptyBlock,
true);
if (priorNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
- nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
+ nsresult rv = aSelection->Collapse(pt.AsRaw());
NS_ENSURE_SUCCESS(rv, rv);
} else {
- nsresult rv = aSelection->Collapse(blockParent, offset + 1);
+ EditorRawDOMPoint afterEmptyBlock(emptyBlock);
+ if (NS_WARN_IF(!afterEmptyBlock.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = aSelection->Collapse(afterEmptyBlock);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (aAction != nsIEditor::eNone) {
MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet");
}
}
NS_ENSURE_STATE(htmlEditor);
*aHandled = true;
@@ -6616,20 +6623,22 @@ HTMLEditRules::ReturnInHeader(Selection&
// Append a <br> to it
nsCOMPtr<Element> brNode = htmlEditor->CreateBR(pNode, 0);
NS_ENSURE_STATE(brNode);
// Set selection to before the break
rv = aSelection.Collapse(pNode, 0);
NS_ENSURE_SUCCESS(rv, rv);
} else {
- headerParent = sibling->GetParentNode();
- offset = headerParent ? headerParent->IndexOf(sibling) : -1;
+ EditorRawDOMPoint afterSibling(sibling);
+ if (NS_WARN_IF(!afterSibling.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
// Put selection after break
- rv = aSelection.Collapse(headerParent, offset + 1);
+ rv = aSelection.Collapse(afterSibling);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
// Put selection at front of righthand heading
rv = aSelection.Collapse(&aHeader, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@@ -6816,25 +6825,23 @@ HTMLEditRules::SplitParagraph(nsIDOMNode
NS_ENSURE_SUCCESS(rv, rv);
rv = InsertBRIfNeeded(*rightPara);
NS_ENSURE_SUCCESS(rv, rv);
// selection to beginning of right hand para;
// look inside any containers that are up front.
nsCOMPtr<nsINode> rightParaNode = do_QueryInterface(rightPara);
NS_ENSURE_STATE(mHTMLEditor && rightParaNode);
- nsCOMPtr<nsIDOMNode> child =
- GetAsDOMNode(mHTMLEditor->GetLeftmostChild(rightParaNode, true));
+ nsIContent* child = mHTMLEditor->GetLeftmostChild(rightParaNode, true);
if (EditorBase::IsTextNode(child) ||
mHTMLEditor->IsContainer(child)) {
aSelection->Collapse(child,0);
} else {
- int32_t offset;
- nsCOMPtr<nsIDOMNode> parent = EditorBase::GetNodeLocation(child, &offset);
- aSelection->Collapse(parent,offset);
+ EditorRawDOMPoint atChild(child);
+ aSelection->Collapse(atChild);
}
return NS_OK;
}
/**
* ReturnInListItem: do the right thing for returns pressed in list items
*/
nsresult
@@ -6950,34 +6957,38 @@ HTMLEditRules::ReturnInListItem(Selectio
}
nsCOMPtr<Element> brNode;
rv = htmlEditor->CopyLastEditableChildStyles(prevItem,
&aListItem,
getter_AddRefs(brNode));
NS_ENSURE_SUCCESS(rv, rv);
if (brNode) {
- nsCOMPtr<nsINode> brParent = brNode->GetParentNode();
- int32_t offset = brParent ? brParent->IndexOf(brNode) : -1;
- rv = aSelection.Collapse(brParent, offset);
+ EditorRawDOMPoint atBrNode(brNode);
+ if (NS_WARN_IF(!atBrNode.IsSetAndValid())) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = aSelection.Collapse(atBrNode);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
} else {
WSRunObject wsObj(htmlEditor, &aListItem, 0);
nsCOMPtr<nsINode> visNode;
int32_t visOffset = 0;
WSType wsType;
wsObj.NextVisibleNode(&aListItem, 0, address_of(visNode),
&visOffset, &wsType);
if (wsType == WSType::special || wsType == WSType::br ||
visNode->IsHTMLElement(nsGkAtoms::hr)) {
- nsCOMPtr<nsINode> parent = visNode->GetParentNode();
- int32_t offset = parent ? parent->IndexOf(visNode) : -1;
- rv = aSelection.Collapse(parent, offset);
+ EditorRawDOMPoint atVisNode(visNode);
+ if (NS_WARN_IF(!atVisNode.IsSetAndValid())) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = aSelection.Collapse(atVisNode);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
} else {
rv = aSelection.Collapse(visNode, visOffset);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
}
@@ -7672,46 +7683,52 @@ HTMLEditRules::PinSelectionToNewBlock(Se
return rv;
}
bool nodeBefore, nodeAfter;
rv = nsRange::CompareNodeToRange(mNewBlock, range, &nodeBefore, &nodeAfter);
NS_ENSURE_SUCCESS(rv, rv);
if (nodeBefore && nodeAfter) {
return NS_OK; // selection is inside block
- } else if (nodeBefore) {
+ }
+
+ if (nodeBefore) {
// selection is after block. put at end of block.
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsINode> tmp = mHTMLEditor->GetLastEditableChild(*mNewBlock);
if (!tmp) {
tmp = mNewBlock;
}
- uint32_t endPoint;
+ EditorRawDOMPoint endPoint;
if (EditorBase::IsTextNode(tmp) ||
mHTMLEditor->IsContainer(tmp)) {
- endPoint = tmp->Length();
+ endPoint.Set(tmp, tmp->Length());
} else {
- tmp = EditorBase::GetNodeLocation(tmp, (int32_t*)&endPoint);
- endPoint++; // want to be after this node
- }
- return aSelection->Collapse(tmp, (int32_t)endPoint);
+ endPoint.Set(tmp);
+ if (NS_WARN_IF(!endPoint.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+ return aSelection->Collapse(endPoint);
+ }
+
+ // selection is before block. put at start of block.
+ NS_ENSURE_STATE(mHTMLEditor);
+ nsCOMPtr<nsINode> tmp = mHTMLEditor->GetFirstEditableChild(*mNewBlock);
+ if (!tmp) {
+ tmp = mNewBlock;
+ }
+ EditorRawDOMPoint atStartOfBlock;
+ if (EditorBase::IsTextNode(tmp) ||
+ mHTMLEditor->IsContainer(tmp)) {
+ atStartOfBlock.Set(tmp);
} else {
- // selection is before block. put at start of block.
- NS_ENSURE_STATE(mHTMLEditor);
- nsCOMPtr<nsINode> tmp = mHTMLEditor->GetFirstEditableChild(*mNewBlock);
- if (!tmp) {
- tmp = mNewBlock;
- }
- int32_t offset;
- if (EditorBase::IsTextNode(tmp) ||
- mHTMLEditor->IsContainer(tmp)) {
- tmp = EditorBase::GetNodeLocation(tmp, &offset);
- }
- return aSelection->Collapse(tmp, 0);
- }
+ atStartOfBlock.Set(tmp, 0);
+ }
+ return aSelection->Collapse(atStartOfBlock);
}
void
HTMLEditRules::CheckInterlinePosition(Selection& aSelection)
{
// If the selection isn't collapsed, do nothing.
if (!aSelection.Collapsed()) {
return;
@@ -7895,17 +7912,17 @@ HTMLEditRules::AdjustSelection(Selection
rv = FindNearSelectableNode(selNode, selOffset, child, aAction,
address_of(nearNode));
NS_ENSURE_SUCCESS(rv, rv);
if (!nearNode) {
return NS_OK;
}
EditorDOMPoint pt = GetGoodSelPointForNode(*nearNode, aAction);
- rv = aSelection->Collapse(pt.Container(), pt.Offset());
+ rv = aSelection->Collapse(pt.AsRaw());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1081,20 +1081,28 @@ HTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode
int32_t selOffset;
nsresult rv =
GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateBR(selNode, selOffset, outBRNode);
NS_ENSURE_SUCCESS(rv, rv);
+ selection->SetInterlinePosition(true);
+
// position selection after br
- selNode = GetNodeLocation(*outBRNode, &selOffset);
- selection->SetInterlinePosition(true);
- return selection->Collapse(selNode, selOffset+1);
+ nsCOMPtr<nsINode> brNode = do_QueryInterface(*outBRNode);
+ if (NS_WARN_IF(!brNode)) {
+ return NS_ERROR_FAILURE;
+ }
+ EditorRawDOMPoint afterBrNode(brNode);
+ if (NS_WARN_IF(!afterBrNode.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ return selection->Collapse(afterBrNode);
}
void
HTMLEditor::CollapseSelectionToDeepestNonTableFirstChild(Selection* aSelection,
nsINode* aNode)
{
MOZ_ASSERT(aNode);
@@ -1687,19 +1695,22 @@ HTMLEditor::SetCaretAfterElement(nsIDOME
}
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMNode>parent;
nsresult rv = aElement->GetParentNode(getter_AddRefs(parent));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
- int32_t offsetInParent = GetChildOffset(aElement, parent);
// Collapse selection to just after desired element,
- return selection->Collapse(parent, offsetInParent + 1);
+ EditorRawDOMPoint afterElement(element);
+ if (NS_WARN_IF(!afterElement.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ return selection->Collapse(afterElement);
}
NS_IMETHODIMP
HTMLEditor::SetParagraphFormat(const nsAString& aParagraphFormat)
{
nsAutoString tag; tag.Assign(aParagraphFormat);
ToLowerCase(tag);
if (tag.EqualsLiteral("dd") || tag.EqualsLiteral("dt")) {
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -13,16 +13,17 @@
#include "WSRunObject.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DOMStringList.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Base64.h"
#include "mozilla/BasicEvents.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/Preferences.h"
#include "mozilla/SelectionState.h"
#include "nsAString.h"
#include "nsCOMPtr.h"
#include "nsCRTGlue.h" // for CRLF
#include "nsComponentManagerUtils.h"
@@ -652,18 +653,20 @@ HTMLEditor::DoInsertHTMLWithContext(cons
nsCOMPtr<nsIContent> linkContent = do_QueryInterface(link);
NS_ENSURE_STATE(linkContent || !link);
nsCOMPtr<nsIContent> selContent = do_QueryInterface(selNode);
NS_ENSURE_STATE(selContent || !selNode);
nsCOMPtr<nsIContent> leftLink;
SplitNodeDeep(*linkContent, *selContent, selOffset,
EmptyContainers::no, getter_AddRefs(leftLink));
if (leftLink) {
- selNode = GetNodeLocation(GetAsDOMNode(leftLink), &selOffset);
- selection->Collapse(selNode, selOffset+1);
+ EditorRawDOMPoint afterLeftLink(leftLink);
+ if (afterLeftLink.AdvanceOffset()) {
+ selection->Collapse(afterLeftLink);
+ }
}
}
}
}
return rules->DidDoAction(selection, &ruleInfo, rv);
}
@@ -1893,20 +1896,19 @@ HTMLEditor::InsertAsPlaintextQuotation(c
if (aNodeInserted && NS_SUCCEEDED(rv)) {
*aNodeInserted = GetAsDOMNode(newNode);
NS_IF_ADDREF(*aNodeInserted);
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && newNode) {
- nsCOMPtr<nsINode> parent = newNode->GetParentNode();
- int32_t offset = parent ? parent->IndexOf(newNode) : -1;
- if (parent) {
- selection->Collapse(parent, offset + 1);
+ EditorRawDOMPoint afterNewNode(newNode);
+ if (afterNewNode.AdvanceOffset()) {
+ selection->Collapse(afterNewNode);
}
}
return rv;
}
NS_IMETHODIMP
HTMLEditor::StripCites()
{
@@ -1973,20 +1975,19 @@ HTMLEditor::InsertAsCitedQuotation(const
if (aNodeInserted && NS_SUCCEEDED(rv)) {
*aNodeInserted = GetAsDOMNode(newNode);
NS_IF_ADDREF(*aNodeInserted);
}
// Set the selection to just after the inserted node:
if (NS_SUCCEEDED(rv) && newNode) {
- nsCOMPtr<nsINode> parent = newNode->GetParentNode();
- int32_t offset = parent ? parent->IndexOf(newNode) : -1;
- if (parent) {
- selection->Collapse(parent, offset + 1);
+ EditorRawDOMPoint afterNewNode(newNode);
+ if (afterNewNode.AdvanceOffset()) {
+ selection->Collapse(afterNewNode);
}
}
return rv;
}
void RemoveBodyAndHead(nsINode& aNode)
{
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include "mozilla/HTMLEditor.h"
#include "HTMLEditUtils.h"
#include "mozilla/Assertions.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/FlushType.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/Element.h"
#include "nsAString.h"
#include "nsAlgorithm.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
@@ -3152,18 +3153,25 @@ HTMLEditor::SetSelectionAfterTableEdit(n
}
} while (!done);
// We didn't find a cell
// Set selection to just before the table
nsCOMPtr<nsIDOMNode> tableParent;
nsresult rv = aTable->GetParentNode(getter_AddRefs(tableParent));
if (NS_SUCCEEDED(rv) && tableParent) {
- int32_t tableOffset = GetChildOffset(aTable, tableParent);
- selection->Collapse(tableParent, tableOffset);
+ nsCOMPtr<nsIContent> table = do_QueryInterface(aTable);
+ if (NS_WARN_IF(!table)) {
+ return;
+ }
+ EditorRawDOMPoint atTable(table);
+ if (NS_WARN_IF(!atTable.IsSetAndValid())) {
+ return;
+ }
+ selection->Collapse(atTable);
return;
}
// Last resort: Set selection to start of doc
// (it's very bad to not have a valid selection!)
SetSelectionAtDocumentStart(selection);
}
NS_IMETHODIMP
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/TextEditRules.h"
#include "TextEditUtils.h"
#include "mozilla/Assertions.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextComposition.h"
#include "mozilla/TextEditor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/NodeIterator.h"
#include "mozilla/dom/Selection.h"
@@ -489,18 +490,21 @@ TextEditRules::CollapseSelectionToTraili
}
nsINode* parentNode = selNode->GetParentNode();
if (parentNode != root) {
return NS_OK;
}
nsINode* nextNode = selNode->GetNextSibling();
if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
- int32_t offsetInParent = EditorBase::GetChildOffset(selNode, parentNode);
- rv = aSelection->Collapse(parentNode, offsetInParent + 1);
+ EditorRawDOMPoint afterSelNode(selNode);
+ if (NS_WARN_IF(!afterSelNode.AdvanceOffset())) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = aSelection->Collapse(afterSelNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
static inline already_AddRefed<nsINode>
@@ -773,16 +777,18 @@ TextEditRules::WillInsertText(EditAction
if (curNode) {
// Make the caret attach to the inserted text, unless this text ends with a LF,
// in which case make the caret attach to the next line.
bool endsWithLF =
!outString->IsEmpty() && outString->Last() == nsCRT::LF;
aSelection->SetInterlinePosition(endsWithLF);
+ MOZ_ASSERT(!selChild,
+ "After inserting text into a text node, selChild should be nullptr");
aSelection->Collapse(curNode, curOffset);
}
}
ASSERT_PASSWORD_LENGTHS_EQUAL()
return NS_OK;
}
nsresult
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/TextEditor.h"
#include "InternetCiter.h"
#include "TextEditUtils.h"
#include "gfxFontUtils.h"
#include "mozilla/Assertions.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h" // AutoPlaceholderBatch, AutoRules
#include "mozilla/HTMLEditor.h"
#include "mozilla/mozalloc.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextEditRules.h"
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Selection.h"
@@ -471,29 +472,34 @@ TextEditor::CreateBRImpl(nsCOMPtr<nsIDOM
if (NS_WARN_IF(!brNode)) {
return NS_ERROR_FAILURE;
}
(*aInOutOffset)++;
}
*outBRNode = GetAsDOMNode(brNode);
if (*outBRNode && (aSelect != eNone)) {
- int32_t offset;
- nsCOMPtr<nsINode> parent = GetNodeLocation(brNode, &offset);
-
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_STATE(selection);
if (aSelect == eNext) {
+ selection->SetInterlinePosition(true);
// position selection after br
- selection->SetInterlinePosition(true);
- selection->Collapse(parent, offset + 1);
+ EditorRawDOMPoint afterBrNode(brNode);
+ if (NS_WARN_IF(!afterBrNode.AdvanceOffset())) {
+ return NS_OK;
+ }
+ selection->Collapse(afterBrNode);
} else if (aSelect == ePrevious) {
+ selection->SetInterlinePosition(true);
// position selection before br
- selection->SetInterlinePosition(true);
- selection->Collapse(parent, offset);
+ EditorRawDOMPoint atBrNode(brNode);
+ if (NS_WARN_IF(!atBrNode.IsSetAndValid())) {
+ return NS_OK;
+ }
+ selection->Collapse(atBrNode);
}
}
return NS_OK;
}
NS_IMETHODIMP
TextEditor::CreateBR(nsIDOMNode* aNode,
@@ -724,17 +730,19 @@ TextEditor::InsertLineBreak()
// insert a linefeed character
rv = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
address_of(selChild), &selOffset, doc);
if (!selNode) {
rv = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
}
if (NS_SUCCEEDED(rv)) {
// set the selection to the correct location
- rv = selection->Collapse(selNode, selOffset);
+ MOZ_ASSERT(!selChild,
+ "After inserting text into a text node, selChild should be nullptr");
+ rv = selection->Collapse(EditorRawDOMPoint(selNode, selOffset));
if (NS_SUCCEEDED(rv)) {
// see if we're at the end of the editor range
nsCOMPtr<nsIDOMNode> endNode;
int32_t endOffset;
rv = GetEndNodeAndOffset(selection,
getter_AddRefs(endNode), &endOffset);
if (NS_SUCCEEDED(rv) &&