Bug 1425091 - Part 3. SelAdjCreateNode and SelAdjInsertNode should check whether valid point. r?masayuki
This crashtest case hits assertion in SelAdjInsertNode due to invalid offset
point. So we check whether this is valid.
Also, SelAdjCreateNode and SelAdjInsertNode should use EditorRawDOMPoint to avoid offset calculation and check valid offset.
MozReview-Commit-ID: A1kaKEzc36e
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1444,20 +1444,20 @@ EditorBase::CreateNode(nsAtom* aTag,
CreateElementTransaction::Create(*this, *aTag, pointToInsert);
nsresult rv = DoTransaction(transaction);
if (NS_SUCCEEDED(rv)) {
ret = transaction->GetNewNode();
MOZ_ASSERT(ret);
// Now, aPointToInsert may be invalid. I.e., GetChild() keeps
// referring the next sibling of new node but Offset() refers the
// new node. Let's make refer the new node.
- pointToInsert.Set(ret);
- }
-
- mRangeUpdater.SelAdjCreateNode(pointToInsert.GetContainer(), offset);
+ pointToInsert.Set(ret, offset);
+ }
+
+ mRangeUpdater.SelAdjCreateNode(pointToInsert.AsRaw());
{
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidCreateNode(nsDependentAtomString(aTag),
GetAsDOMNode(ret), rv);
}
}
@@ -1503,18 +1503,17 @@ EditorBase::InsertNode(nsIContent& aCont
GetAsDOMNode(aPointToInsert.GetNextSiblingOfChild()));
}
}
RefPtr<InsertNodeTransaction> transaction =
InsertNodeTransaction::Create(*this, aContentToInsert, aPointToInsert);
nsresult rv = DoTransaction(transaction);
- mRangeUpdater.SelAdjInsertNode(aPointToInsert.GetContainer(),
- aPointToInsert.Offset());
+ mRangeUpdater.SelAdjInsertNode(aPointToInsert.AsRaw());
{
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidInsertNode(aContentToInsert.AsDOMNode(), rv);
}
}
--- a/editor/libeditor/SelectionState.cpp
+++ b/editor/libeditor/SelectionState.cpp
@@ -208,48 +208,51 @@ RangeUpdater::DropSelectionState(Selecti
}
return NS_OK;
}
// gravity methods:
nsresult
-RangeUpdater::SelAdjCreateNode(nsINode* aParent,
- int32_t aPosition)
+RangeUpdater::SelAdjCreateNode(const EditorRawDOMPoint& aPoint)
{
if (mLock) {
// lock set by Will/DidReplaceParent, etc...
return NS_OK;
}
- NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
size_t count = mArray.Length();
if (!count) {
return NS_OK;
}
+ if (NS_WARN_IF(!aPoint.IsSetAndValid())) {
+ return NS_ERROR_FAILURE;
+ }
+
for (size_t i = 0; i < count; i++) {
RangeItem* item = mArray[i];
NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
- if (item->mStartContainer == aParent && item->mStartOffset > aPosition) {
+ if (item->mStartContainer == aPoint.GetContainer() &&
+ item->mStartOffset > static_cast<int32_t>(aPoint.Offset())) {
item->mStartOffset++;
}
- if (item->mEndContainer == aParent && item->mEndOffset > aPosition) {
+ if (item->mEndContainer == aPoint.GetContainer() &&
+ item->mEndOffset > static_cast<int32_t>(aPoint.Offset())) {
item->mEndOffset++;
}
}
return NS_OK;
}
nsresult
-RangeUpdater::SelAdjInsertNode(nsINode* aParent,
- int32_t aPosition)
+RangeUpdater::SelAdjInsertNode(const EditorRawDOMPoint& aPoint)
{
- return SelAdjCreateNode(aParent, aPosition);
+ return SelAdjCreateNode(aPoint);
}
void
RangeUpdater::SelAdjDeleteNode(nsINode* aNode)
{
if (mLock) {
// lock set by Will/DidReplaceParent, etc...
return;
@@ -315,18 +318,17 @@ RangeUpdater::SelAdjSplitNode(nsIContent
}
size_t count = mArray.Length();
if (!count) {
return NS_OK;
}
EditorRawDOMPoint atLeftNode(aNewLeftNode);
- nsresult rv =
- SelAdjInsertNode(atLeftNode.GetContainer(), atLeftNode.Offset());
+ nsresult rv = SelAdjInsertNode(atLeftNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// If point in the ranges is in left node, change its container to the left
// node. If point in the ranges is in right node, subtract numbers of
// children moved to left node from the offset.
int32_t lengthOfLeftNode = aNewLeftNode->Length();
--- a/editor/libeditor/SelectionState.h
+++ b/editor/libeditor/SelectionState.h
@@ -104,18 +104,18 @@ public:
nsresult RegisterSelectionState(SelectionState& aSelState);
nsresult DropSelectionState(SelectionState& aSelState);
// editor selection gravity routines. Note that we can't always depend on
// DOM Range gravity to do what we want to the "real" selection. For instance,
// if you move a node, that corresponds to deleting it and reinserting it.
// DOM Range gravity will promote the selection out of the node on deletion,
// which is not what you want if you know you are reinserting it.
- nsresult SelAdjCreateNode(nsINode* aParent, int32_t aPosition);
- nsresult SelAdjInsertNode(nsINode* aParent, int32_t aPosition);
+ nsresult SelAdjCreateNode(const EditorRawDOMPoint& aPoint);
+ nsresult SelAdjInsertNode(const EditorRawDOMPoint& aPoint);
void SelAdjDeleteNode(nsINode* aNode);
nsresult SelAdjSplitNode(nsIContent& aRightNode, nsIContent* aNewLeftNode);
nsresult SelAdjJoinNodes(nsINode& aLeftNode,
nsINode& aRightNode,
nsINode& aParent,
int32_t aOffset,
int32_t aOldLeftNodeLength);
void SelAdjInsertText(dom::Text& aTextNode, int32_t aOffset,