Bug 1473515 - Make AutoDisableUndo restores enabled state of undo/redo with previous number of maximum transactions r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 05 Jul 2018 19:44:23 +0900
changeset 483009 1814ad4986ce3190f509f75763536dde7e4306a2
parent 483008 b664194b632aa89d9f8c94c5948b57b2e490882e
child 483010 80d8f267abd8429bd213e109aa2c0724320e1110
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1473515
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1473515 - Make AutoDisableUndo restores enabled state of undo/redo with previous number of maximum transactions r=m_kato Calling EditorBase::EnableUndoRedo() without argument means that editor supports unlimited undo/redo stack. AutoDisableUndo class calls it without argument when it needs to restore undo/redo feature. However, <input type="text"> and <textarea> limits number of maximum transactions up to 1,000, perhaps for footprint. So, AutoDisableUndo should store the last number of maximum transactions before disabling undo/redo from the constructor. MozReview-Commit-ID: CoI6ZXyTd3X
dom/html/nsTextEditorState.cpp
editor/libeditor/EditorBase.h
editor/libeditor/tests/mochitest.ini
editor/libeditor/tests/test_undo_redo_stack_after_setting_value.html
editor/txmgr/TransactionManager.h
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -162,43 +162,53 @@ private:
 };
 
 class MOZ_RAII AutoDisableUndo final
 {
 public:
   explicit AutoDisableUndo(TextEditor* aTextEditor
                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     : mTextEditor(aTextEditor)
-    , mPreviousEnabled(true)
+    , mNumberOfMaximumTransactions(0)
   {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     MOZ_ASSERT(mTextEditor);
 
-    mPreviousEnabled = mTextEditor->IsUndoRedoEnabled();
+    mNumberOfMaximumTransactions =
+      mTextEditor ? mTextEditor->NumberOfMaximumTransactions() : 0;
     DebugOnly<bool> disabledUndoRedo = mTextEditor->DisableUndoRedo();
     NS_WARNING_ASSERTION(disabledUndoRedo,
       "Failed to disable undo/redo transactions");
   }
 
   ~AutoDisableUndo()
   {
-    if (mPreviousEnabled) {
-      DebugOnly<bool> enabledUndoRedo = mTextEditor->EnableUndoRedo();
+    // Don't change enable/disable of undo/redo if it's enabled after
+    // it's disabled by the constructor because we shouldn't change
+    // the maximum undo/redo count to the old value.
+    if (mTextEditor->IsUndoRedoEnabled()) {
+      return;
+    }
+    // If undo/redo was enabled, mNumberOfMaximumTransactions is -1 or lager
+    // than 0.  Only when it's 0, it was disabled.
+    if (mNumberOfMaximumTransactions) {
+      DebugOnly<bool> enabledUndoRedo =
+        mTextEditor->EnableUndoRedo(mNumberOfMaximumTransactions);
       NS_WARNING_ASSERTION(enabledUndoRedo,
         "Failed to enable undo/redo transactions");
     } else {
       DebugOnly<bool> disabledUndoRedo = mTextEditor->DisableUndoRedo();
       NS_WARNING_ASSERTION(disabledUndoRedo,
         "Failed to disable undo/redo transactions");
     }
   }
 
 private:
   TextEditor* mTextEditor;
-  bool mPreviousEnabled;
+  int32_t mNumberOfMaximumTransactions;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*static*/
 bool
 nsITextControlElement::GetWrapPropertyEnum(nsIContent* aContent,
   nsITextControlElement::nsHTMLTextWrap& aWrapProp)
 {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -384,21 +384,31 @@ public:
     return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
   }
   size_t NumberOfRedoItems() const
   {
     return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
   }
 
   /**
+   * Returns number of maximum undo/redo transactions.
+   */
+  int32_t NumberOfMaximumTransactions() const
+  {
+    return mTransactionManager ?
+             mTransactionManager->NumberOfMaximumTransactions() : 0;
+  }
+
+  /**
    * Returns true if this editor can store transactions for undo/redo.
    */
   bool IsUndoRedoEnabled() const
   {
-    return !!mTransactionManager;
+    return mTransactionManager &&
+           mTransactionManager->NumberOfMaximumTransactions();
   }
 
   /**
    * Return true if it's possible to undo/redo right now.
    */
   bool CanUndo() const
   {
     return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
@@ -419,18 +429,16 @@ public:
     }
     return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
   }
   bool DisableUndoRedo()
   {
     if (!mTransactionManager) {
       return true;
     }
-    // XXX Even we clear the transaction manager, IsUndoRedoEnabled() keep
-    //     returning true...
     return mTransactionManager->DisableUndoRedo();
   }
   bool ClearUndoRedo()
   {
     if (!mTransactionManager) {
       return true;
     }
     return mTransactionManager->ClearUndoRedo();
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -274,15 +274,16 @@ skip-if = os == 'android'
 [test_inlineTableEditing.html]
 [test_insertParagraph_in_inline_editing_host.html]
 [test_keypress_untrusted_event.html]
 [test_objectResizing.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
+[test_undo_redo_stack_after_setting_value.html]
 [test_backspace_vs.html]
 [test_css_chrome_load_access.html]
 skip-if = toolkit == 'android' # chrome urls not available due to packaging
 [test_selection_move_commands.html]
 [test_pasteImgTextarea.html]
 skip-if = toolkit == 'android' # bug 1299578
 [test_execCommandPaste_noTarget.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_undo_redo_stack_after_setting_value.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1473515
+-->
+<html>
+<head>
+  <title>Test for Bug 1473515</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1473515">Mozilla Bug 1473515</a>
+<p id="display"></p>
+<div id="content" style="display: none;">
+
+</div>
+
+<input id="input">
+<textarea id="textarea"></textarea>
+
+<pre id="test">
+
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  let editableElements = [
+    document.getElementById("input"),
+    document.getElementById("textarea"),
+  ];
+  for (let editableElement of editableElements) {
+    editableElement.focus();
+    synthesizeKey("a");
+    synthesizeKey("c");
+    synthesizeKey("KEY_ArrowLeft");
+    synthesizeKey("b");
+    let editor = SpecialPowers.wrap(editableElement).editor;
+    let transactionManager = editor.transactionManager;
+    is(transactionManager.numberOfUndoItems, 2,
+       editableElement.tagName + ": Initially, there should be 2 undo items");
+    // Defined as nsITextControlElement::DEFAULT_UNDO_CAP
+    is(transactionManager.maxTransactionCount, 1000,
+       editableElement.tagName + ": Initially, transaction manager should be able to have 1,000 undo items");
+    editableElement.value = "def";
+    is(transactionManager.numberOfUndoItems, 0,
+       editableElement.tagName + ": After setting value, all undo items must be deleted");
+    is(transactionManager.maxTransactionCount, 1000,
+       editableElement.tagName + ": After setting value, maximum transaction count should be restored to the previous value");
+    synthesizeKey("a");
+    synthesizeKey("z", { accelKey: true });
+    is(editableElement.value, "def",
+       editableElement.tagName + ": undo should work after setting value");
+
+    // Disable undo/redo.
+    editor.enableUndo(0);
+    is(transactionManager.maxTransactionCount, 0,
+       editableElement.tagName + ": Transaction manager should not be able to have undo items");
+    editableElement.value = "hij";
+    is(transactionManager.maxTransactionCount, 0,
+       editableElement.tagName + ": Transaction manager should not be able to have undo items after setting value");
+  }
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/editor/txmgr/TransactionManager.h
+++ b/editor/txmgr/TransactionManager.h
@@ -43,16 +43,18 @@ public:
   {
     return mUndoStack.GetSize();
   }
   size_t NumberOfRedoItems() const
   {
     return mRedoStack.GetSize();
   }
 
+  int32_t NumberOfMaximumTransactions() const { return mMaxTransactionCount; }
+
   bool EnableUndoRedo(int32_t aMaxTransactionCount = -1);
   bool DisableUndoRedo()
   {
     return EnableUndoRedo(0);
   }
   bool ClearUndoRedo()
   {
     if (NS_WARN_IF(!mDoStack.IsEmpty())) {