Commit 68294ac1 authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1415445 - part 4: EditorBase::CreateNode() should take EditorRawDOMPoint...

Bug 1415445 - part 4: EditorBase::CreateNode() should take EditorRawDOMPoint as insertion point instead of a set of container, child and offset of the child in the container r=m_kato

EditorBase::CreateNode() should take EditorRawDOMPoint as insertion point of
the new element instead of a set of container, child and offset of the child
in the container.

This patch initializes EditorRawDOMPoint with original 3 arguments as far as
possible.  If the relation of them are broken, MOZ_ASSERT in RawRangeBoundary
constructor detects existing bugs.

MozReview-Commit-ID: 2N55S6pRv7k

--HG--
extra : rebase_source : 2b14a7715815ca0007635b8f791ca9edbe5b65f1
parent 82358b9f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -87,10 +87,11 @@ protected:
    MOZ_RELEASE_ASSERT(aContainer,
      "This constructor shouldn't be used when pointing nowhere");
    if (!mRef) {
      MOZ_ASSERT(mOffset.value() == 0);
      MOZ_ASSERT(!mParent->IsContainerNode() || mOffset.value() == 0);
      return;
    }
    MOZ_ASSERT(mOffset.value() > 0);
    MOZ_ASSERT(mParent == mRef->GetParentNode());
    MOZ_ASSERT(mParent->GetChildAt(mOffset.value() - 1) == mRef);
  }

+32 −24
Original line number Diff line number Diff line
@@ -1419,24 +1419,15 @@ EditorBase::SetSpellcheckUserOverride(bool enable)

already_AddRefed<Element>
EditorBase::CreateNode(nsAtom* aTag,
                       nsINode* aParent,
                       int32_t aPosition,
                       nsIContent* aChildAtPosition)
                       EditorRawDOMPoint& aPointToInsert)
{
  MOZ_ASSERT(aTag && aParent);
  MOZ_ASSERT(aTag);
  MOZ_ASSERT(aPointToInsert.IsSetAndValid());

  EditorRawDOMPoint pointToInsert;
  if (aPosition == -1) {
    pointToInsert.Set(aParent, aParent->Length());
  } else if (aChildAtPosition) {
    pointToInsert.Set(aChildAtPosition);
  } else {
    pointToInsert.Set(aParent, aPosition);
  }
  // XXX We need to offset at new node to mRangeUpdater.  Therefore, we need
  //     to compute the offset now but this is expensive.  So, if it's possible,
  //     we need to redesign mRangeUpdater as avoiding using indices.
  int32_t offset = static_cast<int32_t>(pointToInsert.Offset());
  int32_t offset = static_cast<int32_t>(aPointToInsert.Offset());

  AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);

