зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1572375 - part 3: Get rid of `TextEditRules::WillUndo()`, `TextEditRules::DidUndo()`, `TextEditRules::WillRedo()` and `TextEditRules::DidRedo()` r=m_kato
`TextEditRules::WillUndo()` and `TextEditRules::WillRedo()` only check whether the editor is readonly/disabled or not. So, `TextEditor::UndoAsAction()` and `TextEditor::RedoAsAction()` should do it first. `TextEditRules::DidUndo()` and `TextEditRules::DidRedo()` only set or unset `mPaddingBRElementForEmptyEditor` if it's restored by undo or redo. Therefore, we can move the code into `TextEditor::UndoAsAction()` and `TextEditor::RedoAsAction()`. Note that this patch makes `TextEditor::UndoAsAction()` discard the result of `TransactionManager::Undo()` because this is inconsistent from what `TextEditor::RedoAsAction()` does and this was changed by part 5 of bug 1447924. https://hg.mozilla.org/mozilla-central/rev/869a1445816be7f43f54f7c97f28e4c6273fa75f Differential Revision: https://phabricator.services.mozilla.com/D41157 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b0606032ba
Коммит
d88036fb98
|
@ -665,9 +665,7 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
|
||||
// Deal with actions for which we don't need to check whether the selection is
|
||||
// editable.
|
||||
if (aInfo.mEditSubAction == EditSubAction::eComputeTextToOutput ||
|
||||
aInfo.mEditSubAction == EditSubAction::eUndo ||
|
||||
aInfo.mEditSubAction == EditSubAction::eRedo) {
|
||||
if (aInfo.mEditSubAction == EditSubAction::eComputeTextToOutput) {
|
||||
return TextEditRules::WillDoAction(aInfo, aCancel, aHandled);
|
||||
}
|
||||
|
||||
|
@ -774,6 +772,10 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
return WillRelativeChangeZIndex(-1, aCancel, aHandled);
|
||||
case EditSubAction::eIncreaseZIndex:
|
||||
return WillRelativeChangeZIndex(1, aCancel, aHandled);
|
||||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
return TextEditRules::WillDoAction(aInfo, aCancel, aHandled);
|
||||
}
|
||||
|
@ -807,6 +809,13 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
|
|||
}
|
||||
return DidAbsolutePosition();
|
||||
}
|
||||
case EditSubAction::eInsertElement:
|
||||
case EditSubAction::eInsertQuotedText:
|
||||
return NS_OK;
|
||||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
return TextEditRules::DidDoAction(aInfo, aResult);
|
||||
}
|
||||
|
|
|
@ -318,10 +318,6 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
return WillSetText(aCancel, aHandled, aInfo.inString, aInfo.maxLength);
|
||||
case EditSubAction::eDeleteSelectedContent:
|
||||
return WillDeleteSelection(aInfo.collapsedAction, aCancel, aHandled);
|
||||
case EditSubAction::eUndo:
|
||||
return WillUndo(aCancel, aHandled);
|
||||
case EditSubAction::eRedo:
|
||||
return WillRedo(aCancel, aHandled);
|
||||
case EditSubAction::eSetTextProperty:
|
||||
return WillSetTextProperty(aCancel, aHandled);
|
||||
case EditSubAction::eRemoveTextProperty:
|
||||
|
@ -343,6 +339,8 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
return rv;
|
||||
}
|
||||
case EditSubAction::eInsertElement:
|
||||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
|
@ -365,10 +363,11 @@ nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
|
|||
switch (aInfo.mEditSubAction) {
|
||||
case EditSubAction::eDeleteSelectedContent:
|
||||
return DidDeleteSelection();
|
||||
case EditSubAction::eInsertElement:
|
||||
case EditSubAction::eUndo:
|
||||
return DidUndo(aResult);
|
||||
case EditSubAction::eRedo:
|
||||
return DidRedo(aResult);
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
// Don't fail on transactions we don't handle here!
|
||||
return NS_OK;
|
||||
|
@ -1124,89 +1123,6 @@ nsresult TextEditRules::DidDeleteSelection() {
|
|||
return err.StealNSResult();
|
||||
}
|
||||
|
||||
nsresult TextEditRules::WillUndo(bool* aCancel, bool* aHandled) {
|
||||
if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
// initialize out param
|
||||
*aCancel = false;
|
||||
*aHandled = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TextEditRules::DidUndo(nsresult aResult) {
|
||||
MOZ_ASSERT(IsEditorDataAvailable());
|
||||
|
||||
// If aResult is an error, we return it.
|
||||
if (NS_WARN_IF(NS_FAILED(aResult))) {
|
||||
return aResult;
|
||||
}
|
||||
|
||||
Element* rootElement = TextEditorRef().GetRoot();
|
||||
if (NS_WARN_IF(!rootElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The idea here is to see if the magic empty node has suddenly reappeared as
|
||||
// the result of the undo. If it has, set our state so we remember it.
|
||||
// There is a tradeoff between doing here and at redo, or doing it everywhere
|
||||
// else that might care. Since undo and redo are relatively rare, it makes
|
||||
// sense to take the (small) performance hit here.
|
||||
nsIContent* node = TextEditorRef().GetLeftmostChild(rootElement);
|
||||
if (node && EditorBase::IsPaddingBRElementForEmptyEditor(*node)) {
|
||||
TextEditorRef().mPaddingBRElementForEmptyEditor =
|
||||
static_cast<HTMLBRElement*>(node);
|
||||
} else {
|
||||
TextEditorRef().mPaddingBRElementForEmptyEditor = nullptr;
|
||||
}
|
||||
return aResult;
|
||||
}
|
||||
|
||||
nsresult TextEditRules::WillRedo(bool* aCancel, bool* aHandled) {
|
||||
if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
// initialize out param
|
||||
*aCancel = false;
|
||||
*aHandled = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TextEditRules::DidRedo(nsresult aResult) {
|
||||
MOZ_ASSERT(IsEditorDataAvailable());
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
return aResult; // if aResult is an error, we return it.
|
||||
}
|
||||
|
||||
Element* rootElement = TextEditorRef().GetRoot();
|
||||
if (NS_WARN_IF(!rootElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHTMLCollection> nodeList =
|
||||
rootElement->GetElementsByTagName(NS_LITERAL_STRING("br"));
|
||||
MOZ_ASSERT(nodeList);
|
||||
uint32_t len = nodeList->Length();
|
||||
|
||||
if (len != 1) {
|
||||
// only in the case of one br could there be the padding <br> element.
|
||||
TextEditorRef().mPaddingBRElementForEmptyEditor = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element* brElement = nodeList->Item(0);
|
||||
if (EditorBase::IsPaddingBRElementForEmptyEditor(*brElement)) {
|
||||
TextEditorRef().mPaddingBRElementForEmptyEditor =
|
||||
static_cast<HTMLBRElement*>(brElement);
|
||||
} else {
|
||||
TextEditorRef().mPaddingBRElementForEmptyEditor = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
|
||||
nsAString* aOutString, uint32_t aFlags,
|
||||
bool* aCancel, bool* aHandled) {
|
||||
|
|
|
@ -224,12 +224,6 @@ class TextEditRules {
|
|||
|
||||
nsresult WillRemoveTextProperty(bool* aCancel, bool* aHandled);
|
||||
|
||||
nsresult WillUndo(bool* aCancel, bool* aHandled);
|
||||
nsresult DidUndo(nsresult aResult);
|
||||
|
||||
nsresult WillRedo(bool* aCancel, bool* aHandled);
|
||||
nsresult DidRedo(nsresult aResult);
|
||||
|
||||
/**
|
||||
* Called prior to nsIEditor::OutputToString.
|
||||
*
|
||||
|
|
|
@ -1514,6 +1514,10 @@ TextEditor::SetNewlineHandling(int32_t aNewlineHandling) {
|
|||
}
|
||||
|
||||
nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
||||
if (aCount == 0 || IsReadonly() || IsDisabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we don't have transaction in the undo stack, we shouldn't notify
|
||||
// anybody of trying to undo since it's not useful notification but we
|
||||
// need to pay some runtime cost.
|
||||
|
@ -1534,9 +1538,6 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Protect the edit rules object from dying.
|
||||
RefPtr<TextEditRules> rules(mRules);
|
||||
|
||||
AutoUpdateViewBatch preventSelectionChangeEvent(*this);
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
|
@ -1544,26 +1545,36 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsresult rv = NS_OK;
|
||||
{
|
||||
AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
|
||||
*this, EditSubAction::eUndo, nsIEditor::eNone);
|
||||
|
||||
EditSubActionInfo subActionInfo(EditSubAction::eUndo);
|
||||
bool cancel, handled;
|
||||
rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
|
||||
if (!cancel && NS_SUCCEEDED(rv)) {
|
||||
RefPtr<TransactionManager> transactionManager(mTransactionManager);
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
rv = transactionManager->Undo();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
break;
|
||||
}
|
||||
DoAfterUndoTransaction();
|
||||
RefPtr<TransactionManager> transactionManager(mTransactionManager);
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
if (NS_WARN_IF(NS_FAILED(transactionManager->Undo()))) {
|
||||
break;
|
||||
}
|
||||
DoAfterUndoTransaction();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mRootElement)) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
} else {
|
||||
// The idea here is to see if the magic empty node has suddenly
|
||||
// reappeared as the result of the undo. If it has, set our state
|
||||
// so we remember it. There is a tradeoff between doing here and
|
||||
// at redo, or doing it everywhere else that might care. Since undo
|
||||
// and redo are relatively rare, it makes sense to take the (small)
|
||||
// performance hit here.
|
||||
nsIContent* leftMostChild = GetLeftmostChild(mRootElement);
|
||||
if (leftMostChild &&
|
||||
EditorBase::IsPaddingBRElementForEmptyEditor(*leftMostChild)) {
|
||||
mPaddingBRElementForEmptyEditor =
|
||||
static_cast<HTMLBRElement*>(leftMostChild);
|
||||
} else {
|
||||
mPaddingBRElementForEmptyEditor = nullptr;
|
||||
}
|
||||
rv = rules->DidDoAction(subActionInfo, rv);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"TextEditRules::DidDoAction() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1575,6 +1586,10 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
}
|
||||
|
||||
nsresult TextEditor::RedoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
||||
if (aCount == 0 || IsReadonly() || IsDisabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we don't have transaction in the redo stack, we shouldn't notify
|
||||
// anybody of trying to redo since it's not useful notification but we
|
||||
// need to pay some runtime cost.
|
||||
|
@ -1595,9 +1610,6 @@ nsresult TextEditor::RedoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Protect the edit rules object from dying.
|
||||
RefPtr<TextEditRules> rules(mRules);
|
||||
|
||||
AutoUpdateViewBatch preventSelectionChangeEvent(*this);
|
||||
|
||||
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
|
||||
|
@ -1605,26 +1617,38 @@ nsresult TextEditor::RedoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsresult rv = NS_OK;
|
||||
{
|
||||
AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
|
||||
*this, EditSubAction::eRedo, nsIEditor::eNone);
|
||||
|
||||
EditSubActionInfo subActionInfo(EditSubAction::eRedo);
|
||||
bool cancel, handled;
|
||||
rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
|
||||
if (!cancel && NS_SUCCEEDED(rv)) {
|
||||
RefPtr<TransactionManager> transactionManager(mTransactionManager);
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
nsresult rv = transactionManager->Redo();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
break;
|
||||
}
|
||||
DoAfterRedoTransaction();
|
||||
RefPtr<TransactionManager> transactionManager(mTransactionManager);
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
if (NS_WARN_IF(NS_FAILED(transactionManager->Redo()))) {
|
||||
break;
|
||||
}
|
||||
DoAfterRedoTransaction();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mRootElement)) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
} else {
|
||||
// We may take empty <br> element for empty editor back with this redo.
|
||||
// We need to store it again.
|
||||
// XXX Looks like that this is too slow if there are a lot of nodes.
|
||||
// Shouldn't we just scan children in the root?
|
||||
nsCOMPtr<nsIHTMLCollection> nodeList =
|
||||
mRootElement->GetElementsByTagName(NS_LITERAL_STRING("br"));
|
||||
MOZ_ASSERT(nodeList);
|
||||
Element* brElement =
|
||||
nodeList->Length() == 1 ? nodeList->Item(0) : nullptr;
|
||||
if (brElement &&
|
||||
EditorBase::IsPaddingBRElementForEmptyEditor(*brElement)) {
|
||||
mPaddingBRElementForEmptyEditor =
|
||||
static_cast<HTMLBRElement*>(brElement);
|
||||
} else {
|
||||
mPaddingBRElementForEmptyEditor = nullptr;
|
||||
}
|
||||
rv = rules->DidDoAction(subActionInfo, rv);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"TextEditRules::DidDoAction() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче