Bug 1619914 - part 1: Make each transaction class grab their members with local variable before touching the DOM tree r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D69302
This commit is contained in:
@@ -18,32 +18,32 @@ namespace mozilla {
|
||||
using namespace dom;
|
||||
|
||||
template already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
|
||||
EditorBase& aEditorBase, const EditorDOMPoint& aStartOfRightNode);
|
||||
EditorBase& aEditorBase, const EditorDOMPoint& aStartOfRightContent);
|
||||
template already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
|
||||
EditorBase& aEditorBase, const EditorRawDOMPoint& aStartOfRightNode);
|
||||
EditorBase& aEditorBase, const EditorRawDOMPoint& aStartOfRightContent);
|
||||
|
||||
// static
|
||||
template <typename PT, typename CT>
|
||||
already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
|
||||
EditorBase& aEditorBase,
|
||||
const EditorDOMPointBase<PT, CT>& aStartOfRightNode) {
|
||||
const EditorDOMPointBase<PT, CT>& aStartOfRightContent) {
|
||||
RefPtr<SplitNodeTransaction> transaction =
|
||||
new SplitNodeTransaction(aEditorBase, aStartOfRightNode);
|
||||
new SplitNodeTransaction(aEditorBase, aStartOfRightContent);
|
||||
return transaction.forget();
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
SplitNodeTransaction::SplitNodeTransaction(
|
||||
EditorBase& aEditorBase,
|
||||
const EditorDOMPointBase<PT, CT>& aStartOfRightNode)
|
||||
: mEditorBase(&aEditorBase), mStartOfRightNode(aStartOfRightNode) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStartOfRightNode.IsSet());
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStartOfRightNode.GetContainerAsContent());
|
||||
const EditorDOMPointBase<PT, CT>& aStartOfRightContent)
|
||||
: mEditorBase(&aEditorBase), mStartOfRightContent(aStartOfRightContent) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStartOfRightContent.IsSet());
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStartOfRightContent.GetContainerAsContent());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
|
||||
mEditorBase, mStartOfRightNode, mParent,
|
||||
mNewLeftNode)
|
||||
mEditorBase, mStartOfRightContent,
|
||||
mContainerParentNode, mNewLeftContent)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(SplitNodeTransaction, EditTransactionBase)
|
||||
NS_IMPL_RELEASE_INHERITED(SplitNodeTransaction, EditTransactionBase)
|
||||
@@ -52,16 +52,16 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
|
||||
SplitNodeTransaction::DoTransaction() {
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mStartOfRightNode.IsSet())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mStartOfRightContent.IsSet())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
MOZ_ASSERT(mStartOfRightNode.IsSetAndValid());
|
||||
MOZ_ASSERT(mStartOfRightContent.IsSetAndValid());
|
||||
|
||||
// Create a new node
|
||||
ErrorResult error;
|
||||
// Don't use .downcast directly because AsContent has an assertion we want
|
||||
nsCOMPtr<nsINode> cloneOfRightContainer =
|
||||
mStartOfRightNode.GetContainer()->CloneNode(false, error);
|
||||
mStartOfRightContent.GetContainer()->CloneNode(false, error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("nsINode::CloneNode() failed");
|
||||
return error.StealNSResult();
|
||||
@@ -70,11 +70,21 @@ SplitNodeTransaction::DoTransaction() {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
RefPtr<EditorBase> editorBase(mEditorBase);
|
||||
mNewLeftContent = cloneOfRightContainer->AsContent();
|
||||
|
||||
mContainerParentNode = mStartOfRightContent.GetContainerParent();
|
||||
if (!mContainerParentNode) {
|
||||
NS_WARNING("Right container was an orphan node");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<nsIContent> newLeftContent = *mNewLeftContent;
|
||||
OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
|
||||
EditorDOMPoint startOfRightContent(mStartOfRightContent);
|
||||
|
||||
mNewLeftNode = cloneOfRightContainer->AsContent();
|
||||
if (RefPtr<Element> startOfRightNode =
|
||||
mStartOfRightNode.GetContainerAsElement()) {
|
||||
startOfRightContent.GetContainerAsElement()) {
|
||||
nsresult rv = editorBase->MarkElementDirty(*startOfRightNode);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
@@ -83,17 +93,8 @@ SplitNodeTransaction::DoTransaction() {
|
||||
"EditorBase::MarkElementDirty() failed, but ignored");
|
||||
}
|
||||
|
||||
// Get the parent node
|
||||
mParent = mStartOfRightNode.GetContainerParent();
|
||||
if (!mParent) {
|
||||
NS_WARNING("Right container was an orphan node");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Insert the new node
|
||||
nsCOMPtr<nsIContent> newLeftNode = mNewLeftNode;
|
||||
editorBase->DoSplitNode(EditorDOMPoint(mStartOfRightNode), *newLeftNode,
|
||||
error);
|
||||
editorBase->DoSplitNode(startOfRightContent, newLeftContent, error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("EditorBase::DoSplitNode() failed");
|
||||
return error.StealNSResult();
|
||||
@@ -111,7 +112,7 @@ SplitNodeTransaction::DoTransaction() {
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
EditorRawDOMPoint atEndOfLeftNode(EditorRawDOMPoint::AtEndOf(mNewLeftNode));
|
||||
EditorRawDOMPoint atEndOfLeftNode(EditorRawDOMPoint::AtEndOf(newLeftContent));
|
||||
selection->Collapse(atEndOfLeftNode, error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
|
||||
return error.StealNSResult();
|
||||
@@ -119,19 +120,21 @@ SplitNodeTransaction::DoTransaction() {
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
|
||||
SplitNodeTransaction::UndoTransaction() {
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNewLeftNode) ||
|
||||
NS_WARN_IF(!mParent) || NS_WARN_IF(!mStartOfRightNode.IsSet())) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNewLeftContent) ||
|
||||
NS_WARN_IF(!mContainerParentNode) ||
|
||||
NS_WARN_IF(!mStartOfRightContent.IsSet())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// This assumes Do inserted the new node in front of the prior existing node
|
||||
// XXX Perhaps, we should reset mStartOfRightNode with current first child
|
||||
// of the right node.
|
||||
RefPtr<EditorBase> editorBase = mEditorBase;
|
||||
nsCOMPtr<nsINode> container = mStartOfRightNode.GetContainer();
|
||||
nsCOMPtr<nsINode> newLeftNode = mNewLeftNode;
|
||||
nsCOMPtr<nsINode> parent = mParent;
|
||||
nsresult rv = editorBase->DoJoinNodes(container, newLeftNode, parent);
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<nsINode> containerNode = *mStartOfRightContent.GetContainer();
|
||||
OwningNonNull<nsINode> newLeftContent = *mNewLeftContent;
|
||||
OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
|
||||
nsresult rv = editorBase->DoJoinNodes(containerNode, newLeftContent,
|
||||
containerParentNode);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
|
||||
return rv;
|
||||
}
|
||||
@@ -142,58 +145,54 @@ SplitNodeTransaction::UndoTransaction() {
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
|
||||
SplitNodeTransaction::RedoTransaction() {
|
||||
if (NS_WARN_IF(!mNewLeftNode) || NS_WARN_IF(!mParent) ||
|
||||
NS_WARN_IF(!mStartOfRightNode.IsSet()) || NS_WARN_IF(!mEditorBase)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
if (NS_WARN_IF(!mNewLeftContent) || NS_WARN_IF(!mContainerParentNode) ||
|
||||
NS_WARN_IF(!mStartOfRightContent.IsSet()) || NS_WARN_IF(!mEditorBase)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<nsINode> newLeftContent = *mNewLeftContent;
|
||||
OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
|
||||
EditorDOMPoint startOfRightContent(mStartOfRightContent);
|
||||
|
||||
// First, massage the existing node so it is in its post-split state
|
||||
ErrorResult error;
|
||||
if (mStartOfRightNode.IsInTextNode()) {
|
||||
RefPtr<EditorBase> editorBase = mEditorBase;
|
||||
RefPtr<Text> rightNodeAsText = mStartOfRightNode.GetContainerAsText();
|
||||
MOZ_DIAGNOSTIC_ASSERT(rightNodeAsText);
|
||||
editorBase->DoDeleteText(*rightNodeAsText, 0, mStartOfRightNode.Offset(),
|
||||
error);
|
||||
if (startOfRightContent.IsInTextNode()) {
|
||||
Text* rightTextNode = startOfRightContent.ContainerAsText();
|
||||
editorBase->DoDeleteText(MOZ_KnownLive(*rightTextNode), 0,
|
||||
startOfRightContent.Offset(), error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("EditorBase::DoDeleteText() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIContent> child =
|
||||
mStartOfRightNode.GetContainer()->GetFirstChild();
|
||||
nsCOMPtr<nsIContent> nextSibling;
|
||||
AutoTArray<OwningNonNull<nsIContent>, 24> movingChildren;
|
||||
if (nsIContent* child =
|
||||
startOfRightContent.GetContainer()->GetFirstChild()) {
|
||||
movingChildren.AppendElement(*child);
|
||||
for (uint32_t i = 0; i < startOfRightContent.Offset(); i++) {
|
||||
child = child->GetNextSibling();
|
||||
if (!child) {
|
||||
break;
|
||||
}
|
||||
movingChildren.AppendElement(*child);
|
||||
}
|
||||
}
|
||||
ErrorResult error;
|
||||
for (uint32_t i = 0; i < mStartOfRightNode.Offset(); i++) {
|
||||
// XXX This must be bad behavior. Perhaps, we should work with
|
||||
// mStartOfRightNode::GetChild(). Even if some children
|
||||
// before the right node have been inserted or removed, we should
|
||||
// move all children before the right node because user must focus
|
||||
// on the right node, so, it must be the expected behavior.
|
||||
if (NS_WARN_IF(!child)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
nextSibling = child->GetNextSibling();
|
||||
mStartOfRightNode.GetContainer()->RemoveChild(*child, error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("nsINode::RemoveChild() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
mNewLeftNode->AppendChild(*child, error);
|
||||
for (OwningNonNull<nsIContent>& child : movingChildren) {
|
||||
newLeftContent->AppendChild(child, error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("nsINode::AppendChild() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
child = nextSibling;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(!error.Failed());
|
||||
// Second, re-insert the left node into the tree
|
||||
mParent->InsertBefore(*mNewLeftNode, mStartOfRightNode.GetContainer(), error);
|
||||
containerParentNode->InsertBefore(newLeftContent,
|
||||
startOfRightContent.GetContainer(), error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(), "nsINode::InsertBefore() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
nsIContent* SplitNodeTransaction::GetNewNode() { return mNewLeftNode; }
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
Reference in New Issue
Block a user