--- a/dom/base/RangeBoundary.h
+++ b/dom/base/RangeBoundary.h
@@ -78,16 +78,33 @@ public:
NS_WARNING_ASSERTION(mRef || aOffset == 0,
"Constructing RangeBoundary with invalid value");
}
NS_WARNING_ASSERTION(!mRef || mRef->GetParentNode() == mParent,
"Constructing RangeBoundary with invalid value");
}
+protected:
+ RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef, int32_t aOffset)
+ : mParent(aContainer)
+ , mRef(aRef)
+ , mOffset(mozilla::Some(aOffset))
+ {
+ MOZ_RELEASE_ASSERT(aContainer,
+ "This constructor shouldn't be used when pointing nowhere");
+ if (!mRef) {
+ MOZ_ASSERT(mOffset.value() == 0);
+ return;
+ }
+ MOZ_ASSERT(mOffset.value() > 0);
+ MOZ_ASSERT(mParent->GetChildAt(mOffset.value() - 1) == mRef);
+ }
+
+public:
RangeBoundaryBase()
: mParent(nullptr)
, mRef(nullptr)
{
}
// Needed for initializing RawRangeBoundary from an existing RangeBoundary.
template<typename PT, typename RT>
@@ -119,16 +136,52 @@ public:
if (!mRef) {
MOZ_ASSERT(Offset() == 0, "invalid RangeBoundary");
return mParent->GetFirstChild();
}
MOZ_ASSERT(mParent->GetChildAt(Offset()) == mRef->GetNextSibling());
return mRef->GetNextSibling();
}
+ /**
+ * GetNextSiblingOfChildOffset() returns next sibling of a child at offset.
+ * If this refers after the last child or the container cannot have children,
+ * this returns nullptr with warning.
+ */
+ nsIContent*
+ GetNextSiblingOfChildAtOffset() const
+ {
+ if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) {
+ return nullptr;
+ }
+ if (NS_WARN_IF(!mRef->GetNextSibling())) {
+ // Already referring the end of the container.
+ return nullptr;
+ }
+ return mRef->GetNextSibling()->GetNextSibling();
+ }
+
+ /**
+ * GetPreviousSiblingOfChildAtOffset() returns previous sibling of a child
+ * at offset. If this refers the first child or the container cannot have
+ * children, this returns nullptr with warning.
+ */
+ nsIContent*
+ GetPreviousSiblingOfChildAtOffset() const
+ {
+ if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) {
+ return nullptr;
+ }
+ if (NS_WARN_IF(!mRef)) {
+ // Already referring the start of the container.
+ return nullptr;
+ }
+ return mRef;
+ }
+
uint32_t
Offset() const
{
if (mOffset.isSome()) {
return mOffset.value();
}
if (!mParent) {
@@ -178,16 +231,98 @@ public:
}
mOffset = mozilla::Some(aOffset);
NS_WARNING_ASSERTION(!mRef || mRef->GetParentNode() == mParent,
"Setting RangeBoundary to invalid value");
}
+ /**
+ * AdvanceOffset() tries to reference next sibling of mRef if its container
+ * can have children or increments offset if the container is a text node or
+ * something.
+ * If the container can have children and there is no next sibling, this
+ * outputs warning and does nothing. So, callers need to check if there is
+ * next sibling which you need to refer.
+ */
+ void
+ AdvanceOffset()
+ {
+ if (NS_WARN_IF(!mParent)) {
+ return;
+ }
+ if (!mRef) {
+ if (!mParent->IsContainerNode()) {
+ // In text node or something, just increment the offset.
+ MOZ_ASSERT(mOffset.isSome());
+ if (NS_WARN_IF(mOffset.value() == mParent->Length())) {
+ // Already referring the end of the node.
+ return;
+ }
+ mOffset = mozilla::Some(mOffset.value() + 1);
+ return;
+ }
+ mRef = mParent->GetFirstChild();
+ if (NS_WARN_IF(!mRef)) {
+ // No children in the container.
+ mOffset = mozilla::Some(0);
+ } else {
+ mOffset = mozilla::Some(1);
+ }
+ return;
+ }
+
+ nsIContent* nextSibling = mRef->GetNextSibling();
+ if (NS_WARN_IF(!nextSibling)) {
+ // Already referring the end of the container.
+ return;
+ }
+ mRef = nextSibling;
+ if (mOffset.isSome()) {
+ mOffset = mozilla::Some(mOffset.value() + 1);
+ }
+ }
+
+ /**
+ * RewindOffset() tries to reference next sibling of mRef if its container
+ * can have children or decrements offset if the container is a text node or
+ * something.
+ * If the container can have children and there is no next previous, this
+ * outputs warning and does nothing. So, callers need to check if there is
+ * previous sibling which you need to refer.
+ */
+ void
+ RewindOffset()
+ {
+ if (NS_WARN_IF(!mParent)) {
+ return;
+ }
+ if (!mRef) {
+ if (NS_WARN_IF(mParent->IsContainerNode())) {
+ // Already referring the start of the container
+ mOffset = mozilla::Some(0);
+ return;
+ }
+ // In text node or something, just decrement the offset.
+ MOZ_ASSERT(mOffset.isSome());
+ if (NS_WARN_IF(mOffset.value() == 0)) {
+ // Already referring the start of the node.
+ return;
+ }
+ mOffset = mozilla::Some(mOffset.value() - 1);
+ return;
+ }
+
+ mRef = mRef->GetPreviousSibling();
+ if (mOffset.isSome()) {
+ mOffset = mozilla::Some(mOffset.value() - 1);
+ }
+ }
+
void
SetAfterRef(nsINode* aParent, nsIContent* aRef)
{
mParent = aParent;
mRef = aRef;
if (!mRef) {
mOffset = mozilla::Some(0);
} else {
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -23,21 +23,23 @@
#include "InsertTextTransaction.h" // for InsertTextTransaction
#include "JoinNodeTransaction.h" // for JoinNodeTransaction
#include "PlaceholderTransaction.h" // for PlaceholderTransaction
#include "SplitNodeTransaction.h" // for SplitNodeTransaction
#include "StyleSheetTransactions.h" // for AddStyleSheetTransaction, etc.
#include "TextEditUtils.h" // for TextEditUtils
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
#include "mozilla/CheckedInt.h" // for CheckedInt
+#include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
#include "mozilla/EditorUtils.h" // for AutoRules, etc.
#include "mozilla/EditTransactionBase.h" // for EditTransactionBase
#include "mozilla/FlushType.h" // for FlushType::Frames
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences
+#include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary
#include "mozilla/dom/Selection.h" // for Selection, etc.
#include "mozilla/Services.h" // for GetObserverService
#include "mozilla/TextComposition.h" // for TextComposition
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" // for Element, nsINode::AsElement
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/Text.h"
#include "mozilla/dom/Event.h"
@@ -3759,32 +3761,27 @@ EditorBase::IsTextNode(nsIDOMNode* aNode
return false;
}
uint16_t nodeType;
aNode->GetNodeType(&nodeType);
return (nodeType == nsIDOMNode::TEXT_NODE);
}
-/**
- * GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
- * assuming that aParentOrNode is the node itself if it's a text node, or
- * the node's parent otherwise.
- */
+// static
nsIContent*
-EditorBase::GetNodeAtRangeOffsetPoint(nsINode* aParentOrNode,
- int32_t aOffset)
-{
- if (NS_WARN_IF(!aParentOrNode)) {
+EditorBase::GetNodeAtRangeOffsetPoint(const RawRangeBoundary& aPoint)
+{
+ if (NS_WARN_IF(!aPoint.IsSet())) {
return nullptr;
}
- if (aParentOrNode->GetAsText()) {
- return aParentOrNode->AsContent();
- }
- return aParentOrNode->GetChildAt(aOffset);
+ if (aPoint.Container()->GetAsText()) {
+ return aPoint.Container()->AsContent();
+ }
+ return aPoint.GetChildAtOffset();
}
/**
* GetStartNodeAndOffset() returns whatever the start parent & offset is of
* the first range in the selection.
*/
nsresult
EditorBase::GetStartNodeAndOffset(Selection* aSelection,
@@ -4041,60 +4038,67 @@ EditorBase::JoinNodeDeep(nsIContent& aLe
// While the rightmost children and their descendants of the left node match
// the leftmost children and their descendants of the right node, join them
// up.
nsCOMPtr<nsIContent> leftNodeToJoin = &aLeftNode;
nsCOMPtr<nsIContent> rightNodeToJoin = &aRightNode;
nsCOMPtr<nsINode> parentNode = aRightNode.GetParentNode();
- EditorDOMPoint ret;
+ nsCOMPtr<nsINode> resultNode = nullptr;
+ int32_t resultOffset = -1;
while (leftNodeToJoin && rightNodeToJoin && parentNode &&
AreNodesSameType(leftNodeToJoin, rightNodeToJoin)) {
uint32_t length = leftNodeToJoin->Length();
- ret.node = rightNodeToJoin;
- ret.offset = length;
+ resultNode = rightNodeToJoin;
+ resultOffset = length;
// Do the join
nsresult rv = JoinNodes(*leftNodeToJoin, *rightNodeToJoin);
- NS_ENSURE_SUCCESS(rv, EditorDOMPoint());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditorDOMPoint();
+ }
if (parentNode->GetAsText()) {
// We've joined all the way down to text nodes, we're done!
- return ret;
+ return EditorDOMPoint(resultNode, resultOffset);
}
// Get new left and right nodes, and begin anew
parentNode = rightNodeToJoin;
rightNodeToJoin = parentNode->GetChildAt(length);
if (rightNodeToJoin) {
leftNodeToJoin = rightNodeToJoin->GetPreviousSibling();
} else {
leftNodeToJoin = nullptr;
}
// Skip over non-editable nodes
while (leftNodeToJoin && !IsEditable(leftNodeToJoin)) {
leftNodeToJoin = leftNodeToJoin->GetPreviousSibling();
}
if (!leftNodeToJoin) {
- return ret;
+ return EditorDOMPoint(resultNode, resultOffset);
}
while (rightNodeToJoin && !IsEditable(rightNodeToJoin)) {
rightNodeToJoin = rightNodeToJoin->GetNextSibling();
}
if (!rightNodeToJoin) {
- return ret;
+ return EditorDOMPoint(resultNode, resultOffset);
}
}
- return ret;
+ if (NS_WARN_IF(!resultNode)) {
+ return EditorDOMPoint();
+ }
+
+ return EditorDOMPoint(resultNode, resultOffset);
}
void
EditorBase::BeginUpdateViewBatch()
{
NS_PRECONDITION(mUpdateCount >= 0, "bad state");
if (!mUpdateCount) {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -2,19 +2,21 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_EditorBase_h
#define mozilla_EditorBase_h
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
+#include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/OwningNonNull.h" // for OwningNonNull
#include "mozilla/PresShell.h" // for PresShell
+#include "mozilla/RangeBoundary.h" // for RawRangeBoundary, RangeBoundary
#include "mozilla/SelectionState.h" // for RangeUpdater, etc.
#include "mozilla/StyleSheet.h" // for StyleSheet
#include "mozilla/WeakPtr.h" // for WeakPtr
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/Text.h"
#include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
#include "nsCycleCollectionParticipant.h"
#include "nsGkAtoms.h"
@@ -118,17 +120,16 @@ class HTMLEditor;
class InsertNodeTransaction;
class InsertTextTransaction;
class JoinNodeTransaction;
class PlaceholderTransaction;
class RemoveStyleSheetTransaction;
class SplitNodeTransaction;
class TextComposition;
class TextEditor;
-struct EditorDOMPoint;
namespace dom {
class DataTransfer;
class Element;
class EventTarget;
class Text;
} // namespace dom
@@ -881,18 +882,27 @@ public:
virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2);
static bool IsTextNode(nsIDOMNode* aNode);
static bool IsTextNode(nsINode* aNode)
{
return aNode->NodeType() == nsIDOMNode::TEXT_NODE;
}
- static nsIContent* GetNodeAtRangeOffsetPoint(nsINode* aParentOrNode,
- int32_t aOffset);
+ /**
+ * GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
+ * assuming that the container is the node itself if it's a text node, or
+ * the node's parent otherwise.
+ */
+ static nsIContent* GetNodeAtRangeOffsetPoint(nsINode* aContainer,
+ int32_t aOffset)
+ {
+ return GetNodeAtRangeOffsetPoint(RawRangeBoundary(aContainer, aOffset));
+ }
+ static nsIContent* GetNodeAtRangeOffsetPoint(const RawRangeBoundary& aPoint);
static nsresult GetStartNodeAndOffset(Selection* aSelection,
nsIDOMNode** outStartNode,
int32_t* outStartOffset);
static nsresult GetStartNodeAndOffset(Selection* aSelection,
nsINode** aStartContainer,
int32_t* aStartOffset);
static nsresult GetEndNodeAndOffset(Selection* aSelection,
copy from editor/libeditor/EditorUtils.h
copy to editor/libeditor/EditorDOMPoint.h
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorDOMPoint.h
@@ -1,438 +1,94 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef mozilla_EditorUtils_h
-#define mozilla_EditorUtils_h
+#ifndef mozilla_EditorDOMPoint_h
+#define mozilla_EditorDOMPoint_h
-#include "mozilla/dom/Selection.h"
-#include "mozilla/EditorBase.h"
-#include "mozilla/GuardObjects.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/RangeBoundary.h"
#include "nsCOMPtr.h"
-#include "nsDebug.h"
-#include "nsIDOMNode.h"
-#include "nsIEditor.h"
-#include "nscore.h"
-
-class nsAtom;
-class nsIContentIterator;
-class nsIDOMDocument;
-class nsIDOMEvent;
-class nsISimpleEnumerator;
-class nsITransferable;
-class nsRange;
+#include "nsIContent.h"
+#include "nsINode.h"
namespace mozilla {
-template <class T> class OwningNonNull;
+
+template<typename ParentType, typename RefType>
+class EditorDOMPointBase;
-/***************************************************************************
- * EditActionResult is useful to return multiple results of an editor
- * action handler without out params.
- * Note that when you return an anonymous instance from a method, you should
- * use EditActionIgnored(), EditActionHandled() or EditActionCanceled() for
- * easier to read. In other words, EditActionResult should be used when
- * declaring return type of a method, being an argument or defined as a local
- * variable.
- */
-class MOZ_STACK_CLASS EditActionResult final
+typedef EditorDOMPointBase<nsCOMPtr<nsINode>,
+ nsCOMPtr<nsIContent>> EditorDOMPoint;
+typedef EditorDOMPointBase<nsINode*, nsIContent*> EditorRawDOMPoint;
+
+template<typename ParentType, typename RefType>
+class MOZ_STACK_CLASS EditorDOMPointBase final
+ : public RangeBoundaryBase<ParentType, RefType>
{
public:
- bool Succeeded() const { return NS_SUCCEEDED(mRv); }
- bool Failed() const { return NS_FAILED(mRv); }
- nsresult Rv() const { return mRv; }
- bool Canceled() const { return mCanceled; }
- bool Handled() const { return mHandled; }
-
- EditActionResult SetResult(nsresult aRv)
+ EditorDOMPointBase()
+ : RangeBoundaryBase<ParentType, RefType>()
{
- mRv = aRv;
- return *this;
- }
- EditActionResult MarkAsCanceled()
- {
- mCanceled = true;
- return *this;
- }
- EditActionResult MarkAsHandled()
- {
- mHandled = true;
- return *this;
}
- explicit EditActionResult(nsresult aRv)
- : mRv(aRv)
- , mCanceled(false)
- , mHandled(false)
+ EditorDOMPointBase(nsINode* aConatiner,
+ int32_t aOffset)
+ : RangeBoundaryBase<ParentType, RefType>(aConatiner,
+ aOffset)
{
}
- EditActionResult& operator|=(const EditActionResult& aOther)
+ EditorDOMPointBase(nsIDOMNode* aDOMContainer,
+ int32_t aOffset)
+ : RangeBoundaryBase<ParentType, RefType>()
{
- mCanceled |= aOther.mCanceled;
- mHandled |= aOther.mHandled;
- // When both result are same, keep the result.
- if (mRv == aOther.mRv) {
- return *this;
- }
- // If one of the results is error, use NS_ERROR_FAILURE.
- if (Failed() || aOther.Failed()) {
- mRv = NS_ERROR_FAILURE;
- } else {
- // Otherwise, use generic success code, NS_OK.
- mRv = NS_OK;
- }
- return *this;
+ nsCOMPtr<nsINode> container = do_QueryInterface(aDOMContainer);
+ this->Set(container, aOffset);
}
-private:
- nsresult mRv;
- bool mCanceled;
- bool mHandled;
-
- EditActionResult(nsresult aRv, bool aCanceled, bool aHandled)
- : mRv(aRv)
- , mCanceled(aCanceled)
- , mHandled(aHandled)
- {
- }
-
- EditActionResult()
- : mRv(NS_ERROR_NOT_INITIALIZED)
- , mCanceled(false)
- , mHandled(false)
+ /**
+ * Different from RangeBoundary, aReferenceChild should be a child node
+ * which you want to refer. So, set non-nullptr if offset is
+ * 0 - Length() - 1. Otherwise, set nullptr, i.e., if offset is same as
+ * Length().
+ */
+ EditorDOMPointBase(nsINode* aContainer,
+ nsIContent* aPointedNode)
+ : RangeBoundaryBase<ParentType, RefType>(aContainer,
+ GetRef(aPointedNode))
{
}
- friend EditActionResult EditActionIgnored(nsresult aRv);
- friend EditActionResult EditActionHandled(nsresult aRv);
- friend EditActionResult EditActionCanceled(nsresult aRv);
-};
-
-/***************************************************************************
- * When an edit action handler (or its helper) does nothing,
- * EditActionIgnored should be returned.
- */
-inline EditActionResult
-EditActionIgnored(nsresult aRv = NS_OK)
-{
- return EditActionResult(aRv, false, false);
-}
-
-/***************************************************************************
- * When an edit action handler (or its helper) handled and not canceled,
- * EditActionHandled should be returned.
- */
-inline EditActionResult
-EditActionHandled(nsresult aRv = NS_OK)
-{
- return EditActionResult(aRv, false, true);
-}
+ EditorDOMPointBase(nsINode* aConatiner,
+ nsIContent* aPointedNode,
+ int32_t aOffset)
+ : RangeBoundaryBase<ParentType, RefType>(aConatiner,
+ GetRef(aPointedNode),
+ aOffset)
+ {
+ }
-/***************************************************************************
- * When an edit action handler (or its helper) handled and canceled,
- * EditActionHandled should be returned.
- */
-inline EditActionResult
-EditActionCanceled(nsresult aRv = NS_OK)
-{
- return EditActionResult(aRv, true, true);
-}
-
-/***************************************************************************
- * stack based helper class for batching a collection of transactions inside a
- * placeholder transaction.
- */
-class MOZ_RAII AutoPlaceholderBatch final
-{
-private:
- RefPtr<EditorBase> mEditorBase;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+ template<typename PT, typename RT>
+ explicit EditorDOMPointBase(const RangeBoundaryBase<PT, RT>& aOther)
+ : RangeBoundaryBase<ParentType, RefType>(aOther)
+ {
+ }
-public:
- explicit AutoPlaceholderBatch(EditorBase* aEditorBase
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mEditorBase(aEditorBase)
+ explicit EditorDOMPointBase(const RawRangeBoundary& aRawRangeBoundary)
+ : RangeBoundaryBase<ParentType, RefType>(aRawRangeBoundary)
{
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- BeginPlaceholderTransaction(nullptr);
- }
- AutoPlaceholderBatch(EditorBase* aEditorBase,
- nsAtom* aTransactionName
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mEditorBase(aEditorBase)
- {
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- BeginPlaceholderTransaction(aTransactionName);
- }
- ~AutoPlaceholderBatch()
- {
- if (mEditorBase) {
- mEditorBase->EndPlaceholderTransaction();
- }
}
private:
- void BeginPlaceholderTransaction(nsAtom* aTransactionName)
- {
- if (mEditorBase) {
- mEditorBase->BeginPlaceholderTransaction(aTransactionName);
- }
- }
-};
-
-/***************************************************************************
- * stack based helper class for saving/restoring selection. Note that this
- * assumes that the nodes involved are still around afterwards!
- */
-class MOZ_RAII AutoSelectionRestorer final
-{
-private:
- // Ref-counted reference to the selection that we are supposed to restore.
- RefPtr<dom::Selection> mSelection;
- EditorBase* mEditorBase; // Non-owning ref to EditorBase.
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-
-public:
- /**
- * Constructor responsible for remembering all state needed to restore
- * aSelection.
- */
- AutoSelectionRestorer(dom::Selection* aSelection,
- EditorBase* aEditorBase
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-
- /**
- * Destructor restores mSelection to its former state
- */
- ~AutoSelectionRestorer();
-
- /**
- * Abort() cancels to restore the selection.
- */
- void Abort();
-};
-
-/***************************************************************************
- * stack based helper class for StartOperation()/EndOperation() sandwich
- */
-class MOZ_RAII AutoRules final
-{
-public:
- AutoRules(EditorBase* aEditorBase, EditAction aAction,
- nsIEditor::EDirection aDirection
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mEditorBase(aEditorBase)
- , mDoNothing(false)
- {
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- // mAction will already be set if this is nested call
- if (mEditorBase && !mEditorBase->mAction) {
- mEditorBase->StartOperation(aAction, aDirection);
- } else {
- mDoNothing = true; // nested calls will end up here
- }
- }
-
- ~AutoRules()
- {
- if (mEditorBase && !mDoNothing) {
- mEditorBase->EndOperation();
- }
- }
-
-protected:
- EditorBase* mEditorBase;
- bool mDoNothing;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-/***************************************************************************
- * stack based helper class for turning off active selection adjustment
- * by low level transactions
- */
-class MOZ_RAII AutoTransactionsConserveSelection final
-{
-public:
- explicit AutoTransactionsConserveSelection(EditorBase* aEditorBase
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mEditorBase(aEditorBase)
- , mOldState(true)
- {
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- if (mEditorBase) {
- mOldState = mEditorBase->GetShouldTxnSetSelection();
- mEditorBase->SetShouldTxnSetSelection(false);
- }
- }
-
- ~AutoTransactionsConserveSelection()
- {
- if (mEditorBase) {
- mEditorBase->SetShouldTxnSetSelection(mOldState);
- }
- }
-
-protected:
- EditorBase* mEditorBase;
- bool mOldState;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-/***************************************************************************
- * stack based helper class for batching reflow and paint requests.
- */
-class MOZ_RAII AutoUpdateViewBatch final
-{
-public:
- explicit AutoUpdateViewBatch(EditorBase* aEditorBase
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mEditorBase(aEditorBase)
- {
- MOZ_GUARD_OBJECT_NOTIFIER_INIT;
- NS_ASSERTION(mEditorBase, "null mEditorBase pointer!");
-
- if (mEditorBase) {
- mEditorBase->BeginUpdateViewBatch();
- }
- }
-
- ~AutoUpdateViewBatch()
+ static nsIContent* GetRef(nsIContent* aPointedNode)
{
- if (mEditorBase) {
- mEditorBase->EndUpdateViewBatch();
- }
- }
-
-protected:
- EditorBase* mEditorBase;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-class MOZ_STACK_CLASS AutoRangeArray final
-{
-public:
- explicit AutoRangeArray(dom::Selection* aSelection)
- {
- if (!aSelection) {
- return;
- }
- uint32_t rangeCount = aSelection->RangeCount();
- for (uint32_t i = 0; i < rangeCount; i++) {
- mRanges.AppendElement(*aSelection->GetRangeAt(i));
- }
+ MOZ_ASSERT(aPointedNode);
+ return aPointedNode ? aPointedNode->GetPreviousSibling() : nullptr;
}
-
- AutoTArray<mozilla::OwningNonNull<nsRange>, 8> mRanges;
-};
-
-/******************************************************************************
- * some helper classes for iterating the dom tree
- *****************************************************************************/
-
-class BoolDomIterFunctor
-{
-public:
- virtual bool operator()(nsINode* aNode) const = 0;
-};
-
-class MOZ_RAII DOMIterator
-{
-public:
- explicit DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-
- explicit DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
- virtual ~DOMIterator();
-
- nsresult Init(nsRange& aRange);
-
- void AppendList(
- const BoolDomIterFunctor& functor,
- nsTArray<mozilla::OwningNonNull<nsINode>>& arrayOfNodes) const;
-
-protected:
- nsCOMPtr<nsIContentIterator> mIter;
- MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-class MOZ_RAII DOMSubtreeIterator final : public DOMIterator
-{
-public:
- explicit DOMSubtreeIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
- virtual ~DOMSubtreeIterator();
-
- nsresult Init(nsRange& aRange);
-};
-
-class TrivialFunctor final : public BoolDomIterFunctor
-{
-public:
- // Used to build list of all nodes iterator covers
- virtual bool operator()(nsINode* aNode) const
- {
- return true;
- }
-};
-
-/******************************************************************************
- * general dom point utility struct
- *****************************************************************************/
-struct MOZ_STACK_CLASS EditorDOMPoint final
-{
- nsCOMPtr<nsINode> node;
- int32_t offset;
-
- EditorDOMPoint()
- : node(nullptr)
- , offset(-1)
- {}
- EditorDOMPoint(nsINode* aNode, int32_t aOffset)
- : node(aNode)
- , offset(aOffset)
- {}
- EditorDOMPoint(nsIDOMNode* aNode, int32_t aOffset)
- : node(do_QueryInterface(aNode))
- , offset(aOffset)
- {}
-
- void SetPoint(nsINode* aNode, int32_t aOffset)
- {
- node = aNode;
- offset = aOffset;
- }
- void SetPoint(nsIDOMNode* aNode, int32_t aOffset)
- {
- node = do_QueryInterface(aNode);
- offset = aOffset;
- }
-};
-
-class EditorUtils final
-{
-public:
- // Note that aChild isn't a normal XPCOM outparam and won't get AddRef'ed.
- static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
- nsIContent** aChild);
- static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
- int32_t* aOffset = nullptr);
- static bool IsDescendantOf(nsIDOMNode* aNode, nsIDOMNode* aParent,
- int32_t* aOffset = nullptr);
- static bool IsLeafNode(nsIDOMNode* aNode);
-};
-
-class EditorHookUtils final
-{
-public:
- static bool DoInsertionHook(nsIDOMDocument* aDoc, nsIDOMEvent* aEvent,
- nsITransferable* aTrans);
-
-private:
- static nsresult GetHookEnumeratorFromDocument(
- nsIDOMDocument*aDoc,
- nsISimpleEnumerator** aEnumerator);
};
} // namespace mozilla
-#endif // #ifndef mozilla_EditorUtils_h
+#endif // #ifndef mozilla_EditorDOMPoint_h
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -370,49 +370,16 @@ class TrivialFunctor final : public Bool
public:
// Used to build list of all nodes iterator covers
virtual bool operator()(nsINode* aNode) const
{
return true;
}
};
-/******************************************************************************
- * general dom point utility struct
- *****************************************************************************/
-struct MOZ_STACK_CLASS EditorDOMPoint final
-{
- nsCOMPtr<nsINode> node;
- int32_t offset;
-
- EditorDOMPoint()
- : node(nullptr)
- , offset(-1)
- {}
- EditorDOMPoint(nsINode* aNode, int32_t aOffset)
- : node(aNode)
- , offset(aOffset)
- {}
- EditorDOMPoint(nsIDOMNode* aNode, int32_t aOffset)
- : node(do_QueryInterface(aNode))
- , offset(aOffset)
- {}
-
- void SetPoint(nsINode* aNode, int32_t aOffset)
- {
- node = aNode;
- offset = aOffset;
- }
- void SetPoint(nsIDOMNode* aNode, int32_t aOffset)
- {
- node = do_QueryInterface(aNode);
- offset = aOffset;
- }
-};
-
class EditorUtils final
{
public:
// Note that aChild isn't a normal XPCOM outparam and won't get AddRef'ed.
static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
nsIContent** aChild);
static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
int32_t* aOffset = nullptr);
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -8,16 +8,17 @@
#include <stdlib.h>
#include "HTMLEditUtils.h"
#include "TextEditUtils.h"
#include "WSRunObject.h"
#include "mozilla/Assertions.h"
#include "mozilla/CSSEditUtils.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/Selection.h"
@@ -2299,19 +2300,21 @@ HTMLEditRules::WillDeleteSelection(Selec
if (sibling) {
NS_ENSURE_STATE(mHTMLEditor);
stepbrother = mHTMLEditor->GetNextHTMLSibling(sibling);
}
// Are they both text nodes? If so, join them!
if (startNode == stepbrother && startNode->GetAsText() &&
sibling->GetAsText()) {
EditorDOMPoint pt = JoinNodesSmart(*sibling, *startNode->AsContent());
- NS_ENSURE_STATE(pt.node);
+ if (NS_WARN_IF(!pt.IsSet())) {
+ return NS_ERROR_FAILURE;
+ }
// Fix up selection
- rv = aSelection->Collapse(pt.node, pt.offset);
+ rv = aSelection->Collapse(pt.Container(), pt.Offset());
NS_ENSURE_SUCCESS(rv, rv);
}
rv = InsertBRIfNeeded(aSelection);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
if (wsType == WSType::otherBlock) {
@@ -2369,18 +2372,20 @@ HTMLEditRules::WillDeleteSelection(Selec
InDifferentTableElements(leftNode, rightNode)) {
return NS_OK;
}
if (bDeletedBR) {
// Put selection at edge of block and we are done.
NS_ENSURE_STATE(leafNode);
EditorDOMPoint newSel = GetGoodSelPointForNode(*leafNode, aAction);
- NS_ENSURE_STATE(newSel.node);
- aSelection->Collapse(newSel.node, newSel.offset);
+ if (NS_WARN_IF(!newSel.IsSet())) {
+ return NS_ERROR_FAILURE;
+ }
+ aSelection->Collapse(newSel.Container(), newSel.Offset());
return NS_OK;
}
// Else we are joining content to block
nsCOMPtr<nsINode> selPointNode = startNode;
int32_t selPointOffset = startOffset;
{
@@ -2558,19 +2563,21 @@ HTMLEditRules::WillDeleteSelection(Selec
// First delete the selection
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
NS_ENSURE_SUCCESS(rv, rv);
// Join blocks
NS_ENSURE_STATE(mHTMLEditor);
EditorDOMPoint pt =
mHTMLEditor->JoinNodeDeep(*leftParent, *rightParent);
- NS_ENSURE_STATE(pt.node);
+ if (NS_WARN_IF(!pt.IsSet())) {
+ return NS_ERROR_FAILURE;
+ }
// Fix up selection
- rv = aSelection->Collapse(pt.node, pt.offset);
+ rv = aSelection->Collapse(pt.Container(), pt.Offset());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// Else blocks not same type, or not siblings. Delete everything
// except table elements.
join = true;
@@ -2767,29 +2774,33 @@ HTMLEditRules::GetGoodSelPointForNode(ns
aAction == nsIEditor::ePreviousWord ||
aAction == nsIEditor::eToBeginningOfLine ||
aAction == nsIEditor::eToEndOfLine);
bool isPreviousAction = (aAction == nsIEditor::ePrevious ||
aAction == nsIEditor::ePreviousWord ||
aAction == nsIEditor::eToBeginningOfLine);
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
if (aNode.GetAsText() || mHTMLEditor->IsContainer(&aNode) ||
NS_WARN_IF(!aNode.GetParentNode())) {
return EditorDOMPoint(&aNode, isPreviousAction ? aNode.Length() : 0);
}
- EditorDOMPoint ret;
- ret.node = aNode.GetParentNode();
- ret.offset = ret.node ? ret.node->IndexOf(&aNode) : -1;
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor) ||
+ NS_WARN_IF(!aNode.IsContent())) {
+ return EditorDOMPoint();
+ }
+
+ EditorDOMPoint ret(aNode.GetParentNode(), aNode.AsContent());
if ((!aNode.IsHTMLElement(nsGkAtoms::br) ||
mHTMLEditor->IsVisibleBRElement(&aNode)) && isPreviousAction) {
- ret.offset++;
+ ret.AdvanceOffset();
}
return ret;
}
EditActionResult
HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
nsIContent& aRightNode)
{
@@ -3066,17 +3077,17 @@ HTMLEditRules::TryToJoinBlocks(nsIConten
// Do br adjustment.
nsCOMPtr<Element> brNode =
CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd);
EditActionResult ret(NS_OK);
if (mergeLists || leftBlock->NodeInfo()->NameAtom() ==
rightBlock->NodeInfo()->NameAtom()) {
// Nodes are same type. merge them.
EditorDOMPoint pt = JoinNodesSmart(*leftBlock, *rightBlock);
- if (pt.node && mergeLists) {
+ if (pt.IsSet() && mergeLists) {
RefPtr<Element> newBlock =
ConvertListType(rightBlock, existingList, nsGkAtoms::li);
}
ret.MarkAsHandled();
} else {
// Nodes are dissimilar types.
ret |= MoveBlock(*leftBlock, *rightBlock, leftOffset, rightOffset);
if (NS_WARN_IF(ret.Failed())) {
@@ -5159,34 +5170,34 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
aAction == nsIEditor::eToEndOfLine) {
// Move to the start of the next node, if any
nsINode* child = emptyBlock->GetNextSibling();
nsCOMPtr<nsIContent> nextNode =
htmlEditor->GetNextNode(blockParent, offset + 1, child, true);
if (nextNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
- nsresult rv = aSelection->Collapse(pt.node, pt.offset);
+ nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Adjust selection to be right after it.
nsresult rv = aSelection->Collapse(blockParent, offset + 1);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (aAction == nsIEditor::ePrevious ||
aAction == nsIEditor::ePreviousWord ||
aAction == nsIEditor::eToBeginningOfLine) {
// Move to the end of the previous node
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
offset,
emptyBlock,
true);
if (priorNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
- nsresult rv = aSelection->Collapse(pt.node, pt.offset);
+ nsresult rv = aSelection->Collapse(pt.Container(), pt.Offset());
NS_ENSURE_SUCCESS(rv, rv);
} else {
nsresult rv = aSelection->Collapse(blockParent, offset + 1);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (aAction != nsIEditor::eNone) {
MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet");
}
@@ -5848,32 +5859,37 @@ HTMLEditRules::PromoteRange(nsRange& aRa
return;
}
}
// Make a new adjusted range to represent the appropriate block content.
// This is tricky. The basic idea is to push out the range endpoints to
// truly enclose the blocks that we will affect.
- EditorDOMPoint opStart =
+ // Make sure that the new range ends up to be in the editable section.
+ // XXX Looks like that this check wastes the time. Perhaps, we should
+ // implement a method which checks both two DOM points in the editor
+ // root.
+ EditorDOMPoint startPoint =
GetPromotedPoint(kStart, *startNode, startOffset, aOperationType);
- EditorDOMPoint opEnd =
+ if (!htmlEditor->IsDescendantOfEditorRoot(
+ EditorBase::GetNodeAtRangeOffsetPoint(startPoint.AsRaw()))) {
+ return;
+ }
+ EditorDOMPoint endPoint =
GetPromotedPoint(kEnd, *endNode, endOffset, aOperationType);
-
- // Make sure that the new range ends up to be in the editable section.
+ EditorRawDOMPoint lastRawPoint(endPoint.AsRaw());
+ lastRawPoint.RewindOffset();
if (!htmlEditor->IsDescendantOfEditorRoot(
- EditorBase::GetNodeAtRangeOffsetPoint(opStart.node, opStart.offset)) ||
- !htmlEditor->IsDescendantOfEditorRoot(
- EditorBase::GetNodeAtRangeOffsetPoint(opEnd.node, opEnd.offset - 1))) {
+ EditorBase::GetNodeAtRangeOffsetPoint(lastRawPoint))) {
return;
}
DebugOnly<nsresult> rv =
- aRange.SetStartAndEnd(opStart.node, opStart.offset,
- opEnd.node, opEnd.offset);
+ aRange.SetStartAndEnd(startPoint.AsRaw(), endPoint.AsRaw());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
class UniqueFunctor final : public BoolDomIterFunctor
{
public:
explicit UniqueFunctor(nsTArray<OwningNonNull<nsINode>>& aArray)
: mArray(aArray)
@@ -6395,39 +6411,44 @@ HTMLEditRules::GetHighestInlineParent(ns
}
/**
* GetNodesFromPoint() constructs a list of nodes from a point that will be
* operated on.
*/
nsresult
HTMLEditRules::GetNodesFromPoint(
- EditorDOMPoint aPoint,
+ const EditorDOMPoint& aPoint,
EditAction aOperation,
nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
TouchContent aTouchContent)
{
- NS_ENSURE_STATE(aPoint.node);
- RefPtr<nsRange> range = new nsRange(aPoint.node);
- nsresult rv = range->SetStart(aPoint.node, aPoint.offset);
+ if (NS_WARN_IF(!aPoint.IsSet())) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ RefPtr<nsRange> range = new nsRange(aPoint.Container());
+ DebugOnly<nsresult> rv = range->SetStart(aPoint.Container(), aPoint.Offset());
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Expand the range to include adjacent inlines
PromoteRange(*range, aOperation);
// Make array of ranges
nsTArray<RefPtr<nsRange>> arrayOfRanges;
// Stuff new opRange into array
arrayOfRanges.AppendElement(range);
// Use these ranges to contruct a list of nodes to act on
- rv = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, aOperation,
- aTouchContent);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv2 =
+ GetNodesForOperation(arrayOfRanges, outArrayOfNodes, aOperation,
+ aTouchContent);
+ if (NS_WARN_IF(NS_FAILED(rv2))) {
+ return rv2;
+ }
return NS_OK;
}
/**
* GetNodesFromSelection() constructs a list of nodes from the selection that
* will be operated on.
*/
@@ -7320,62 +7341,85 @@ HTMLEditRules::SplitAsNeeded(nsAtom& aTa
* Returns the point where they're merged, or (nullptr, -1) on failure.
*/
EditorDOMPoint
HTMLEditRules::JoinNodesSmart(nsIContent& aNodeLeft,
nsIContent& aNodeRight)
{
// Caller responsible for left and right node being the same type
nsCOMPtr<nsINode> parent = aNodeLeft.GetParentNode();
- NS_ENSURE_TRUE(parent, EditorDOMPoint());
+ if (NS_WARN_IF(!parent)) {
+ return EditorDOMPoint();
+ }
int32_t parOffset = parent->IndexOf(&aNodeLeft);
nsCOMPtr<nsINode> rightParent = aNodeRight.GetParentNode();
// If they don't have the same parent, first move the right node to after the
// left one
if (parent != rightParent) {
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
nsresult rv = mHTMLEditor->MoveNode(&aNodeRight, parent, parOffset);
- NS_ENSURE_SUCCESS(rv, EditorDOMPoint());
- }
-
- EditorDOMPoint ret(&aNodeRight, aNodeLeft.Length());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditorDOMPoint();
+ }
+ }
+
+ nsCOMPtr<nsINode> resultNode = &aNodeRight;
+ int32_t resultOffset = aNodeLeft.Length();
// Separate join rules for differing blocks
if (HTMLEditUtils::IsList(&aNodeLeft) || aNodeLeft.GetAsText()) {
// For lists, merge shallow (wouldn't want to combine list items)
nsresult rv = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight);
- NS_ENSURE_SUCCESS(rv, EditorDOMPoint());
- return ret;
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditorDOMPoint();
+ }
+ return EditorDOMPoint(resultNode, resultOffset);
}
// Remember the last left child, and first right child
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
nsCOMPtr<nsIContent> lastLeft = mHTMLEditor->GetLastEditableChild(aNodeLeft);
- NS_ENSURE_TRUE(lastLeft, EditorDOMPoint());
-
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!lastLeft)) {
+ return EditorDOMPoint();
+ }
+
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
nsCOMPtr<nsIContent> firstRight = mHTMLEditor->GetFirstEditableChild(aNodeRight);
- NS_ENSURE_TRUE(firstRight, EditorDOMPoint());
+ if (NS_WARN_IF(!firstRight)) {
+ return EditorDOMPoint();
+ }
// For list items, divs, etc., merge smart
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
nsresult rv = mHTMLEditor->JoinNodes(aNodeLeft, aNodeRight);
- NS_ENSURE_SUCCESS(rv, EditorDOMPoint());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return EditorDOMPoint();
+ }
if (lastLeft && firstRight && mHTMLEditor &&
mHTMLEditor->AreNodesSameType(lastLeft, firstRight) &&
(lastLeft->GetAsText() || !mHTMLEditor ||
(lastLeft->IsElement() && firstRight->IsElement() &&
mHTMLEditor->mCSSEditUtils->ElementsSameStyle(lastLeft->AsElement(),
firstRight->AsElement())))) {
- NS_ENSURE_TRUE(mHTMLEditor, EditorDOMPoint());
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditorDOMPoint();
+ }
return JoinNodesSmart(*lastLeft, *firstRight);
}
- return ret;
+ return EditorDOMPoint(resultNode, resultOffset);
}
Element*
HTMLEditRules::GetTopEnclosingMailCite(nsINode& aNode)
{
nsCOMPtr<Element> ret;
for (nsCOMPtr<nsINode> node = &aNode; node; node = node->GetParentNode()) {
@@ -7833,17 +7877,17 @@ HTMLEditRules::AdjustSelection(Selection
rv = FindNearSelectableNode(selNode, selOffset, child, aAction,
address_of(nearNode));
NS_ENSURE_SUCCESS(rv, rv);
if (!nearNode) {
return NS_OK;
}
EditorDOMPoint pt = GetGoodSelPointForNode(*nearNode, aAction);
- rv = aSelection->Collapse(pt.node, pt.offset);
+ rv = aSelection->Collapse(pt.Container(), pt.Offset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HTMLEditRules_h
#define HTMLEditRules_h
#include "TypeInState.h"
+#include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
#include "mozilla/SelectionState.h"
#include "mozilla/TextEditRules.h"
#include "nsCOMPtr.h"
#include "nsIEditActionListener.h"
#include "nsIEditor.h"
#include "nsIHTMLEditor.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
@@ -27,17 +28,16 @@ class nsINode;
class nsRange;
namespace mozilla {
class EditActionResult;
class HTMLEditor;
class RulesInfo;
class TextEditor;
-struct EditorDOMPoint;
namespace dom {
class Element;
class Selection;
} // namespace dom
struct StyleCache final : public PropItem
{
bool mPresent;
@@ -184,18 +184,18 @@ protected:
*
* @param aNode Reference to a block parent.
* @param aInsertMozBR true if this should insert a moz-<br> element.
* Otherwise, i.e., this should insert a normal <br>
* element, false.
*/
nsresult InsertBRIfNeededInternal(nsINode& aNode, bool aInsertMozBR);
- mozilla::EditorDOMPoint GetGoodSelPointForNode(nsINode& aNode,
- nsIEditor::EDirection aAction);
+ EditorDOMPoint GetGoodSelPointForNode(nsINode& aNode,
+ nsIEditor::EDirection aAction);
/**
* TryToJoinBlocks() tries to join two block elements. The right element is
* always joined to the left element. If the elements are the same type and
* not nested within each other, JoinNodesSmart() is called (example, joining
* two list items together into one). If the elements are not the same type,
* or one is a descendant of the other, we instead destroy the right block
* placing its children into leftblock. DTD containment rules are followed
@@ -350,17 +350,17 @@ protected:
nsresult GetNodesForOperation(
nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
EditAction aOperationType,
TouchContent aTouchContent = TouchContent::yes);
void GetChildNodesForOperation(
nsINode& aNode,
nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes);
- nsresult GetNodesFromPoint(EditorDOMPoint aPoint,
+ nsresult GetNodesFromPoint(const EditorDOMPoint& aPoint,
EditAction aOperation,
nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
TouchContent aTouchContent);
nsresult GetNodesFromSelection(
Selection& aSelection,
EditAction aOperation,
nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
TouchContent aTouchContent = TouchContent::yes);
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WSRunObject.h"
#include "TextEditUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
+#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/mozalloc.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/SelectionState.h"
#include "nsAString.h"
#include "nsCRT.h"
@@ -645,45 +646,44 @@ WSRunObject::GetWSNodes()
mFirstNBSPNode = textNode;
mFirstNBSPOffset = pos;
// also keep track of latest nbsp so far
if (!mLastNBSPNode) {
mLastNBSPNode = textNode;
mLastNBSPOffset = pos;
}
}
- start.node = textNode;
- start.offset = pos;
+ start.Set(textNode, pos);
}
}
}
while (!mStartNode) {
// we haven't found the start of ws yet. Keep looking
nsCOMPtr<nsIContent> priorNode = GetPreviousWSNode(start, wsBoundingParent);
if (priorNode) {
if (IsBlockNode(priorNode)) {
- mStartNode = start.node;
- mStartOffset = start.offset;
+ mStartNode = start.Container();
+ mStartOffset = start.Offset();
mStartReason = WSType::otherBlock;
mStartReasonNode = priorNode;
} else if (priorNode->IsNodeOfType(nsINode::eTEXT) &&
priorNode->IsEditable()) {
RefPtr<Text> textNode = priorNode->GetAsText();
mNodeArray.InsertElementAt(0, textNode);
const nsTextFragment *textFrag;
if (!textNode || !(textFrag = textNode->GetText())) {
return NS_ERROR_NULL_POINTER;
}
uint32_t len = textNode->TextLength();
if (len < 1) {
// Zero length text node. Set start point to it
// so we can get past it!
- start.SetPoint(priorNode, 0);
+ start.Set(priorNode, 0);
} else {
for (int32_t pos = len - 1; pos >= 0; pos--) {
// sanity bounds check the char position. bug 136165
if (uint32_t(pos) >= textFrag->GetLength()) {
NS_NOTREACHED("looking beyond end of text fragment");
continue;
}
char16_t theChar = textFrag->CharAt(pos);
@@ -699,35 +699,35 @@ WSRunObject::GetWSNodes()
mFirstNBSPNode = textNode;
mFirstNBSPOffset = pos;
// also keep track of latest nbsp so far
if (!mLastNBSPNode) {
mLastNBSPNode = textNode;
mLastNBSPOffset = pos;
}
}
- start.SetPoint(textNode, pos);
+ start.Set(textNode, pos);
}
}
} else {
// it's a break or a special node, like <img>, that is not a block and not
// a break but still serves as a terminator to ws runs.
- mStartNode = start.node;
- mStartOffset = start.offset;
+ mStartNode = start.Container();
+ mStartOffset = start.Offset();
if (TextEditUtils::IsBreak(priorNode)) {
mStartReason = WSType::br;
} else {
mStartReason = WSType::special;
}
mStartReasonNode = priorNode;
}
} else {
// no prior node means we exhausted wsBoundingParent
- mStartNode = start.node;
- mStartOffset = start.offset;
+ mStartNode = start.Container();
+ mStartOffset = start.Offset();
mStartReason = WSType::thisBlock;
mStartReasonNode = wsBoundingParent;
}
}
// then look ahead to find following ws nodes
if (RefPtr<Text> textNode = mNode->GetAsText()) {
// don't need to put it on list. it already is from code above
@@ -754,45 +754,45 @@ WSRunObject::GetWSNodes()
mLastNBSPNode = textNode;
mLastNBSPOffset = pos;
// also keep track of earliest nbsp so far
if (!mFirstNBSPNode) {
mFirstNBSPNode = textNode;
mFirstNBSPOffset = pos;
}
}
- end.SetPoint(textNode, pos + 1);
+ end.Set(textNode, pos + 1);
}
}
}
while (!mEndNode) {
// we haven't found the end of ws yet. Keep looking
nsCOMPtr<nsIContent> nextNode = GetNextWSNode(end, wsBoundingParent);
if (nextNode) {
if (IsBlockNode(nextNode)) {
// we encountered a new block. therefore no more ws.
- mEndNode = end.node;
- mEndOffset = end.offset;
+ mEndNode = end.Container();
+ mEndOffset = end.Offset();
mEndReason = WSType::otherBlock;
mEndReasonNode = nextNode;
} else if (nextNode->IsNodeOfType(nsINode::eTEXT) &&
nextNode->IsEditable()) {
RefPtr<Text> textNode = nextNode->GetAsText();
mNodeArray.AppendElement(textNode);
const nsTextFragment *textFrag;
if (!textNode || !(textFrag = textNode->GetText())) {
return NS_ERROR_NULL_POINTER;
}
uint32_t len = textNode->TextLength();
if (len < 1) {
// Zero length text node. Set end point to it
// so we can get past it!
- end.SetPoint(textNode, 0);
+ end.Set(textNode, 0);
} else {
for (uint32_t pos = 0; pos < len; pos++) {
// sanity bounds check the char position. bug 136165
if (pos >= textFrag->GetLength()) {
NS_NOTREACHED("looking beyond end of text fragment");
continue;
}
char16_t theChar = textFrag->CharAt(pos);
@@ -808,36 +808,36 @@ WSRunObject::GetWSNodes()
mLastNBSPNode = textNode;
mLastNBSPOffset = pos;
// also keep track of earliest nbsp so far
if (!mFirstNBSPNode) {
mFirstNBSPNode = textNode;
mFirstNBSPOffset = pos;
}
}
- end.SetPoint(textNode, pos + 1);
+ end.Set(textNode, pos + 1);
}
}
} else {
// we encountered a break or a special node, like <img>,
// that is not a block and not a break but still
// serves as a terminator to ws runs.
- mEndNode = end.node;
- mEndOffset = end.offset;
+ mEndNode = end.Container();
+ mEndOffset = end.Offset();
if (TextEditUtils::IsBreak(nextNode)) {
mEndReason = WSType::br;
} else {
mEndReason = WSType::special;
}
mEndReasonNode = nextNode;
}
} else {
// no next node means we exhausted wsBoundingParent
- mEndNode = end.node;
- mEndOffset = end.offset;
+ mEndNode = end.Container();
+ mEndOffset = end.Offset();
mEndReason = WSType::thisBlock;
mEndReasonNode = wsBoundingParent;
}
}
return NS_OK;
}
@@ -1028,45 +1028,50 @@ WSRunObject::GetPreviousWSNodeInner(nsIN
return child;
}
}
// Else return the node itself
return priorNode;
}
nsIContent*
-WSRunObject::GetPreviousWSNode(EditorDOMPoint aPoint,
+WSRunObject::GetPreviousWSNode(const EditorDOMPoint& aPoint,
nsINode* aBlockParent)
{
// Can't really recycle various getnext/prior routines because we
// have special needs here. Need to step into inline containers but
// not block containers.
- MOZ_ASSERT(aPoint.node && aBlockParent);
+ MOZ_ASSERT(aPoint.IsSet() && aBlockParent);
- if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
- return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
+ if (aPoint.Container()->NodeType() == nsIDOMNode::TEXT_NODE) {
+ return GetPreviousWSNodeInner(aPoint.Container(), aBlockParent);
}
- if (!mHTMLEditor->IsContainer(aPoint.node)) {
- return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
+ if (!mHTMLEditor->IsContainer(aPoint.Container())) {
+ return GetPreviousWSNodeInner(aPoint.Container(), aBlockParent);
}
- if (!aPoint.offset) {
- if (aPoint.node == aBlockParent) {
+ if (!aPoint.Offset()) {
+ if (aPoint.Container() == aBlockParent) {
// We are at start of the block.
return nullptr;
}
// We are at start of non-block container
- return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
+ return GetPreviousWSNodeInner(aPoint.Container(), aBlockParent);
}
- nsCOMPtr<nsIContent> startContent = do_QueryInterface(aPoint.node);
- NS_ENSURE_TRUE(startContent, nullptr);
- nsCOMPtr<nsIContent> priorNode = startContent->GetChildAt(aPoint.offset - 1);
- NS_ENSURE_TRUE(priorNode, nullptr);
+ if (NS_WARN_IF(!aPoint.Container()->IsContent())) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIContent> priorNode = aPoint.GetPreviousSiblingOfChildAtOffset();
+ if (NS_WARN_IF(!priorNode)) {
+ return nullptr;
+ }
+
// We have a prior node. If it's a block, return it.
if (IsBlockNode(priorNode)) {
return priorNode;
}
if (mHTMLEditor->IsContainer(priorNode)) {
// Else if it's a container, get deep rightmost child
nsCOMPtr<nsIContent> child = mHTMLEditor->GetRightmostChild(priorNode);
if (child) {
@@ -1112,43 +1117,44 @@ WSRunObject::GetNextWSNodeInner(nsINode*
return child;
}
}
// Else return the node itself
return nextNode;
}
nsIContent*
-WSRunObject::GetNextWSNode(EditorDOMPoint aPoint,
+WSRunObject::GetNextWSNode(const EditorDOMPoint& aPoint,
nsINode* aBlockParent)
{
// Can't really recycle various getnext/prior routines because we have
// special needs here. Need to step into inline containers but not block
// containers.
- MOZ_ASSERT(aPoint.node && aBlockParent);
+ MOZ_ASSERT(aPoint.IsSet() && aBlockParent);
- if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
- return GetNextWSNodeInner(aPoint.node, aBlockParent);
+ if (aPoint.Container()->NodeType() == nsIDOMNode::TEXT_NODE) {
+ return GetNextWSNodeInner(aPoint.Container(), aBlockParent);
}
- if (!mHTMLEditor->IsContainer(aPoint.node)) {
- return GetNextWSNodeInner(aPoint.node, aBlockParent);
+ if (!mHTMLEditor->IsContainer(aPoint.Container())) {
+ return GetNextWSNodeInner(aPoint.Container(), aBlockParent);
}
- nsCOMPtr<nsIContent> startContent = do_QueryInterface(aPoint.node);
- NS_ENSURE_TRUE(startContent, nullptr);
+ if (NS_WARN_IF(!aPoint.Container()->IsContent())) {
+ return nullptr;
+ }
- nsCOMPtr<nsIContent> nextNode = startContent->GetChildAt(aPoint.offset);
+ nsCOMPtr<nsIContent> nextNode = aPoint.GetChildAtOffset();
if (!nextNode) {
- if (aPoint.node == aBlockParent) {
+ if (aPoint.Container() == aBlockParent) {
// We are at end of the block.
return nullptr;
}
// We are at end of non-block container
- return GetNextWSNodeInner(aPoint.node, aBlockParent);
+ return GetNextWSNodeInner(aPoint.Container(), aBlockParent);
}
// We have a next node. If it's a block, return it.
if (IsBlockNode(nextNode)) {
return nextNode;
}
if (mHTMLEditor->IsContainer(nextNode)) {
// else if it's a container, get deep leftmost child
--- a/editor/libeditor/WSRunObject.h
+++ b/editor/libeditor/WSRunObject.h
@@ -7,24 +7,24 @@
#define WSRunObject_h
#include "nsCOMPtr.h"
#include "nsIEditor.h" // for EDirection
#include "nsINode.h"
#include "nscore.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Text.h"
+#include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint
class nsIDOMNode;
namespace mozilla {
class HTMLEditor;
class HTMLEditRules;
-struct EditorDOMPoint;
// class WSRunObject represents the entire whitespace situation
// around a given point. It collects up a list of nodes that contain
// whitespace and categorizes in up to 3 different WSFragments (detailed
// below). Each WSFragment is a collection of whitespace that is
// either all insignificant, or that is significant. A WSFragment could
// consist of insignificant whitespace because it is after a block
// boundary or after a break. Or it could be insignificant because it
@@ -317,19 +317,21 @@ protected:
nsINode* GetWSBoundingParent();
nsresult GetWSNodes();
void GetRuns();
void ClearRuns();
void MakeSingleWSRun(WSType aType);
nsIContent* GetPreviousWSNodeInner(nsINode* aStartNode,
nsINode* aBlockParent);
- nsIContent* GetPreviousWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent);
+ nsIContent* GetPreviousWSNode(const EditorDOMPoint& aPoint,
+ nsINode* aBlockParent);
nsIContent* GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent);
- nsIContent* GetNextWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent);
+ nsIContent* GetNextWSNode(const EditorDOMPoint& aPoint,
+ nsINode* aBlockParent);
nsresult PrepareToDeleteRangePriv(WSRunObject* aEndObject);
nsresult PrepareToSplitAcrossBlocksPriv();
nsresult DeleteChars(nsINode* aStartNode, int32_t aStartOffset,
nsINode* aEndNode, int32_t aEndOffset);
WSPoint GetCharAfter(nsINode* aNode, int32_t aOffset);
WSPoint GetCharBefore(nsINode* aNode, int32_t aOffset);
WSPoint GetCharAfter(const WSPoint& aPoint);
WSPoint GetCharBefore(const WSPoint& aPoint);
--- a/editor/libeditor/moz.build
+++ b/editor/libeditor/moz.build
@@ -17,16 +17,17 @@ EXPORTS += [
'nsIEditRules.h',
]
EXPORTS.mozilla += [
'ChangeStyleTransaction.h',
'CSSEditUtils.h',
'EditorBase.h',
'EditorController.h',
+ 'EditorDOMPoint.h',
'EditorUtils.h',
'EditTransactionBase.h',
'HTMLEditor.h',
'ManualNAC.h',
'SelectionState.h',
'TextEditor.h',
'TextEditRules.h',
]