Commit 44969eec authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1740872 - part 1: Move `EditorBase::CreateElementWithTransaction()` 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
parent a916f856
Loading
Loading
Loading
Loading
+19 −18
Original line number Diff line number Diff line
@@ -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"

@@ -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.
@@ -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)
@@ -94,16 +95,16 @@ 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;
  }

@@ -111,10 +112,10 @@ NS_IMETHODIMP CreateElementTransaction::DoTransaction() {
  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;
@@ -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;
  }
@@ -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;
  }
+10 −9
Original line number Diff line number Diff line
@@ -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"
@@ -22,21 +23,21 @@ 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
@@ -44,7 +45,7 @@ class CreateElementTransaction final : public EditTransactionBase {
   */
  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
@@ -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;
+0 −71
Original line number Diff line number Diff line
@@ -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
@@ -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);
+0 −18
Original line number Diff line number Diff line
@@ -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.
   *
+2 −1
Original line number Diff line number Diff line
@@ -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
Loading