Skip to content

Commit

Permalink
Bug 1740872 - part 1: Move `EditorBase::CreateElementWithTransaction(…
Browse files Browse the repository at this point in the history
…)` into `HTMLEditor` r=m_kato

I realized that it's now used only by `HTMLEditor` so that we can move it
into `HTMLEditor` and we can make `CreateElementTransaction` treat `HTMLEditor`
directly rather than via `EditorBase`.

Differential Revision: https://phabricator.services.mozilla.com/D131198
  • Loading branch information
masayuki-nakano committed Nov 17, 2021
1 parent a52bf0c commit 7ca8dae
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 204 deletions.
37 changes: 19 additions & 18 deletions editor/libeditor/CreateElementTransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
#include <algorithm>
#include <stdio.h>

#include "EditorDOMPoint.h"
#include "HTMLEditor.h"

#include "mozilla/dom/Element.h"
#include "mozilla/dom/Selection.h"

#include "mozilla/Casting.h"
#include "mozilla/EditorBase.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/Logging.h"
#include "mozilla/ToString.h"

Expand All @@ -36,28 +37,28 @@ namespace mozilla {
using namespace dom;

template already_AddRefed<CreateElementTransaction>
CreateElementTransaction::Create(EditorBase& aEditorBase, nsAtom& aTag,
CreateElementTransaction::Create(HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorDOMPoint& aPointToInsert);
template already_AddRefed<CreateElementTransaction>
CreateElementTransaction::Create(EditorBase& aEditorBase, nsAtom& aTag,
CreateElementTransaction::Create(HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorRawDOMPoint& aPointToInsert);

template <typename PT, typename CT>
already_AddRefed<CreateElementTransaction> CreateElementTransaction::Create(
EditorBase& aEditorBase, nsAtom& aTag,
HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorDOMPointBase<PT, CT>& aPointToInsert) {
RefPtr<CreateElementTransaction> transaction =
new CreateElementTransaction(aEditorBase, aTag, aPointToInsert);
new CreateElementTransaction(aHTMLEditor, aTagName, aPointToInsert);
return transaction.forget();
}

template <typename PT, typename CT>
CreateElementTransaction::CreateElementTransaction(
EditorBase& aEditorBase, nsAtom& aTag,
HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorDOMPointBase<PT, CT>& aPointToInsert)
: EditTransactionBase(),
mEditorBase(&aEditorBase),
mTag(&aTag),
mHTMLEditor(&aHTMLEditor),
mTag(&aTagName),
mPointToInsert(aPointToInsert) {
MOZ_ASSERT(!mPointToInsert.IsInDataNode());
// We only need the child node at inserting new node.
Expand All @@ -76,12 +77,12 @@ std::ostream& operator<<(std::ostream& aStream,
if (aTransaction.mNewElement) {
aStream << " (" << *aTransaction.mNewElement << ")";
}
aStream << ", mEditorBase=" << aTransaction.mEditorBase.get() << " }";
aStream << ", mHTMLEditor=" << aTransaction.mHTMLEditor.get() << " }";
return aStream;
}

NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
EditTransactionBase, mEditorBase,
EditTransactionBase, mHTMLEditor,
mPointToInsert, mNewElement)

NS_IMPL_ADDREF_INHERITED(CreateElementTransaction, EditTransactionBase)
Expand All @@ -94,27 +95,27 @@ NS_IMETHODIMP CreateElementTransaction::DoTransaction() {
("%p CreateElementTransaction::%s this=%s", this, __FUNCTION__,
ToString(*this).c_str()));

if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) ||
if (NS_WARN_IF(!mHTMLEditor) || NS_WARN_IF(!mTag) ||
NS_WARN_IF(!mPointToInsert.IsSet())) {
return NS_ERROR_NOT_INITIALIZED;
}

OwningNonNull<EditorBase> editorBase = *mEditorBase;
OwningNonNull<HTMLEditor> editorBase = *mHTMLEditor;

mNewElement = editorBase->CreateHTMLContent(mTag);
if (!mNewElement) {
NS_WARNING("EditorBase::CreateHTMLContent() failed");
NS_WARNING("HTMLEditor::CreateHTMLContent() failed");
return NS_ERROR_FAILURE;
}

// Try to insert formatting white-space for the new node:
OwningNonNull<Element> newElement = *mNewElement;
nsresult rv = editorBase->MarkElementDirty(newElement);
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return EditorBase::ToGenericNSResult(rv);
return HTMLEditor::ToGenericNSResult(rv);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::MarkElementDirty() failed, but ignored");
"HTMLEditor::MarkElementDirty() failed, but ignored");

// Insert the new node
ErrorResult error;
Expand Down Expand Up @@ -201,7 +202,7 @@ NS_IMETHODIMP CreateElementTransaction::UndoTransaction() {
("%p CreateElementTransaction::%s this=%s", this, __FUNCTION__,
ToString(*this).c_str()));

if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
if (NS_WARN_IF(!mHTMLEditor) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
NS_WARN_IF(!mNewElement)) {
return NS_ERROR_NOT_AVAILABLE;
}
Expand All @@ -219,7 +220,7 @@ NS_IMETHODIMP CreateElementTransaction::RedoTransaction() {
("%p CreateElementTransaction::%s this=%s", this, __FUNCTION__,
ToString(*this).c_str()));

if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
if (NS_WARN_IF(!mHTMLEditor) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
NS_WARN_IF(!mNewElement)) {
return NS_ERROR_NOT_AVAILABLE;
}
Expand Down
19 changes: 10 additions & 9 deletions editor/libeditor/CreateElementTransaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
#ifndef CreateElementTransaction_h
#define CreateElementTransaction_h

#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditTransactionBase.h"
#include "EditorDOMPoint.h"
#include "EditTransactionBase.h"

#include "mozilla/RefPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupportsImpl.h"
Expand All @@ -22,29 +23,29 @@ namespace dom {
class Element;
}

class EditorBase;
class HTMLEditor;

class CreateElementTransaction final : public EditTransactionBase {
protected:
template <typename PT, typename CT>
CreateElementTransaction(EditorBase& aEditorBase, nsAtom& aTag,
CreateElementTransaction(HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorDOMPointBase<PT, CT>& aPointToInsert);

public:
/**
* Create a transaction for creating a new child node of the container of
* aPointToInsert of type aTag.
* aPointToInsert of type aTagName.
*
* @param aEditorBase The editor which manages the transaction.
* @param aTag The tag (P, HR, TABLE, etc.) for the new element.
* @param aHTMLEditor The editor which manages the transaction.
* @param aTagName The tag (P, HR, TABLE, etc.) for the new element.
* @param aPointToInsert The new node will be inserted before the child at
* aPointToInsert. If this refers end of the container
* or after, the new node will be appended to the
* container.
*/
template <typename PT, typename CT>
static already_AddRefed<CreateElementTransaction> Create(
EditorBase& aEditorBase, nsAtom& aTag,
HTMLEditor& aHTMLEditor, nsAtom& aTagName,
const EditorDOMPointBase<PT, CT>& aPointToInsert);

NS_DECL_ISUPPORTS_INHERITED
Expand All @@ -70,7 +71,7 @@ class CreateElementTransaction final : public EditTransactionBase {
MOZ_CAN_RUN_SCRIPT void InsertNewNode(ErrorResult& aError);

// The document into which the new node will be inserted.
RefPtr<EditorBase> mEditorBase;
RefPtr<HTMLEditor> mHTMLEditor;

// The tag (mapping to object type) for the new element.
RefPtr<nsAtom> mTag;
Expand Down
71 changes: 0 additions & 71 deletions editor/libeditor/EditorBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include "ChangeAttributeTransaction.h" // for ChangeAttributeTransaction
#include "CompositionTransaction.h" // for CompositionTransaction
#include "CreateElementTransaction.h" // for CreateElementTransaction
#include "DeleteNodeTransaction.h" // for DeleteNodeTransaction
#include "DeleteRangeTransaction.h" // for DeleteRangeTransaction
#include "DeleteTextTransaction.h" // for DeleteTextTransaction
Expand Down Expand Up @@ -1994,76 +1993,6 @@ NS_IMETHODIMP EditorBase::SetSpellcheckUserOverride(bool enable) {
return NS_OK;
}

Result<RefPtr<Element>, nsresult> EditorBase::CreateNodeWithTransaction(
nsAtom& aTagName, const EditorDOMPoint& aPointToInsert) {
MOZ_ASSERT(IsEditActionDataAvailable());
MOZ_ASSERT(aPointToInsert.IsSetAndValid());

// XXX We need offset at new node for RangeUpdaterRef(). Therefore, we need
// to compute the offset now but this is expensive. So, if it's possible,
// we need to redesign RangeUpdaterRef() as avoiding using indices.
Unused << aPointToInsert.Offset();

IgnoredErrorResult ignoredError;
AutoEditSubActionNotifier startToHandleEditSubAction(
*this, EditSubAction::eCreateNode, nsIEditor::eNext, ignoredError);
if (NS_WARN_IF(ignoredError.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
return Err(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(
!ignoredError.Failed(),
"TextEditor::OnStartToHandleTopLevelEditSubAction() failed, but ignored");

RefPtr<Element> newElement;

RefPtr<CreateElementTransaction> transaction =
CreateElementTransaction::Create(*this, aTagName, aPointToInsert);
nsresult rv = DoTransactionInternal(transaction);
if (NS_WARN_IF(Destroyed())) {
rv = NS_ERROR_EDITOR_DESTROYED;
} else if (transaction->GetNewElement() &&
transaction->GetNewElement()->GetParentNode() !=
aPointToInsert.GetContainer()) {
NS_WARNING("The new element was not inserted into the expected node");
rv = NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
}
if (NS_FAILED(rv)) {
NS_WARNING("EditorBase::DoTransactionInternal() failed");
// XXX Why do we do this even when DoTransaction() returned error?
DebugOnly<nsresult> rvIgnored =
RangeUpdaterRef().SelAdjCreateNode(aPointToInsert);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"Rangeupdater::SelAdjCreateNode() failed, but ignored");
} else {
newElement = transaction->GetNewElement();
MOZ_ASSERT(newElement);

// If we succeeded to create and insert new element, we need to adjust
// ranges in RangeUpdaterRef(). It currently requires offset of the new
// node. So, let's call it with original offset. Note that if
// aPointToInsert stores child node, it may not be at the offset since new
// element must be inserted before the old child. Although, mutation
// observer can do anything, but currently, we don't check it.
DebugOnly<nsresult> rvIgnored =
RangeUpdaterRef().SelAdjCreateNode(EditorRawDOMPoint(
aPointToInsert.GetContainer(), aPointToInsert.Offset()));
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rvIgnored),
"Rangeupdater::SelAdjCreateNode() failed, but ignored");
}

if (IsHTMLEditor() && newElement) {
TopLevelEditSubActionDataRef().DidCreateElement(*this, *newElement);
}

if (NS_FAILED(rv)) {
return Err(rv);
}

return newElement;
}

NS_IMETHODIMP EditorBase::InsertNode(nsINode* aNodeToInsert,
nsINode* aContainer, uint32_t aOffset) {
nsCOMPtr<nsIContent> contentToInsert = do_QueryInterface(aNodeToInsert);
Expand Down
18 changes: 0 additions & 18 deletions editor/libeditor/EditorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1822,24 +1822,6 @@ class EditorBase : public nsIEditor,
const nsAString& aStringToSet,
ErrorResult& aRv);

/**
* Create an element node whose name is aTag at before aPointToInsert. When
* this succeed to create an element node, this sets aPointToInsert to the
* new element because the relation of child and offset may be broken.
* If the caller needs to collapse the selection to next to the new element
* node, it should call |aPointToInsert.AdvanceOffset()| after calling this.
*
* @param aTag The element name to create.
* @param aPointToInsert The insertion point of new element. If this refers
* end of the container or after, the transaction
* will append the element to the container.
* Otherwise, will insert the element before the
* child node referred by this.
* @return The created new element node or an error.
*/
MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
CreateNodeWithTransaction(nsAtom& aTag, const EditorDOMPoint& aPointToInsert);

/**
* DeleteTextWithTransaction() removes text in the range from aTextNode.
*
Expand Down
3 changes: 2 additions & 1 deletion editor/libeditor/HTMLEditHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ class MOZ_STACK_CLASS SplitNodeResult final {
/**
* SplitPoint() returns the split point in the container.
* This is useful when callers insert an element at split point with
* EditorBase::CreateNodeWithTransaction() or something similar methods.
* HTMLEditor::CreateAndInsertElementWithTransaction() 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
Expand Down
Loading

0 comments on commit 7ca8dae

Please sign in to comment.