mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 12:57:31 +09:00
Bug 1336011 - Fix Crash in InvalidArrayIndex_CRASH in mozilla::EditorBase::DeleteSelectionImpl
* EditorBase shouldn't refer mActionListeners directly in loops because it might be removed during a loop * Create an alias of the type of mEditorObservers * Create an alias of the type of mDocStateListeners Tag #1375
This commit is contained in:
parent
5b8f93694a
commit
31048968fd
2 changed files with 124 additions and 71 deletions
|
|
@ -1385,10 +1385,13 @@ EditorBase::CreateNode(nsIAtom* aTag,
|
||||||
|
|
||||||
AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
|
AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillCreateNode(nsDependentAtomString(aTag),
|
listener->WillCreateNode(nsDependentAtomString(aTag),
|
||||||
GetAsDOMNode(aParent), aPosition);
|
GetAsDOMNode(aParent), aPosition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<Element> ret;
|
nsCOMPtr<Element> ret;
|
||||||
|
|
||||||
|
|
@ -1402,10 +1405,13 @@ EditorBase::CreateNode(nsIAtom* aTag,
|
||||||
|
|
||||||
mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
|
mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidCreateNode(nsDependentAtomString(aTag), GetAsDOMNode(ret),
|
listener->DidCreateNode(nsDependentAtomString(aTag), GetAsDOMNode(ret),
|
||||||
GetAsDOMNode(aParent), aPosition, rv);
|
GetAsDOMNode(aParent), aPosition, rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret.forget();
|
return ret.forget();
|
||||||
}
|
}
|
||||||
|
|
@ -1429,10 +1435,13 @@ EditorBase::InsertNode(nsIContent& aNode,
|
||||||
{
|
{
|
||||||
AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
|
AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
|
listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
|
||||||
aPosition);
|
aPosition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<InsertNodeTransaction> transaction =
|
RefPtr<InsertNodeTransaction> transaction =
|
||||||
CreateTxnForInsertNode(aNode, aParent, aPosition);
|
CreateTxnForInsertNode(aNode, aParent, aPosition);
|
||||||
|
|
@ -1440,10 +1449,13 @@ EditorBase::InsertNode(nsIContent& aNode,
|
||||||
|
|
||||||
mRangeUpdater.SelAdjInsertNode(aParent.AsDOMNode(), aPosition);
|
mRangeUpdater.SelAdjInsertNode(aParent.AsDOMNode(), aPosition);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition,
|
listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition,
|
||||||
rv);
|
rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -1468,9 +1480,12 @@ EditorBase::SplitNode(nsIContent& aNode,
|
||||||
{
|
{
|
||||||
AutoRules beginRulesSniffing(this, EditAction::splitNode, nsIEditor::eNext);
|
AutoRules beginRulesSniffing(this, EditAction::splitNode, nsIEditor::eNext);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillSplitNode(aNode.AsDOMNode(), aOffset);
|
listener->WillSplitNode(aNode.AsDOMNode(), aOffset);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<SplitNodeTransaction> transaction =
|
RefPtr<SplitNodeTransaction> transaction =
|
||||||
CreateTxnForSplitNode(aNode, aOffset);
|
CreateTxnForSplitNode(aNode, aOffset);
|
||||||
|
|
@ -1482,10 +1497,13 @@ EditorBase::SplitNode(nsIContent& aNode,
|
||||||
mRangeUpdater.SelAdjSplitNode(aNode, aOffset, newNode);
|
mRangeUpdater.SelAdjSplitNode(aNode, aOffset, newNode);
|
||||||
|
|
||||||
nsresult rv = aResult.StealNSResult();
|
nsresult rv = aResult.StealNSResult();
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode),
|
listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode),
|
||||||
rv);
|
rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Note: result might be a success code, so we can't use Throw() to
|
// Note: result might be a success code, so we can't use Throw() to
|
||||||
// set it on aResult.
|
// set it on aResult.
|
||||||
aResult = rv;
|
aResult = rv;
|
||||||
|
|
@ -1520,10 +1538,13 @@ EditorBase::JoinNodes(nsINode& aLeftNode,
|
||||||
// Find the number of children of the lefthand node
|
// Find the number of children of the lefthand node
|
||||||
uint32_t oldLeftNodeLen = aLeftNode.Length();
|
uint32_t oldLeftNodeLen = aLeftNode.Length();
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
|
listener->WillJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
|
||||||
parent->AsDOMNode());
|
parent->AsDOMNode());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
RefPtr<JoinNodeTransaction> transaction =
|
RefPtr<JoinNodeTransaction> transaction =
|
||||||
|
|
@ -1535,10 +1556,13 @@ EditorBase::JoinNodes(nsINode& aLeftNode,
|
||||||
mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
|
mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
|
||||||
(int32_t)oldLeftNodeLen);
|
(int32_t)oldLeftNodeLen);
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
|
listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
|
||||||
parent->AsDOMNode(), rv);
|
parent->AsDOMNode(), rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -1558,9 +1582,12 @@ EditorBase::DeleteNode(nsINode* aNode)
|
||||||
nsIEditor::ePrevious);
|
nsIEditor::ePrevious);
|
||||||
|
|
||||||
// save node location for selection updating code.
|
// save node location for selection updating code.
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillDeleteNode(aNode->AsDOMNode());
|
listener->WillDeleteNode(aNode->AsDOMNode());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<DeleteNodeTransaction> transaction;
|
RefPtr<DeleteNodeTransaction> transaction;
|
||||||
nsresult rv = CreateTxnForDeleteNode(aNode, getter_AddRefs(transaction));
|
nsresult rv = CreateTxnForDeleteNode(aNode, getter_AddRefs(transaction));
|
||||||
|
|
@ -1568,9 +1595,12 @@ EditorBase::DeleteNode(nsINode* aNode)
|
||||||
rv = DoTransaction(transaction);
|
rv = DoTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidDeleteNode(aNode->AsDOMNode(), rv);
|
listener->DidDeleteNode(aNode->AsDOMNode(), rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -1844,7 +1874,7 @@ void
|
||||||
EditorBase::NotifyEditorObservers(NotificationForEditorObservers aNotification)
|
EditorBase::NotifyEditorObservers(NotificationForEditorObservers aNotification)
|
||||||
{
|
{
|
||||||
// Copy the observers since EditAction()s can modify mEditorObservers.
|
// Copy the observers since EditAction()s can modify mEditorObservers.
|
||||||
nsTArray<mozilla::OwningNonNull<nsIEditorObserver>> observers(mEditorObservers);
|
AutoEditorObserverArray observers(mEditorObservers);
|
||||||
switch (aNotification) {
|
switch (aNotification) {
|
||||||
case eNotifyEditorObserversOfEnd:
|
case eNotifyEditorObserversOfEnd:
|
||||||
mIsInEditAction = false;
|
mIsInEditAction = false;
|
||||||
|
|
@ -2505,11 +2535,14 @@ EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let listeners know what's up
|
// Let listeners know what's up
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillInsertText(
|
listener->WillInsertText(
|
||||||
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
|
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
|
||||||
insertedOffset, aStringToInsert);
|
insertedOffset, aStringToInsert);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// XXX We may not need these view batches anymore. This is handled at a
|
// XXX We may not need these view batches anymore. This is handled at a
|
||||||
// higher level now I believe.
|
// higher level now I believe.
|
||||||
|
|
@ -2518,11 +2551,14 @@ EditorBase::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
|
||||||
EndUpdateViewBatch();
|
EndUpdateViewBatch();
|
||||||
|
|
||||||
// let listeners know what happened
|
// let listeners know what happened
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidInsertText(
|
listener->DidInsertText(
|
||||||
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
|
static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
|
||||||
insertedOffset, aStringToInsert, rv);
|
insertedOffset, aStringToInsert, rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Added some cruft here for bug 43366. Layout was crashing because we left
|
// Added some cruft here for bug 43366. Layout was crashing because we left
|
||||||
// an empty text node lying around in the document. So I delete empty text
|
// an empty text node lying around in the document. So I delete empty text
|
||||||
|
|
@ -2583,8 +2619,7 @@ EditorBase::NotifyDocumentListeners(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<OwningNonNull<nsIDocumentStateListener>>
|
AutoDocumentStateListenerArray listeners(mDocStateListeners);
|
||||||
listeners(mDocStateListeners);
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
switch (aNotificationType) {
|
switch (aNotificationType) {
|
||||||
|
|
@ -2656,20 +2691,26 @@ EditorBase::DeleteText(nsGenericDOMDataNode& aCharData,
|
||||||
nsIEditor::ePrevious);
|
nsIEditor::ePrevious);
|
||||||
|
|
||||||
// Let listeners know what's up
|
// Let listeners know what's up
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->WillDeleteText(
|
listener->WillDeleteText(
|
||||||
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
|
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
|
||||||
aLength);
|
aLength);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = DoTransaction(transaction);
|
nsresult rv = DoTransaction(transaction);
|
||||||
|
|
||||||
// Let listeners know what happened
|
// Let listeners know what happened
|
||||||
for (auto& listener : mActionListeners) {
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
|
for (auto& listener : listeners) {
|
||||||
listener->DidDeleteText(
|
listener->DidDeleteText(
|
||||||
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
|
static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
|
||||||
aLength, rv);
|
aLength, rv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -4034,24 +4075,29 @@ EditorBase::DeleteSelectionImpl(EDirection aAction,
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
|
AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
|
||||||
// Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
|
// Notify nsIEditActionListener::WillDelete[Selection|Text|Node]
|
||||||
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
if (!deleteNode) {
|
if (!deleteNode) {
|
||||||
for (auto& listener : mActionListeners) {
|
for (auto& listener : listeners) {
|
||||||
listener->WillDeleteSelection(selection);
|
listener->WillDeleteSelection(selection);
|
||||||
}
|
}
|
||||||
} else if (deleteCharData) {
|
} else if (deleteCharData) {
|
||||||
for (auto& listener : mActionListeners) {
|
for (auto& listener : listeners) {
|
||||||
listener->WillDeleteText(deleteCharData, deleteCharOffset, 1);
|
listener->WillDeleteText(deleteCharData, deleteCharOffset, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto& listener : mActionListeners) {
|
for (auto& listener : listeners) {
|
||||||
listener->WillDeleteNode(deleteNode->AsDOMNode());
|
listener->WillDeleteNode(deleteNode->AsDOMNode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the specified amount
|
// Delete the specified amount
|
||||||
rv = DoTransaction(transaction);
|
rv = DoTransaction(transaction);
|
||||||
|
|
||||||
// Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
|
// Notify nsIEditActionListener::DidDelete[Selection|Text|Node]
|
||||||
|
{
|
||||||
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
if (!deleteNode) {
|
if (!deleteNode) {
|
||||||
for (auto& listener : mActionListeners) {
|
for (auto& listener : mActionListeners) {
|
||||||
listener->DidDeleteSelection(selection);
|
listener->DidDeleteSelection(selection);
|
||||||
|
|
@ -4066,6 +4112,7 @@ EditorBase::DeleteSelectionImpl(EDirection aAction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -987,11 +987,17 @@ protected:
|
||||||
RefPtr<TextComposition> mComposition;
|
RefPtr<TextComposition> mComposition;
|
||||||
|
|
||||||
// Listens to all low level actions on the doc.
|
// Listens to all low level actions on the doc.
|
||||||
nsTArray<OwningNonNull<nsIEditActionListener>> mActionListeners;
|
typedef AutoTArray<OwningNonNull<nsIEditActionListener>, 5>
|
||||||
|
AutoActionListenerArray;
|
||||||
|
AutoActionListenerArray mActionListeners;
|
||||||
// Just notify once per high level change.
|
// Just notify once per high level change.
|
||||||
nsTArray<OwningNonNull<nsIEditorObserver>> mEditorObservers;
|
typedef AutoTArray<OwningNonNull<nsIEditorObserver>, 3>
|
||||||
|
AutoEditorObserverArray;
|
||||||
|
AutoEditorObserverArray mEditorObservers;
|
||||||
// Listen to overall doc state (dirty or not, just created, etc.).
|
// Listen to overall doc state (dirty or not, just created, etc.).
|
||||||
nsTArray<OwningNonNull<nsIDocumentStateListener>> mDocStateListeners;
|
typedef AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1>
|
||||||
|
AutoDocumentStateListenerArray;
|
||||||
|
AutoDocumentStateListenerArray mDocStateListeners;
|
||||||
|
|
||||||
// Cached selection for AutoSelectionRestorer.
|
// Cached selection for AutoSelectionRestorer.
|
||||||
SelectionState mSavedSel;
|
SelectionState mSavedSel;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue