Bug 1386960 - Call nsTextInputListener's callback manually after using the non-transaction based editor code path for setting values of input controls; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 04 Aug 2017 17:31:12 -0400
changeset 425521 fe97dc518033d4fec46f2feb60236e5997b8212d
parent 425520 ccc4663a6c255cd70bace1e4680fee660505f316
child 425522 c6ca0e3b1c53fc67de6de78432731a9119f93ba1
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1386960
milestone57.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 1386960 - Call nsTextInputListener's callback manually after using the non-transaction based editor code path for setting values of input controls; r=bzbarsky
dom/html/nsTextEditorState.cpp
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -797,34 +797,38 @@ nsTextInputSelectionImpl::CheckVisibilit
   }
 
   nsCOMPtr<nsISelectionController> shell = do_QueryReferent(mPresShellWeak);
   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
 
   return shell->CheckVisibilityContent(aNode, aStartOffset, aEndOffset, aRetval);
 }
 
-class nsTextInputListener : public nsISelectionListener,
-                            public nsIDOMEventListener,
-                            public nsIEditorObserver,
-                            public nsSupportsWeakReference
+class nsTextInputListener final : public nsISelectionListener,
+                                  public nsIDOMEventListener,
+                                  public nsIEditorObserver,
+                                  public nsSupportsWeakReference
 {
 public:
   /** the default constructor
    */
   explicit nsTextInputListener(nsITextControlElement* aTxtCtrlElement);
 
   /** SetEditor gives an address to the editor that will be accessed
    *  @param aEditor the editor this listener calls for editing operations
    */
   void SetFrame(nsTextControlFrame *aFrame){mFrame = aFrame;}
 
   void SettingValue(bool aValue) { mSettingValue = aValue; }
   void SetValueChanged(bool aSetValueChanged) { mSetValueChanged = aSetValueChanged; }
 
+  // aFrame is an optional pointer to our frame, if not passed the method will
+  // use mFrame to compute it lazily.
+  void HandleValueChanged(nsTextControlFrame* aFrame = nullptr);
+
   NS_DECL_ISUPPORTS
 
   NS_DECL_NSISELECTIONLISTENER
 
   NS_DECL_NSIDOMEVENTLISTENER
 
   NS_DECL_NSIEDITOROBSERVER
 
@@ -1077,28 +1081,39 @@ nsTextInputListener::EditAction()
     mHadUndoItems = numUndoItems != 0;
     mHadRedoItems = numRedoItems != 0;
   }
 
   if (!weakFrame.IsAlive()) {
     return NS_OK;
   }
 
+  HandleValueChanged(frame);
+
+  return NS_OK;
+}
+
+void
+nsTextInputListener::HandleValueChanged(nsTextControlFrame* aFrame)
+{
   // Make sure we know we were changed (do NOT set this to false if there are
   // no undo items; JS could change the value and we'd still need to save it)
   if (mSetValueChanged) {
-    frame->SetValueChanged(true);
+    if (!aFrame) {
+      nsITextControlFrame* frameBase = do_QueryFrame(mFrame);
+      aFrame = static_cast<nsTextControlFrame*> (frameBase);
+      NS_ASSERTION(aFrame, "Where is our frame?");
+    }
+    aFrame->SetValueChanged(true);
   }
 
   if (!mSettingValue) {
     mTxtCtrlElement->OnValueChanged(/* aNotify = */ true,
                                     /* aWasInteractiveUserChange = */ true);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextInputListener::BeforeEditAction()
 {
   return NS_OK;
 }
 
@@ -2679,16 +2694,21 @@ nsTextEditorState::SetValue(const nsAStr
             AutoDisableUndo disableUndo(textEditor);
             if (domSel) {
               // Since we don't use undo transaction, we don't need to store
               // selection state.  SetText will set selection to tail.
               domSel->RemoveAllRanges();
             }
 
             textEditor->SetText(newValue);
+
+            // Call the listener's HandleValueChanged() callback manually, since
+            // we don't use the transaction manager in this path and it could be
+            // that the editor would bypass calling the listener for that reason.
+            mTextListener->HandleValueChanged();
           }
 
           mTextListener->SetValueChanged(true);
           mTextListener->SettingValue(false);
 
           if (!notifyValueChanged) {
             // Listener doesn't update frame, but it is required for placeholder
             ValueWasChanged(true);