@@ -1444,21 +1435,25 @@ EditorBase::CreateNode(nsAtom* aTag,
    AutoActionListenerArray listeners(mActionListeners);
    for (auto& listener : listeners) {
      listener->WillCreateNode(nsDependentAtomString(aTag),
                               GetAsDOMNode(pointToInsert.GetChildAtOffset()));
                               GetAsDOMNode(aPointToInsert.GetChildAtOffset()));
    }
  }

  nsCOMPtr<Element> ret;

  RefPtr<CreateElementTransaction> transaction =
    CreateTxnForCreateElement(*aTag, pointToInsert);
    CreateTxnForCreateElement(*aTag, aPointToInsert);
  nsresult rv = DoTransaction(transaction);
  if (NS_SUCCEEDED(rv)) {
    ret = transaction->GetNewNode();
    MOZ_ASSERT(ret);
    // Now, aPointToInsert may be invalid.  I.e., ChildAtOffset() keeps
    // referring the next sibling of new node but Offset() refers the
    // new node.  Let's make refer the new node.
    aPointToInsert.Set(ret);
  }

  mRangeUpdater.SelAdjCreateNode(pointToInsert.Container(), offset);
  mRangeUpdater.SelAdjCreateNode(aPointToInsert.Container(), offset);

  {
    AutoActionListenerArray listeners(mActionListeners);
@@ -4226,16 +4221,29 @@ EditorBase::DeleteSelectionAndCreateElement(nsAtom& aTag)
  RefPtr<Selection> selection = GetSelection();
  NS_ENSURE_TRUE(selection, nullptr);

  nsCOMPtr<nsINode> node = selection->GetAnchorNode();
  uint32_t offset = selection->AnchorOffset();
  nsIContent* child = selection->GetChildAtAnchorOffset();

  nsCOMPtr<Element> newElement = CreateNode(&aTag, node, offset, child);
  EditorRawDOMPoint pointToInsert(selection->GetChildAtAnchorOffset());
  if (!pointToInsert.IsSet()) {
    // Perhaps, the anchor point is in a text node.
    pointToInsert.Set(selection->GetAnchorNode(), selection->AnchorOffset());
    if (NS_WARN_IF(!pointToInsert.IsSet())) {
      return nullptr;
    }
  }
  RefPtr<Element> newElement = CreateNode(&aTag, pointToInsert);

  // We want the selection to be just after the new node
  rv = selection->Collapse(node, offset + 1);
  NS_ENSURE_SUCCESS(rv, nullptr);

  DebugOnly<bool> advanced = pointToInsert.AdvanceOffset();
  NS_WARNING_ASSERTION(advanced,
                       "Failed to move offset next to the new element");
  ErrorResult error;
  selection->Collapse(pointToInsert, error);
  if (NS_WARN_IF(error.Failed())) {
    // XXX Even if it succeeded to create new element, this returns error
    //     when Selection.Collapse() fails something.  This could occur with
    //     mutation observer or mutation event listener.
    error.SuppressException();
    return nullptr;
  }
  return newElement.forget();
}

+17 −3
Original line number Diff line number Diff line
@@ -410,9 +410,23 @@ protected:
    CreateTxnForCreateElement(nsAtom& aTag,
                              const EditorRawDOMPoint& aPointToInsert);

  already_AddRefed<Element> CreateNode(nsAtom* aTag, nsINode* aParent,
                                       int32_t aPosition,
                                       nsIContent* aChildAtPosition = nullptr);
  /**
   * 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.
   */
  already_AddRefed<Element> CreateNode(nsAtom* aTag,
                                       EditorRawDOMPoint& aPointToInsert);

  /**
   * Create a transaction for inserting aNode as a child of aParent.
+16 −7
Original line number Diff line number Diff line
@@ -59,15 +59,16 @@ public:
        aPointedNode && aPointedNode->IsContent() ?
          aPointedNode->GetParentNode() : nullptr,
        aPointedNode && aPointedNode->IsContent() ?
          GetRef(aPointedNode->AsContent()) : nullptr)
          GetRef(aPointedNode->GetParentNode(),
                 aPointedNode->AsContent()) : nullptr)
  {
  }

  EditorDOMPointBase(nsINode* aConatiner,
  EditorDOMPointBase(nsINode* aContainer,
                     nsIContent* aPointedNode,
                     int32_t aOffset)
    : RangeBoundaryBase<ParentType, RefType>(aConatiner,
                                             GetRef(aPointedNode),
    : RangeBoundaryBase<ParentType, RefType>(aContainer,
                                             GetRef(aContainer, aPointedNode),
                                             aOffset)
  {
  }
@@ -84,10 +85,18 @@ public:
  }

private:
  static nsIContent* GetRef(nsIContent* aPointedNode)
  static nsIContent* GetRef(nsINode* aContainerNode, nsIContent* aPointedNode)
  {
    MOZ_ASSERT(aPointedNode);
    return aPointedNode ? aPointedNode->GetPreviousSibling() : nullptr;
    // If referring one of a child of the container, the 'ref' should be the
    // previous sibling of the referring child.
    if (aPointedNode) {
      return aPointedNode->GetPreviousSibling();
    }
    // If referring after the last child, the 'ref' should be the last child.
    if (aContainerNode && aContainerNode->IsContainerNode()) {
      return aContainerNode->GetLastChild();
    }
    return nullptr;
  }
};

+105 −82

File changed.

Preview size limit exceeded, changes collapsed.

Loading