Bug 1430021 - part 2: Make HTMLEditRules not derived from nsIEditActionListener r?m_kato
HTMLEditRules implements only some of nsIEditActionListener and this is always
first edit action listener. So, if we make EditorBase treat HTMLEditRules
directly before notifying edit action listeners, we can save a lot of runtime
cost (virtual calls especially unnecessary, copying array of edit action
listeners with strong pointer, redundant QIs), although the code becomes not
beautiful.
Perhaps, we should do same thing to nsTextServicesDocument and
mozInlineSpellChecker in other bugs.
MozReview-Commit-ID: Eveaxj398f2
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -14,16 +14,17 @@
#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
#include "EditAggregateTransaction.h" // for EditAggregateTransaction
#include "EditorEventListener.h" // for EditorEventListener
+#include "HTMLEditRules.h" // for HTMLEditRules
#include "InsertNodeTransaction.h" // for InsertNodeTransaction
#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
@@ -1426,17 +1427,17 @@ EditorBase::CreateNode(nsAtom* aTag,
// XXX We need offset at new node for 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());
AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillCreateNode(nsDependentAtomString(aTag),
GetAsDOMNode(pointToInsert.GetChild()));
}
}
nsCOMPtr<Element> ret;
@@ -1450,17 +1451,22 @@ EditorBase::CreateNode(nsAtom* aTag,
// Now, aPointToInsert may be invalid. I.e., GetChild() keeps
// referring the next sibling of new node but Offset() refers the
// new node. Let's make refer the new node.
pointToInsert.Set(ret, offset);
}
mRangeUpdater.SelAdjCreateNode(pointToInsert.AsRaw());
- {
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidCreateNode(ret);
+ }
+
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidCreateNode(nsDependentAtomString(aTag),
GetAsDOMNode(ret), rv);
}
}
return ret.forget();
@@ -1491,32 +1497,37 @@ EditorBase::InsertNode(nsIContent& aCont
{
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return NS_ERROR_INVALID_ARG;
}
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillInsertNode(
aContentToInsert.AsDOMNode(),
GetAsDOMNode(aPointToInsert.GetNextSiblingOfChild()));
}
}
RefPtr<InsertNodeTransaction> transaction =
InsertNodeTransaction::Create(*this, aContentToInsert, aPointToInsert);
nsresult rv = DoTransaction(transaction);
mRangeUpdater.SelAdjInsertNode(aPointToInsert.AsRaw());
- {
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidInsertNode(aContentToInsert);
+ }
+
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidInsertNode(aContentToInsert.AsDOMNode(), rv);
}
}
return rv;
}
@@ -1554,40 +1565,50 @@ EditorBase::SplitNode(const EditorRawDOM
}
MOZ_ASSERT(aStartOfRightNode.IsSetAndValid());
AutoRules beginRulesSniffing(this, EditAction::splitNode, nsIEditor::eNext);
// Different from CreateNode(), we need offset at start of right node only
// for WillSplitNode() since the offset is always same as the length of new
// left node.
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
// XXX Unfortunately, we need to compute offset here because the container
// may be a data node like text node. However, nobody implements this
// method actually. So, we should get rid of this in a follow up bug.
listener->WillSplitNode(aStartOfRightNode.GetContainerAsDOMNode(),
aStartOfRightNode.Offset());
}
+ } else {
+ // XXX Unfortunately, storing offset of the split point in
+ // SplitNodeTransaction is necessary for now. We should fix this
+ // in a follow up bug.
+ Unused << aStartOfRightNode.Offset();
}
RefPtr<SplitNodeTransaction> transaction =
SplitNodeTransaction::Create(*this, aStartOfRightNode);
aError = DoTransaction(transaction);
nsCOMPtr<nsIContent> newNode = transaction->GetNewNode();
NS_WARNING_ASSERTION(newNode, "Failed to create a new left node");
// XXX Some other transactions manage range updater by themselves.
// Why doesn't SplitNodeTransaction do it?
mRangeUpdater.SelAdjSplitNode(*aStartOfRightNode.GetContainerAsContent(),
newNode);
- {
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidSplitNode(aStartOfRightNode.GetContainer(), newNode);
+ }
+
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidSplitNode(aStartOfRightNode.GetContainerAsDOMNode(),
GetAsDOMNode(newNode));
}
}
if (NS_WARN_IF(aError.Failed())) {
@@ -1619,17 +1640,22 @@ EditorBase::JoinNodes(nsINode& aLeftNode
nsIEditor::ePrevious);
// Remember some values; later used for saved selection updating.
// Find the offset between the nodes to be joined.
int32_t offset = parent->IndexOf(&aRightNode);
// Find the number of children of the lefthand node
uint32_t oldLeftNodeLen = aLeftNode.Length();
- {
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->WillJoinNodes(aLeftNode, aRightNode);
+ }
+
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
parent->AsDOMNode());
}
}
nsresult rv = NS_OK;
@@ -1639,17 +1665,22 @@ EditorBase::JoinNodes(nsINode& aLeftNode
rv = DoTransaction(transaction);
}
// XXX Some other transactions manage range updater by themselves.
// Why doesn't JoinNodeTransaction do it?
mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
(int32_t)oldLeftNodeLen);
- {
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidJoinNodes(aLeftNode, aRightNode);
+ }
+
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
parent->AsDOMNode(), rv);
}
}
return rv;
@@ -1668,30 +1699,35 @@ EditorBase::DeleteNode(nsINode* aNode)
{
if (NS_WARN_IF(!aNode)) {
return NS_ERROR_INVALID_ARG;
}
AutoRules beginRulesSniffing(this, EditAction::createNode,
nsIEditor::ePrevious);
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->WillDeleteNode(aNode);
+ }
+
// save node location for selection updating code.
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillDeleteNode(aNode->AsDOMNode());
}
}
RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
DeleteNodeTransaction::MaybeCreate(*this, *aNode);
nsresult rv = deleteNodeTransaction ? DoTransaction(deleteNodeTransaction) :
NS_ERROR_FAILURE;
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidDeleteNode(aNode->AsDOMNode(), rv);
}
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -2807,33 +2843,39 @@ EditorBase::InsertTextIntoTextNodeImpl(c
insertedTextNode = mComposition->GetContainerTextNode();
insertedOffset = mComposition->XPOffsetInTextNode();
} else {
transaction =
InsertTextTransaction::Create(*this, aStringToInsert, aTextNode, aOffset);
}
// Let listeners know what's up
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillInsertText(
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
insertedOffset, aStringToInsert);
}
}
// XXX We may not need these view batches anymore. This is handled at a
// higher level now I believe.
BeginUpdateViewBatch();
nsresult rv = DoTransaction(transaction);
EndUpdateViewBatch();
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidInsertText(insertedTextNode, insertedOffset,
+ aStringToInsert);
+ }
+
// let listeners know what happened
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidInsertText(
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
insertedOffset, aStringToInsert, rv);
}
}
@@ -2951,17 +2993,17 @@ EditorBase::SetTextImpl(Selection& aSele
Text& aCharData)
{
const uint32_t length = aCharData.Length();
AutoRules beginRulesSniffing(this, EditAction::setText,
nsIEditor::eNext);
// Let listeners know what's up
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
if (length) {
listener->WillDeleteText(
static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
length);
}
if (!aString.IsEmpty()) {
@@ -2986,18 +3028,28 @@ EditorBase::SetTextImpl(Selection& aSele
DebugOnly<nsresult> rv = selection->Collapse(&aCharData, aString.Length());
NS_ASSERTION(NS_SUCCEEDED(rv),
"Selection could not be collapsed after insert");
}
mRangeUpdater.SelAdjDeleteText(&aCharData, 0, length);
mRangeUpdater.SelAdjInsertText(aCharData, 0, aString);
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ if (length) {
+ htmlEditRules->DidDeleteText(&aCharData, 0, length);
+ }
+ if (!aString.IsEmpty()) {
+ htmlEditRules->DidInsertText(&aCharData, 0, aString);
+ }
+ }
+
// Let listeners know what happened
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
if (length) {
listener->DidDeleteText(
static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
length, rv);
}
if (!aString.IsEmpty()) {
@@ -3021,29 +3073,34 @@ EditorBase::DeleteText(nsGenericDOMDataN
if (NS_WARN_IF(!transaction)) {
return NS_ERROR_FAILURE;
}
AutoRules beginRulesSniffing(this, EditAction::deleteText,
nsIEditor::ePrevious);
// Let listeners know what's up
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->WillDeleteText(
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
aLength);
}
}
nsresult rv = DoTransaction(transaction);
+ if (mRules && mRules->AsHTMLEditRules()) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidDeleteText(&aCharData, aOffset, aLength);
+ }
+
// Let listeners know what happened
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
listener->DidDeleteText(
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
aLength, rv);
}
}
@@ -3455,31 +3512,16 @@ EditorBase::GetNodeLocation(nsINode* aCh
*aOffset = GetChildOffset(aChild, parent);
MOZ_ASSERT(*aOffset != -1);
} else {
*aOffset = -1;
}
return parent;
}
-/**
- * Returns the number of things inside aNode. If aNode is text, returns number
- * of characters. If not, returns number of children nodes.
- */
-nsresult
-EditorBase::GetLengthOfDOMNode(nsIDOMNode* aNode,
- uint32_t& aCount)
-{
- aCount = 0;
- nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
- NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
- aCount = node->Length();
- return NS_OK;
-}
-
nsIContent*
EditorBase::GetPreviousNodeInternal(nsINode& aNode,
bool aFindEditableNode,
bool aNoBlockCrossing)
{
if (!IsDescendantOfEditorRoot(&aNode)) {
return nullptr;
}
@@ -4378,18 +4420,29 @@ EditorBase::DeleteSelectionImpl(EDirecti
&deleteCharLength);
if (NS_WARN_IF(!deleteSelectionTransaction)) {
return NS_ERROR_FAILURE;
}
}
nsCOMPtr<nsIDOMCharacterData> deleteCharData(do_QueryInterface(deleteNode));
AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
+
+ if (mRules && mRules->AsHTMLEditRules()) {
+ if (!deleteNode) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->WillDeleteSelection(selection);
+ } else if (!deleteCharData) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->WillDeleteNode(deleteNode);
+ }
+ }
+
// Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
- {
+ if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
if (!deleteNode) {
for (auto& listener : listeners) {
listener->WillDeleteSelection(selection);
}
} else if (deleteCharData) {
for (auto& listener : listeners) {
listener->WillDeleteText(deleteCharData, deleteCharOffset, 1);
@@ -4399,16 +4452,21 @@ EditorBase::DeleteSelectionImpl(EDirecti
listener->WillDeleteNode(deleteNode->AsDOMNode());
}
}
}
// Delete the specified amount
nsresult rv = DoTransaction(deleteSelectionTransaction);
+ if (mRules && mRules->AsHTMLEditRules() && deleteCharData) {
+ RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
+ htmlEditRules->DidDeleteText(deleteNode, deleteCharOffset, 1);
+ }
+
// Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
{
AutoActionListenerArray listeners(mActionListeners);
if (!deleteNode) {
for (auto& listener : mActionListeners) {
listener->DidDeleteSelection(selection);
}
} else if (deleteCharData) {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -751,25 +751,16 @@ public:
* Set outOffset to the offset of aChild in the parent.
* Returns the parent of aChild.
*/
static already_AddRefed<nsIDOMNode> GetNodeLocation(nsIDOMNode* aChild,
int32_t* outOffset);
static nsINode* GetNodeLocation(nsINode* aChild, int32_t* aOffset);
/**
- * Returns the number of things inside aNode in the out-param aCount.
- * @param aNode is the node to get the length of.
- * If aNode is text, returns number of characters.
- * If not, returns number of children nodes.
- * @param aCount [OUT] the result of the above calculation.
- */
- static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, uint32_t &aCount);
-
- /**
* Get the previous node.
*/
nsIContent* GetPreviousNode(const EditorRawDOMPoint& aPoint)
{
return GetPreviousNodeInternal(aPoint, false, false);
}
nsIContent* GetPreviousEditableNode(const EditorRawDOMPoint& aPoint)
{
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -194,17 +194,16 @@ HTMLEditRules::HTMLEditRules()
InitFields();
}
void
HTMLEditRules::InitFields()
{
mHTMLEditor = nullptr;
mDocChangeRange = nullptr;
- mListenerEnabled = true;
mReturnInEmptyLIKillsList = true;
mDidDeleteSelection = false;
mDidRangedDelete = false;
mRestoreContentEditableCount = false;
mUtilRange = nullptr;
mJoinOffset = 0;
mNewBlock = nullptr;
mRangeItem = new RangeItem();
@@ -233,29 +232,19 @@ HTMLEditRules::InitStyleCacheArray(Style
aStyleCache[15] = StyleCache(nsGkAtoms::acronym, nullptr);
aStyleCache[16] = StyleCache(nsGkAtoms::backgroundColor, nullptr);
aStyleCache[17] = StyleCache(nsGkAtoms::sub, nullptr);
aStyleCache[18] = StyleCache(nsGkAtoms::sup, nullptr);
}
HTMLEditRules::~HTMLEditRules()
{
- // remove ourselves as a listener to edit actions
- // In some cases, we have already been removed by
- // ~HTMLEditor, in which case we will get a null pointer here
- // which we ignore. But this allows us to add the ability to
- // switch rule sets on the fly if we want.
- if (mHTMLEditor) {
- mHTMLEditor->RemoveEditActionListener(this);
- }
-}
-
-NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLEditRules,
- TextEditRules,
- nsIEditActionListener)
+}
+
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLEditRules, TextEditRules)
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLEditRules, TextEditRules,
mDocChangeRange, mUtilRange, mNewBlock,
mRangeItem)
nsresult
HTMLEditRules::Init(TextEditor* aTextEditor)
{
@@ -303,26 +292,25 @@ HTMLEditRules::Init(TextEditor* aTextEdi
if (node->IsElement()) {
ErrorResult rv;
mDocChangeRange->SelectNode(*node, rv);
NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
AdjustSpecialBreaks();
}
- // add ourselves as a listener to edit actions
- return mHTMLEditor->AddEditActionListener(this);
+ StartToListenToEditActions();
+
+ return NS_OK;
}
nsresult
HTMLEditRules::DetachEditor()
{
- if (mHTMLEditor) {
- mHTMLEditor->RemoveEditActionListener(this);
- }
+ EndListeningToEditActions();
mHTMLEditor = nullptr;
return TextEditRules::DetachEditor();
}
nsresult
HTMLEditRules::BeforeEdit(EditAction aAction,
nsIEditor::EDirection aDirection)
{
@@ -8798,217 +8786,160 @@ HTMLEditRules::InsertBRIfNeededInternal(
RefPtr<Element> brElement =
CreateBRInternal(EditorRawDOMPoint(&aNode, 0), aInsertMozBR);
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
-NS_IMETHODIMP
-HTMLEditRules::WillCreateNode(const nsAString& aTag,
- nsIDOMNode* aNextSiblingOfNewNode)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidCreateNode(const nsAString& aTag,
- nsIDOMNode* aNewNode,
- nsresult aResult)
+void
+HTMLEditRules::DidCreateNode(Element* aNewElement)
{
if (!mListenerEnabled) {
- return NS_OK;
+ return;
+ }
+ if (NS_WARN_IF(!aNewElement)) {
+ return;
}
// assumption that Join keeps the righthand node
- nsresult rv = mUtilRange->SelectNode(aNewNode);
- NS_ENSURE_SUCCESS(rv, rv);
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillInsertNode(nsIDOMNode* aNode,
- nsIDOMNode* aNextSiblingOfNewNode)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidInsertNode(nsIDOMNode* aNode,
- nsresult aResult)
-{
- if (!mListenerEnabled) {
- return NS_OK;
- }
- nsresult rv = mUtilRange->SelectNode(aNode);
- NS_ENSURE_SUCCESS(rv, rv);
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillDeleteNode(nsIDOMNode* aChild)
+ IgnoredErrorResult error;
+ mUtilRange->SelectNode(*aNewElement, error);
+ if (NS_WARN_IF(error.Failed())) {
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::DidInsertNode(nsIContent& aContent)
{
if (!mListenerEnabled) {
- return NS_OK;
- }
- nsresult rv = mUtilRange->SelectNode(aChild);
- NS_ENSURE_SUCCESS(rv, rv);
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidDeleteNode(nsIDOMNode* aChild,
- nsresult aResult)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillSplitNode(nsIDOMNode* aExistingRightNode,
- int32_t aOffset)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidSplitNode(nsIDOMNode* aExistingRightNode,
- nsIDOMNode* aNewLeftNode)
+ return;
+ }
+ IgnoredErrorResult error;
+ mUtilRange->SelectNode(aContent, error);
+ if (NS_WARN_IF(error.Failed())) {
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::WillDeleteNode(nsINode* aChild)
{
if (!mListenerEnabled) {
- return NS_OK;
- }
- nsCOMPtr<nsINode> newLeftNode = do_QueryInterface(aNewLeftNode);
- nsCOMPtr<nsINode> existingRightNode = do_QueryInterface(aExistingRightNode);
- nsresult rv = mUtilRange->SetStartAndEnd(newLeftNode, 0,
- existingRightNode, 0);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillJoinNodes(nsIDOMNode* aLeftNode,
- nsIDOMNode* aRightNode,
- nsIDOMNode* aParent)
+ return;
+ }
+ if (NS_WARN_IF(!aChild)) {
+ return;
+ }
+ IgnoredErrorResult error;
+ mUtilRange->SelectNode(*aChild, error);
+ if (NS_WARN_IF(error.Failed())) {
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::DidSplitNode(nsINode* aExistingRightNode,
+ nsINode* aNewLeftNode)
{
if (!mListenerEnabled) {
- return NS_OK;
- }
- // remember split point
- return EditorBase::GetLengthOfDOMNode(aLeftNode, mJoinOffset);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidJoinNodes(nsIDOMNode* aLeftNode,
- nsIDOMNode* aRightNode,
- nsIDOMNode* aParent,
- nsresult aResult)
+ return;
+ }
+ nsresult rv = mUtilRange->SetStartAndEnd(aNewLeftNode, 0,
+ aExistingRightNode, 0);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::WillJoinNodes(nsINode& aLeftNode,
+ nsINode& aRightNode)
{
if (!mListenerEnabled) {
- return NS_OK;
- }
- nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
- // assumption that Join keeps the righthand node
- nsresult rv = mUtilRange->CollapseTo(rightNode, mJoinOffset);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillInsertText(nsIDOMCharacterData* aTextNode,
- int32_t aOffset,
- const nsAString& aString)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidInsertText(nsIDOMCharacterData* aTextNode,
- int32_t aOffset,
- const nsAString& aString,
- nsresult aResult)
+ return;
+ }
+ // remember split point
+ mJoinOffset = aLeftNode.Length();
+}
+
+void
+HTMLEditRules::DidJoinNodes(nsINode& aLeftNode,
+ nsINode& aRightNode)
{
if (!mListenerEnabled) {
- return NS_OK;
+ return;
+ }
+ // assumption that Join keeps the righthand node
+ nsresult rv = mUtilRange->CollapseTo(&aRightNode, mJoinOffset);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::DidInsertText(nsINode* aTextNode,
+ int32_t aOffset,
+ const nsAString& aString)
+{
+ if (!mListenerEnabled) {
+ return;
}
int32_t length = aString.Length();
- nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
- nsresult rv = mUtilRange->SetStartAndEnd(theNode, aOffset,
- theNode, aOffset + length);
+ nsresult rv = mUtilRange->SetStartAndEnd(aTextNode, aOffset,
+ aTextNode, aOffset + length);
if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillDeleteText(nsIDOMCharacterData* aTextNode,
- int32_t aOffset,
- int32_t aLength)
-{
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidDeleteText(nsIDOMCharacterData* aTextNode,
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::DidDeleteText(nsINode* aTextNode,
int32_t aOffset,
- int32_t aLength,
- nsresult aResult)
+ int32_t aLength)
{
if (!mListenerEnabled) {
- return NS_OK;
- }
- nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
- nsresult rv = mUtilRange->CollapseTo(theNode, aOffset);
+ return;
+ }
+ nsresult rv = mUtilRange->CollapseTo(aTextNode, aOffset);
if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::WillDeleteSelection(nsISelection* aSelection)
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
+}
+
+void
+HTMLEditRules::WillDeleteSelection(Selection* aSelection)
{
if (!mListenerEnabled) {
- return NS_OK;
+ return;
}
if (NS_WARN_IF(!aSelection)) {
- return NS_ERROR_INVALID_ARG;
- }
- RefPtr<Selection> selection = aSelection->AsSelection();
- // get the (collapsed) selection location
- nsCOMPtr<nsINode> startNode;
- int32_t startOffset;
- nsresult rv =
- EditorBase::GetStartNodeAndOffset(selection,
- getter_AddRefs(startNode), &startOffset);
+ return;
+ }
+ EditorRawDOMPoint startPoint = EditorBase::GetStartPoint(aSelection);
+ if (NS_WARN_IF(!startPoint.IsSet())) {
+ return;
+ }
+ EditorRawDOMPoint endPoint = EditorBase::GetEndPoint(aSelection);
+ if (NS_WARN_IF(!endPoint.IsSet())) {
+ return;
+ }
+ nsresult rv = mUtilRange->SetStartAndEnd(startPoint, endPoint);
if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- nsCOMPtr<nsINode> endNode;
- int32_t endOffset;
- rv = EditorBase::GetEndNodeAndOffset(selection,
- getter_AddRefs(endNode), &endOffset);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = mUtilRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return UpdateDocChangeRange(mUtilRange);
-}
-
-NS_IMETHODIMP
-HTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
-{
- return NS_OK;
+ return;
+ }
+ UpdateDocChangeRange(mUtilRange);
}
// Let's remove all alignment hints in the children of aNode; it can
// be an ALIGN attribute (in case we just remove it) or a CENTER
// element (here we have to remove the container and keep its
// children). We break on tables and don't look at their children.
nsresult
HTMLEditRules::RemoveAlignment(nsINode& aNode,
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -6,17 +6,16 @@
#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"
#include "nscore.h"
class nsAtom;
class nsIDOMCharacterData;
@@ -73,17 +72,16 @@ struct StyleCache final : public PropIte
{
MOZ_COUNT_DTOR(StyleCache);
}
};
#define SIZE_STYLE_TABLE 19
class HTMLEditRules : public TextEditRules
- , public nsIEditActionListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditRules, TextEditRules)
HTMLEditRules();
// TextEditRules methods
@@ -105,47 +103,33 @@ public:
nsresult GetListState(bool* aMixed, bool* aOL, bool* aUL, bool* aDL);
nsresult GetListItemState(bool* aMixed, bool* aLI, bool* aDT, bool* aDD);
nsresult GetIndentState(bool* aCanIndent, bool* aCanOutdent);
nsresult GetAlignment(bool* aMixed, nsIHTMLEditor::EAlignment* aAlign);
nsresult GetParagraphState(bool* aMixed, nsAString& outFormat);
nsresult MakeSureElemStartsOrEndsOnCR(nsINode& aNode);
- // nsIEditActionListener methods
+ void DidCreateNode(Element* aNewElement);
+ void DidInsertNode(nsIContent& aNode);
+ void WillDeleteNode(nsINode* aChild);
+ void DidSplitNode(nsINode* aExistingRightNode,
+ nsINode* aNewLeftNode);
+ void WillJoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
+ void DidJoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
+ void DidInsertText(nsINode* aTextNode, int32_t aOffset,
+ const nsAString& aString);
+ void DidDeleteText(nsINode* aTextNode, int32_t aOffset, int32_t aLength);
+ void WillDeleteSelection(Selection* aSelection);
- NS_IMETHOD WillCreateNode(const nsAString& aTag,
- nsIDOMNode* aNextSiblingOfNewNode) override;
- NS_IMETHOD DidCreateNode(const nsAString& aTag, nsIDOMNode* aNewNode,
- nsresult aResult) override;
- NS_IMETHOD WillInsertNode(nsIDOMNode* aNode,
- nsIDOMNode* aNextSiblingOfNewNode) override;
- NS_IMETHOD DidInsertNode(nsIDOMNode* aNode, nsresult aResult) override;
- NS_IMETHOD WillDeleteNode(nsIDOMNode* aChild) override;
- NS_IMETHOD DidDeleteNode(nsIDOMNode* aChild, nsresult aResult) override;
- NS_IMETHOD WillSplitNode(nsIDOMNode* aExistingRightNode,
- int32_t aOffset) override;
- NS_IMETHOD DidSplitNode(nsIDOMNode* aExistingRightNode,
- nsIDOMNode* aNewLeftNode) override;
- NS_IMETHOD WillJoinNodes(nsIDOMNode* aLeftNode, nsIDOMNode* aRightNode,
- nsIDOMNode* aParent) override;
- NS_IMETHOD DidJoinNodes(nsIDOMNode* aLeftNode, nsIDOMNode* aRightNode,
- nsIDOMNode* aParent, nsresult aResult) override;
- NS_IMETHOD WillInsertText(nsIDOMCharacterData* aTextNode, int32_t aOffset,
- const nsAString &aString) override;
- NS_IMETHOD DidInsertText(nsIDOMCharacterData* aTextNode, int32_t aOffset,
- const nsAString &aString, nsresult aResult) override;
- NS_IMETHOD WillDeleteText(nsIDOMCharacterData* aTextNode, int32_t aOffset,
- int32_t aLength) override;
- NS_IMETHOD DidDeleteText(nsIDOMCharacterData* aTextNode, int32_t aOffset,
- int32_t aLength, nsresult aResult) override;
- NS_IMETHOD WillDeleteSelection(nsISelection* aSelection) override;
- NS_IMETHOD DidDeleteSelection(nsISelection* aSelection) override;
void DeleteNodeIfCollapsedText(nsINode& aNode);
+ void StartToListenToEditActions() { mListenerEnabled = true; }
+ void EndListeningToEditActions() { mListenerEnabled = false; }
+
protected:
virtual ~HTMLEditRules();
enum RulesEndpoint
{
kStart,
kEnd
};
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -130,23 +130,18 @@ HTMLEditor::HTMLEditor()
Preferences::GetBool("editor.use_div_for_default_newlines", true)
? ParagraphSeparator::div : ParagraphSeparator::br)
{
mIsHTMLEditorClass = true;
}
HTMLEditor::~HTMLEditor()
{
- // remove the rules as an action listener. Else we get a bad
- // ownership loop later on. it's ok if the rules aren't a listener;
- // we ignore the error.
- if (mRules) {
- nsCOMPtr<nsIEditActionListener> listener =
- static_cast<nsIEditActionListener*>(mRules->AsHTMLEditRules());
- RemoveEditActionListener(listener);
+ if (mRules && mRules->AsHTMLEditRules()) {
+ mRules->AsHTMLEditRules()->EndListeningToEditActions();
}
//the autopointers will clear themselves up.
//but we need to also remove the listeners or we have a leak
RefPtr<Selection> selection = GetSelection();
// if we don't get the selection, just skip this
if (selection) {
nsCOMPtr<nsISelectionListener>listener;