Bug 1413181 - part 13: HTMLEditRules::MaybeSplitAncestorsForInsert() should be able to return a DOM point in text node r?m_kato
HTMLEditRules::MaybeSplitAncestorsForInsert() may be called with a point in a
text and it needs to return given split point as is. Additionally, the given
point may be in a text node. So, it may not be represented with an
nsCOMPtr<nsIContent>.
Therefore, we need to add new member, EditorDOMPoint, to SplitNodeResult and
when MaybeSplitAncestorsForInsert() needs to return the given point as is,
it should use it.
Note that if the methods which return SplitNodeResult split some nodes actually,
the left node and/or the right node may be removed from the DOM tree. In this
case, EditorDOMPoint cannot store such orphan node. Therefore, we cannot
make mNextNode nor mPreviousNode EditorDOMPoint.
MozReview-Commit-ID: LwH8RZzkrmT
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -170,43 +170,63 @@ public:
}
/**
* GetRightNode() simply returns the right node which was split.
* This won't return nullptr unless failed to split due to invalid arguments.
*/
nsIContent* GetRightNode() const
{
+ if (mGivenSplitPoint.IsSet()) {
+ return mGivenSplitPoint.GetChildAtOffset();
+ }
return mPreviousNode && !mNextNode ? mPreviousNode : mNextNode;
}
/**
* GetPreviousNode() returns previous node at the split point.
*/
- nsIContent* GetPreviousNode() const { return mPreviousNode; }
+ nsIContent* GetPreviousNode() const
+ {
+ if (mGivenSplitPoint.IsSet()) {
+ return mGivenSplitPoint.IsEndOfContainer() ?
+ mGivenSplitPoint.GetChildAtOffset() : nullptr;
+ }
+ return mPreviousNode;
+ }
/**
* GetNextNode() returns next node at the split point.
*/
- nsIContent* GetNextNode() const { return mNextNode; }
+ nsIContent* GetNextNode() const
+ {
+ if (mGivenSplitPoint.IsSet()) {
+ return !mGivenSplitPoint.IsEndOfContainer() ?
+ mGivenSplitPoint.GetChildAtOffset() : nullptr;
+ }
+ return mNextNode;
+ }
/**
* SplitPoint() returns the split point in the container.
* This is useful when callers insert an element at split point with
* EditorBase::CreateNode() or something similar methods.
*
* Note that the result is EditorRawDOMPoint but the nodes are grabbed
* by this instance. Therefore, the life time of both container node
* and child node are guaranteed while using the result temporarily.
*/
EditorRawDOMPoint SplitPoint() const
{
if (Failed()) {
return EditorRawDOMPoint();
}
+ if (mGivenSplitPoint.IsSet()) {
+ return mGivenSplitPoint.AsRaw();
+ }
if (!mPreviousNode) {
return EditorRawDOMPoint(mNextNode);
}
EditorRawDOMPoint point(mPreviousNode);
DebugOnly<bool> advanced = point.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset to after previous node");
return point;
@@ -226,29 +246,53 @@ public:
: mPreviousNode(aPreviousNodeOfSplitPoint)
, mNextNode(aNextNodeOfSplitPoint)
, mRv(NS_OK)
{
MOZ_DIAGNOSTIC_ASSERT(mPreviousNode || mNextNode);
}
/**
+ * This constructor should be used when the method didn't split any nodes
+ * but want to return given split point as right point.
+ */
+ explicit SplitNodeResult(const EditorRawDOMPoint& aGivenSplitPoint)
+ : mGivenSplitPoint(aGivenSplitPoint)
+ , mRv(NS_OK)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(mGivenSplitPoint.IsSet());
+ }
+
+ /**
* This constructor shouldn't be used by anybody except methods which
* use this as error result when it fails.
*/
explicit SplitNodeResult(nsresult aRv)
: mRv(aRv)
{
MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
}
private:
+ // When methods which return this class split some nodes actually, they
+ // need to set a set of left node and right node to this class. However,
+ // one or both of them may be moved or removed by mutation observer.
+ // In such case, we cannot represent the point with EditorDOMPoint since
+ // it requires current container node. Therefore, we need to use
+ // nsCOMPtr<nsIContent> here instead.
nsCOMPtr<nsIContent> mPreviousNode;
nsCOMPtr<nsIContent> mNextNode;
+ // Methods which return this class may not split any nodes actually. Then,
+ // they may want to return given split point as is since such behavior makes
+ // their callers simpler. In this case, the point may be in a text node
+ // which cannot be represented as a node. Therefore, we need EditorDOMPoint
+ // for representing the point.
+ EditorDOMPoint mGivenSplitPoint;
+
nsresult mRv;
SplitNodeResult() = delete;
};
/***************************************************************************
* stack based helper class for batching a collection of transactions inside a
* placeholder transaction.
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -7535,20 +7535,20 @@ HTMLEditRules::MaybeSplitAncestorsForIns
// Found an ancestor node which can contain the element.
break;
}
}
MOZ_DIAGNOSTIC_ASSERT(pointToInsert.IsSet());
// If the point itself can contain the tag, we don't need to split any
- // ancestor nodes.
+ // ancestor nodes. In this case, we should return the given split point
+ // as is.
if (pointToInsert.Container() == aStartOfDeepestRightNode.Container()) {
- return SplitNodeResult(nullptr,
- aStartOfDeepestRightNode.GetChildAtOffset());
+ return SplitNodeResult(aStartOfDeepestRightNode);
}
SplitNodeResult splitNodeResult =
htmlEditor->SplitNodeDeep(*pointToInsert.GetChildAtOffset(),
aStartOfDeepestRightNode,
SplitAtEdges::eAllowToCreateEmptyContainer);
NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
"Failed to split the node for insert the element");