Bug 668606 input event should be fired on all editors r=ehsan+smaug, sr=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 27 Mar 2012 10:36:44 +0900
changeset 93690 e4d4400c93b1f44a5c7cca84ce42d80801d8a7bb
parent 93689 127fdbb5639a0d8203b392a50efc5fa8ff1201b3
child 93691 18801aa145f05c61bca7ce946cb396914b690114
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, smaug
bugs668606
milestone14.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 668606 input event should be fired on all editors r=ehsan+smaug, sr=smaug
content/html/content/src/nsTextEditorState.cpp
editor/idl/nsIEditor.idl
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/tests/Makefile.in
editor/libeditor/html/tests/test_dom_input_event_on_htmleditor.html
editor/libeditor/text/nsPlaintextDataTransfer.cpp
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsPlaintextEditor.h
editor/libeditor/text/tests/Makefile.in
editor/libeditor/text/tests/test_dom_input_event_on_texteditor.html
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -870,24 +870,16 @@ nsTextInputListener::EditAction()
   // 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)
   frame->SetValueChanged(true);
 
   if (!mSettingValue) {
     mTxtCtrlElement->OnValueChanged(true);
   }
 
-  // Fire input event
-  bool trusted = false;
-  editor->GetLastKeypressEventTrusted(&trusted);
-  frame->FireOnInput(trusted);
-
-  // mFrame may be dead after this, but we don't need to check for it, because
-  // we are not uisng it in this function any more.
-
   return NS_OK;
 }
 
 // END nsIEditorObserver
 
 
 nsresult
 nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
@@ -1770,17 +1762,17 @@ nsTextEditorState::SetValue(const nsAStr
       mBoundFrame->GetText(currentValue);
     }
 
     nsWeakFrame weakFrame(mBoundFrame);
 
     // this is necessary to avoid infinite recursion
     if (!currentValue.Equals(aValue))
     {
-      nsTextControlFrame::ValueSetter valueSetter(mBoundFrame,
+      nsTextControlFrame::ValueSetter valueSetter(mBoundFrame, mEditor,
                                                   mBoundFrame->mFocusedValue.Equals(currentValue));
 
       // \r is an illegal character in the dom, but people use them,
       // so convert windows and mac platform linebreaks to \n:
       // Unfortunately aValue is declared const, so we have to copy
       // in order to do this substitution.
       nsString newValue(aValue);
       if (aValue.FindChar(PRUnichar('\r')) != -1) {
--- a/editor/idl/nsIEditor.idl
+++ b/editor/idl/nsIEditor.idl
@@ -50,17 +50,17 @@ interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
 interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
-[scriptable, uuid(656005d2-d900-4839-81bf-6274a3c38537)]
+[scriptable, uuid(2e14b183-29d4-4282-9475-589277a70654)]
 
 interface nsIEditor  : nsISupports
 {
 %{C++
   typedef short EDirection;
 %}
   const short eNone = 0;
   const short eNext = 1;
@@ -561,15 +561,11 @@ interface nsIEditor  : nsISupports
   void debugDumpContent() ;
 
   /* Run unit tests. Noop in optimized builds */
   void debugUnitTests(out long outNumTests, out long  outNumTestsFailed);
 
   /* checks if a node is read-only or not */
   [notxpcom] boolean isModifiableNode(in nsIDOMNode aNode);
 
-  /**
-   * Will be set to true if the last keypress event that the editor has handled
-   * has been trusted.  The value will only be valid when the edit action listeners
-   * are being called, and will throw upon access at all other times.
-   */
-  readonly attribute boolean lastKeypressEventTrusted;
+  /* Set true if you want to suppress dispatching input event. */
+  attribute boolean suppressDispatchingInputEvent;
 };
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -165,17 +165,19 @@ nsEditor::nsEditor()
 ,  mInIMEMode(false)
 ,  mIsIMEComposing(false)
 ,  mShouldTxnSetSelection(true)
 ,  mDidPreDestroy(false)
 ,  mDidPostCreate(false)
 ,  mDocDirtyState(-1)
 ,  mDocWeak(nsnull)
 ,  mPhonetic(nsnull)
-,  mLastKeypressEventWasTrusted(eTriUnset)
+,  mHandlingActionCount(0)
+,  mHandlingTrustedAction(false)
+,  mDispatchInputEvent(true)
 {
   //initialize member variables here
 }
 
 nsEditor::~nsEditor()
 {
   NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?");
 
@@ -1761,22 +1763,77 @@ nsEditor::RemoveEditorObserver(nsIEditor
   NS_ENSURE_TRUE(aObserver, NS_ERROR_FAILURE);
 
   if (!mEditorObservers.RemoveObject(aObserver))
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
+class EditorInputEventDispatcher : public nsRunnable
+{
+public:
+  EditorInputEventDispatcher(nsEditor* aEditor,
+                             bool aIsTrusted,
+                             nsIContent* aTarget) :
+    mEditor(aEditor), mTarget(aTarget), mIsTrusted(aIsTrusted)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    // Note that we don't need to check mDispatchInputEvent here.  We need
+    // to check it only when the editor requests to dispatch the input event.
+
+    if (!mTarget->IsInDoc()) {
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIPresShell> ps = mEditor->GetPresShell();
+    if (!ps) {
+      return NS_OK;
+    }
+
+    nsEvent inputEvent(mIsTrusted, NS_FORM_INPUT);
+    inputEvent.flags |= NS_EVENT_FLAG_CANT_CANCEL;
+    inputEvent.time = static_cast<PRUint64>(PR_Now() / 1000);
+    nsEventStatus status = nsEventStatus_eIgnore;
+    nsresult rv =
+      ps->HandleEventWithTarget(&inputEvent, nsnull, mTarget, &status);
+    NS_ENSURE_SUCCESS(rv, NS_OK); // print the warning if error
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<nsEditor> mEditor;
+  nsCOMPtr<nsIContent> mTarget;
+  bool mIsTrusted;
+};
+
 void nsEditor::NotifyEditorObservers(void)
 {
-  for (PRInt32 i = 0; i < mEditorObservers.Count(); i++)
+  for (PRInt32 i = 0; i < mEditorObservers.Count(); i++) {
     mEditorObservers[i]->EditAction();
-}
-
+  }
+
+  if (!mDispatchInputEvent) {
+    return;
+  }
+
+  // We don't need to dispatch multiple input events if there is a pending
+  // input event.  However, it may have different event target.  If we resolved
+  // this issue, we need to manage the pending events in an array.  But it's
+  // overwork.  We don't need to do it for the very rare case.
+
+  nsCOMPtr<nsIContent> target = GetInputEventTargetContent();
+  NS_ENSURE_TRUE(target, );
+
+  nsContentUtils::AddScriptRunner(
+     new EditorInputEventDispatcher(this, mHandlingTrustedAction, target));
+}
 
 NS_IMETHODIMP
 nsEditor::AddEditActionListener(nsIEditActionListener *aListener)
 {
   NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
 
   // Make sure the listener isn't already on the list
   if (mActionListeners.IndexOf(aListener) == -1) 
@@ -5381,41 +5438,41 @@ nsEditor::IsAcceptableInputEvent(nsIDOME
     return false;
   }
 
   // Otherwise, we shouldn't handle any input events when we're not an active
   // element of the DOM window.
   return IsActiveInDOMWindow();
 }
 
-NS_IMETHODIMP
-nsEditor::GetLastKeypressEventTrusted(bool *aWasTrusted)
-{
-  NS_ENSURE_ARG_POINTER(aWasTrusted);
-
-  if (mLastKeypressEventWasTrusted == eTriUnset) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  *aWasTrusted = (mLastKeypressEventWasTrusted == eTriTrue);
-  return NS_OK;
-}
-
-void
-nsEditor::BeginKeypressHandling(nsIDOMNSEvent* aEvent)
-{
-  NS_ASSERTION(mLastKeypressEventWasTrusted == eTriUnset, "How come our status is not clear?");
-
-  if (aEvent) {
-    bool isTrusted = false;
-    aEvent->GetIsTrusted(&isTrusted);
-    mLastKeypressEventWasTrusted = isTrusted ? eTriTrue : eTriFalse;
-  }
-}
-
 void
 nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
 {
   InitializeSelection(aFocusEventTarget);
   if (mInlineSpellChecker) {
     mInlineSpellChecker->UpdateCurrentDictionary();
   }
 }
+
+NS_IMETHODIMP
+nsEditor::GetSuppressDispatchingInputEvent(bool *aSuppressed)
+{
+  NS_ENSURE_ARG_POINTER(aSuppressed);
+  *aSuppressed = !mDispatchInputEvent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEditor::SetSuppressDispatchingInputEvent(bool aSuppress)
+{
+  mDispatchInputEvent = !aSuppress;
+  return NS_OK;
+}
+
+nsEditor::HandlingTrustedAction::HandlingTrustedAction(nsEditor* aSelf,
+                                                       nsIDOMNSEvent* aEvent)
+{
+  MOZ_ASSERT(aEvent);
+
+  bool isTrusted = false;
+  aEvent->GetIsTrusted(&isTrusted);
+  Init(aSelf, isTrusted);
+}
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -212,39 +212,16 @@ public:
   // IME event handlers
   virtual nsresult BeginIMEComposition();
   virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
                                         nsIPrivateTextRangeList *aTextRange)=0;
   nsresult EndIMEComposition();
 
   void SwitchTextDirectionTo(PRUint32 aDirection);
 
-  void BeginKeypressHandling() { mLastKeypressEventWasTrusted = eTriTrue; }
-  void BeginKeypressHandling(nsIDOMNSEvent* aEvent);
-  void EndKeypressHandling() { mLastKeypressEventWasTrusted = eTriUnset; }
-
-  class FireTrustedInputEvent {
-  public:
-    explicit FireTrustedInputEvent(nsEditor* aSelf, bool aActive = true)
-      : mEditor(aSelf)
-      , mShouldAct(aActive && mEditor->mLastKeypressEventWasTrusted == eTriUnset) {
-      if (mShouldAct) {
-        mEditor->BeginKeypressHandling();
-      }
-    }
-    ~FireTrustedInputEvent() {
-      if (mShouldAct) {
-        mEditor->EndKeypressHandling();
-      }
-    }
-  private:
-    nsEditor* mEditor;
-    bool mShouldAct;
-  };
-
 protected:
   nsCString mContentMIMEType;       // MIME type of the doc we are editing.
 
   nsresult DetermineCurrentDirection();
 
   /** create a transaction for setting aAttribute to aValue on aElement
     */
   NS_IMETHOD CreateTxnForSetAttribute(nsIDOMElement *aElement, 
@@ -723,16 +700,19 @@ public:
   }
 
   bool IsTabbable() const
   {
     return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
            IsInteractionAllowed();
   }
 
+  // Get the input event target. This might return null.
+  virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0;
+
   // Get the focused content, if we're focused.  Returns null otherwise.
   virtual already_AddRefed<nsIContent> GetFocusedContent();
 
   // Whether the editor is active on the DOM window.  Note that when this
   // returns true but GetFocusedContent() returns null, it means that this editor was
   // focused when the DOM window was active.
   virtual bool IsActiveInDOMWindow();
 
@@ -768,16 +748,55 @@ public:
                                           nsIDOMNode *aDestinationNode,
                                           PRInt32 aDestOffset,
                                           bool aDoDeleteSelection) = 0;
 
   virtual nsresult InsertFromDrop(nsIDOMEvent* aDropEvent) = 0;
 
   virtual already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode) { return nsnull; }
 
+  NS_STACK_CLASS class HandlingTrustedAction
+  {
+  public:
+    explicit HandlingTrustedAction(nsEditor* aSelf, bool aIsTrusted = true)
+    {
+      Init(aSelf, aIsTrusted);
+    }
+
+    HandlingTrustedAction(nsEditor* aSelf, nsIDOMNSEvent* aEvent);
+
+    ~HandlingTrustedAction()
+    {
+      mEditor->mHandlingTrustedAction = mWasHandlingTrustedAction;
+      mEditor->mHandlingActionCount--;
+    }
+
+  private:
+    nsRefPtr<nsEditor> mEditor;
+    bool mWasHandlingTrustedAction;
+
+    void Init(nsEditor* aSelf, bool aIsTrusted)
+    {
+      MOZ_ASSERT(aSelf);
+
+      mEditor = aSelf;
+      mWasHandlingTrustedAction = aSelf->mHandlingTrustedAction;
+      if (aIsTrusted) {
+        // If action is nested and the outer event is not trusted,
+        // we shouldn't override it.
+        if (aSelf->mHandlingActionCount == 0) {
+          aSelf->mHandlingTrustedAction = true;
+        }
+      } else {
+        aSelf->mHandlingTrustedAction = false;
+      }
+      aSelf->mHandlingActionCount++;
+    }
+  };
+
 protected:
 
   PRUint32        mModCount;     // number of modifications (for undo/redo stack)
   PRUint32        mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
 
@@ -821,17 +840,19 @@ protected:
   nsWeakPtr        mDocWeak;  // weak reference to the nsIDOMDocument
   // The form field as an event receiver
   nsCOMPtr<nsIDOMEventTarget> mEventTarget;
 
   nsString* mPhonetic;
 
  nsCOMPtr<nsIDOMEventListener> mEventListener;
 
-  Tristate mLastKeypressEventWasTrusted;
+  PRUint32 mHandlingActionCount;
+  bool mHandlingTrustedAction;
+  bool mDispatchInputEvent;
 
   friend bool NSCanUnload(nsISupports* serviceMgr);
   friend class nsAutoTxnsConserveSelection;
   friend class nsAutoSelectionReset;
   friend class nsAutoRules;
   friend class nsRangeUpdater;
 };
 
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -69,30 +69,16 @@
 #include "nsIDOMDragEvent.h"
 #include "nsIFocusManager.h"
 #include "nsIDOMWindow.h"
 #include "nsContentUtils.h"
 #include "nsIBidiKeyboard.h"
 
 using namespace mozilla;
 
-class nsAutoEditorKeypressOperation {
-public:
-  nsAutoEditorKeypressOperation(nsEditor *aEditor, nsIDOMNSEvent *aEvent)
-    : mEditor(aEditor) {
-    mEditor->BeginKeypressHandling(aEvent);
-  }
-  ~nsAutoEditorKeypressOperation() {
-    mEditor->EndKeypressHandling();
-  }
-
-private:
-  nsEditor *mEditor;
-};
-
 nsEditorEventListener::nsEditorEventListener() :
   mEditor(nsnull), mCommitText(false),
   mInTransaction(false)
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   , mHaveBidiKeyboards(false)
   , mShouldSwitchTextDirection(false)
   , mSwitchToRTL(false)
 #endif
@@ -476,17 +462,17 @@ nsEditorEventListener::KeyPress(nsIDOMEv
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
 
   if (!mEditor->IsAcceptableInputEvent(aKeyEvent)) {
     return NS_OK;
   }
 
   // Transfer the event's trusted-ness to our editor
   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aKeyEvent);
-  nsAutoEditorKeypressOperation operation(mEditor, NSEvent);
+  nsEditor::HandlingTrustedAction operation(mEditor, NSEvent);
 
   // DOM event handling happens in two passes, the client pass and the system
   // pass.  We do all of our processing in the system pass, to allow client
   // handlers the opportunity to cancel events and prevent typing in the editor.
   // If the client pass cancelled the event, defaultPrevented will be true
   // below.
 
   bool defaultPrevented;
@@ -631,17 +617,17 @@ nsEditorEventListener::HandleText(nsIDOM
 
   // if we are readonly or disabled, then do nothing.
   if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return NS_OK;
   }
 
   // Transfer the event's trusted-ness to our editor
   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aTextEvent);
-  nsAutoEditorKeypressOperation operation(mEditor, NSEvent);
+  nsEditor::HandlingTrustedAction operation(mEditor, NSEvent);
 
   return mEditor->UpdateIMEComposition(composedText, textRangeList);
 }
 
 /**
  * Drag event implementation
  */
 
@@ -876,17 +862,17 @@ nsEditorEventListener::HandleEndComposit
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
     return NS_OK;
   }
 
   // Transfer the event's trusted-ness to our editor
   nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aCompositionEvent);
-  nsAutoEditorKeypressOperation operation(mEditor, NSEvent);
+  nsEditor::HandlingTrustedAction operation(mEditor, NSEvent);
 
   return mEditor->EndIMEComposition();
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -5692,8 +5692,15 @@ nsHTMLEditor::GetPreferredIMEState(IMESt
   aState->mOpen = IMEState::DONT_CHANGE_OPEN_STATE;
   if (IsReadonly() || IsDisabled()) {
     aState->mEnabled = IMEState::DISABLED;
   } else {
     aState->mEnabled = IMEState::ENABLED;
   }
   return NS_OK;
 }
+
+already_AddRefed<nsIContent>
+nsHTMLEditor::GetInputEventTargetContent()
+{
+  nsCOMPtr<nsIContent> target = GetActiveEditingHost();
+  return target.forget();
+}
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -156,16 +156,17 @@ public:
   NS_IMETHOD GetIsDocumentEditable(bool *aIsDocumentEditable);
   NS_IMETHOD BeginningOfDocument();
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
   virtual already_AddRefed<nsIContent> GetFocusedContent();
   virtual bool IsActiveInDOMWindow();
   virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
   virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
+  virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
 
   /* ------------ nsStubMutationObserver overrides --------- */
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   /* ------------ nsIEditorIMESupport overrides ------------ */
   NS_IMETHOD GetPreferredIMEState(mozilla::widget::IMEState *aState);
--- a/editor/libeditor/html/tests/Makefile.in
+++ b/editor/libeditor/html/tests/Makefile.in
@@ -91,16 +91,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug674861.html \
 		test_bug676401.html \
 		test_bug677752.html \
 		test_bug697842.html \
 		test_bug725069.html \
 		test_bug735059.html \
 		test_CF_HTML_clipboard.html \
 		test_contenteditable_focus.html \
+		test_dom_input_event_on_htmleditor.html \
 		test_htmleditor_keyevent_handling.html \
 		test_keypress_untrusted_event.html \
 		test_select_all_without_body.html \
 		file_select_all_without_body.html \
 		test_root_element_replacement.html \
 		$(NULL)
 
 ifneq (mobile,$(MOZ_BUILD_APP))
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/html/tests/test_dom_input_event_on_htmleditor.html
@@ -0,0 +1,164 @@
+<html>
+<head>
+  <title>Test for input event of text editor</title>
+  <script type="text/javascript"
+          src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript"
+          src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css"
+          href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="display">
+  <iframe id="editor1" src="data:text/html,<html><body contenteditable id='eventTarget'></body></html>"></iframe>
+  <iframe id="editor2" src="data:text/html,<html contenteditable id='eventTarget'><body></body></html>"></iframe>
+  <iframe id="editor3" src="data:text/html,<html><body><div contenteditable id='eventTarget'></div></body></html>"></iframe>
+  <iframe id="editor4" src="data:text/html,<html contenteditable id='eventTarget'><body><div contenteditable id='editTarget'></div></body></html>"></iframe>
+  <iframe id="editor5" src="data:text/html,<html><body id='eventTarget'></body><script>document.designMode='on';</script></html>"></iframe>
+</div>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+const kIsMac = navigator.platform.indexOf("Mac") == 0;
+
+function runTests()
+{
+  function doTests(aDocument, aWindow, aDescription)
+  {
+    aDescription += ": ";
+    aWindow.focus();
+
+    var eventTarget = aDocument.getElementById("eventTarget");
+
+    var editTarget = aDocument.getElementById("editTarget");
+    if (!editTarget) {
+      editTarget = eventTarget;
+    }
+    editTarget.innerHTML = "";
+    editTarget.focus();
+
+    var body = aDocument.body;
+
+    var inputEvent = null;
+
+    var handler = function (aEvent) {
+      is(aEvent.target, eventTarget,
+         "input event is fired on unexpected element: " + aEvent.target.tagName);
+      ok(!aEvent.cancelable, "input event must not be cancelable");
+      ok(aEvent.bubbles, "input event must be bubbles");
+      var eventTime = new Date(aEvent.timeStamp);
+      var duration = Math.abs(Date.now() - aEvent.timeStamp);
+      ok(duration < 30 * 1000,
+         "perhaps, timestamp wasn't set correctly :" + eventTime.toLocaleString());
+      inputEvent = aEvent;
+    };
+
+    aWindow.addEventListener("input", handler, true);
+
+    inputEvent = null;
+    synthesizeKey("a", { }, aWindow);
+    if (editTarget != eventTarget) {
+      is(editTarget.innerHTML, "a", aDescription + "wrong element was edited");
+    }
+    ok(inputEvent, aDescription + "input event wasn't fired by 'a' key");
+    ok(inputEvent.isTrusted, aDescription + "input event by 'a' key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_BACK_SPACE", { }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by BackSpace key");
+    ok(inputEvent.isTrusted, aDescription + "input event by BackSpace key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("B", { shiftKey: true }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by 'B' key");
+    ok(inputEvent.isTrusted, aDescription + "input event by 'B' key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_ENTER", { }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by Enter key");
+    ok(inputEvent.isTrusted, aDescription + "input event by Enter key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("C", { shiftKey: true }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by 'C' key");
+    ok(inputEvent.isTrusted, aDescription + "input event by 'C' key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_ENTER", { }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by Enter key (again)");
+    ok(inputEvent.isTrusted, aDescription + "input event by Enter key (again) wasn't trusted event");
+
+    inputEvent = null;
+    editTarget.innerHTML = "foo-bar";
+    ok(!inputEvent, aDescription + "input event was fired by setting value");
+
+    inputEvent = null;
+    editTarget.innerHTML = "";
+    ok(!inputEvent, aDescription + "input event was fired by setting empty value");
+
+    inputEvent = null;
+    synthesizeKey(" ", { }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by Space key");
+    ok(inputEvent.isTrusted, aDescription + "input event by Space key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_DELETE", { }, aWindow);
+    ok(!inputEvent, aDescription + "input event was fired by Delete key at the end");
+
+    inputEvent = null;
+    synthesizeKey("VK_LEFT", { }, aWindow);
+    ok(!inputEvent, aDescription + "input event was fired by Left key");
+
+    inputEvent = null;
+    synthesizeKey("VK_DELETE", { }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by Delete key at the start");
+    ok(inputEvent.isTrusted, aDescription + "input event by Delete key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("z", { accelKey: true }, aWindow);
+    ok(inputEvent, aDescription + "input event wasn't fired by Undo");
+    ok(inputEvent.isTrusted, aDescription + "input event by Undo wasn't trusted event");
+
+    inputEvent = null;
+    if (kIsMac) {
+      synthesizeKey("z", { accelKey: true, shiftKey: true }, aWindow);
+    } else {
+      synthesizeKey("y", { accelKey: true }, aWindow);
+    }
+    ok(inputEvent, aDescription + "input event wasn't fired by Redo");
+    ok(inputEvent.isTrusted, aDescription + "input event by Redo wasn't trusted event");
+
+    aWindow.removeEventListener("input", handler, true);
+  }
+
+  doTests(document.getElementById("editor1").contentDocument,
+          document.getElementById("editor1").contentWindow,
+          "Editor1, body has contenteditable attribute");
+  doTests(document.getElementById("editor2").contentDocument,
+          document.getElementById("editor2").contentWindow,
+          "Editor2, html has contenteditable attribute");
+  doTests(document.getElementById("editor3").contentDocument,
+          document.getElementById("editor3").contentWindow,
+          "Editor3, div has contenteditable attribute");
+  doTests(document.getElementById("editor4").contentDocument,
+          document.getElementById("editor4").contentWindow,
+          "Editor4, html and div has contenteditable attribute");
+  doTests(document.getElementById("editor5").contentDocument,
+          document.getElementById("editor5").contentWindow,
+          "Editor5, html and div has contenteditable attribute");
+
+  SimpleTest.finish();
+}
+
+</script>
+</body>
+
+</html>
--- a/editor/libeditor/text/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/text/nsPlaintextDataTransfer.cpp
@@ -120,17 +120,17 @@ nsresult nsPlaintextEditor::InsertTextAt
   return InsertText(aStringToInsert);
 }
 
 NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *aTransferable,
                                                             nsIDOMNode *aDestinationNode,
                                                             PRInt32 aDestOffset,
                                                             bool aDoDeleteSelection)
 {
-  FireTrustedInputEvent trusted(this);
+  HandlingTrustedAction trusted(this);
 
   nsresult rv = NS_OK;
   char* bestFlavor = nsnull;
   nsCOMPtr<nsISupports> genericDataObj;
   PRUint32 len = 0;
   if (NS_SUCCEEDED(aTransferable->GetAnyTransferData(&bestFlavor, getter_AddRefs(genericDataObj), &len))
       && bestFlavor && (0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
                         0 == nsCRT::strcmp(bestFlavor, kMozTextInternal)))
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -743,17 +743,17 @@ NS_IMETHODIMP nsPlaintextEditor::DeleteS
 {
   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
 
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
   nsresult result;
 
-  FireTrustedInputEvent trusted(this, aAction != eNone);
+  HandlingTrustedAction trusted(this, aAction != eNone);
 
   // delete placeholder txns merge.
   nsAutoPlaceHolderBatch batch(this, nsGkAtoms::DeleteTxnName);
   nsAutoRules beginRulesSniffing(this, kOpDeleteSelection, aAction);
 
   // pre-process
   nsCOMPtr<nsISelection> selection;
   result = GetSelection(getter_AddRefs(selection));
@@ -989,16 +989,23 @@ nsPlaintextEditor::UpdateIMEComposition(
   // NOTE: We must notify after the auto batch will be gone.
   if (mIsIMEComposing) {
     NotifyEditorObservers();
   }
 
   return rv;
 }
 
+already_AddRefed<nsIContent>
+nsPlaintextEditor::GetInputEventTargetContent()
+{
+  nsCOMPtr<nsIContent> target = do_QueryInterface(mEventTarget);
+  return target.forget();
+}
+
 NS_IMETHODIMP
 nsPlaintextEditor::GetDocumentIsEmpty(bool *aDocumentIsEmpty)
 {
   NS_ENSURE_TRUE(aDocumentIsEmpty, NS_ERROR_NULL_POINTER);
   
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
 
   // Protect the edit rules object from dying
@@ -1188,17 +1195,17 @@ nsPlaintextEditor::SetNewlineHandling(PR
 }
 
 NS_IMETHODIMP 
 nsPlaintextEditor::Undo(PRUint32 aCount)
 {
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
-  FireTrustedInputEvent trusted(this);
+  HandlingTrustedAction trusted(this);
 
   nsAutoUpdateViewBatch beginViewBatching(this);
 
   ForceCompositionEnd();
 
   nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
 
   nsTextRulesInfo ruleInfo(nsTextEditRules::kUndo);
@@ -1218,17 +1225,17 @@ nsPlaintextEditor::Undo(PRUint32 aCount)
 }
 
 NS_IMETHODIMP 
 nsPlaintextEditor::Redo(PRUint32 aCount)
 {
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
-  FireTrustedInputEvent trusted(this);
+  HandlingTrustedAction trusted(this);
 
   nsAutoUpdateViewBatch beginViewBatching(this);
 
   ForceCompositionEnd();
 
   nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
 
   nsTextRulesInfo ruleInfo(nsTextEditRules::kRedo);
@@ -1277,17 +1284,17 @@ nsPlaintextEditor::FireClipboardEvent(PR
 
   // If the event handler caused the editor to be destroyed, return false.
   // Otherwise return true to indicate that the event was not cancelled.
   return !mDidPreDestroy;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::Cut()
 {
-  FireTrustedInputEvent trusted(this);
+  HandlingTrustedAction trusted(this);
 
   if (FireClipboardEvent(NS_CUT))
     return DeleteSelection(eNone);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut)
 {
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -142,16 +142,18 @@ public:
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
 
   virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
 
   virtual nsresult BeginIMEComposition();
   virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
                                         nsIPrivateTextRangeList *aTextRange);
 
+  virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
+
   /* ------------ Utility Routines, not part of public API -------------- */
   NS_IMETHOD TypedText(const nsAString& aString, PRInt32 aAction);
 
   /** Returns the absolute position of the end points of aSelection
    * in the document as a text stream.
    * Invariant: aStartOffset <= aEndOffset.
    */
   nsresult GetTextSelectionOffsets(nsISelection *aSelection,
--- a/editor/libeditor/text/tests/Makefile.in
+++ b/editor/libeditor/text/tests/Makefile.in
@@ -61,16 +61,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug625452.html \
 		test_bug629172.html \
 		test_bug638596.html \
 		test_bug641466.html \
 		test_bug645914.html \
 		test_bug681229.html \
 		test_bug692520.html \
 		test_bug717147.html \
+		test_dom_input_event_on_texteditor.html \
 		$(NULL)
 
 # disables the key handling test on gtk2 because gtk2 overrides some key events
 # on our editor, and the combinations depend on the system.
 ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 _TEST_FILES += \
 		test_texteditor_keyevent_handling.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/text/tests/test_dom_input_event_on_texteditor.html
@@ -0,0 +1,133 @@
+<html>
+<head>
+  <title>Test for input event of text editor</title>
+  <script type="text/javascript"
+          src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript"
+          src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css"
+          href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="display">
+  <input type="text" id="input">
+  <textarea id="textarea"></textarea>
+</div>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+const kIsMac = navigator.platform.indexOf("Mac") == 0;
+
+function runTests()
+{
+  function doTests(aElement, aDescription, aIsTextarea)
+  {
+    aDescription += ": ";
+    aElement.focus();
+    aElement.value = "";
+
+    var inputEvent = null;
+
+    var handler = function (aEvent) {
+      is(aEvent.target, aElement,
+         "input event is fired on unexpected element: " + aEvent.target.tagName);
+      ok(!aEvent.cancelable, "input event must not be cancelable");
+      ok(aEvent.bubbles, "input event must be bubbles");
+      var eventTime = new Date(aEvent.timeStamp);
+      var duration = Math.abs(Date.now() - aEvent.timeStamp);
+      ok(duration < 30 * 1000,
+         "perhaps, timestamp wasn't set correctly :" + eventTime.toLocaleString());
+      inputEvent = aEvent;
+    };
+
+    aElement.addEventListener("input", handler, true);
+
+    inputEvent = null;
+    synthesizeKey("a", { });
+    is(aElement.value, "a", aDescription + "'a' key didn't change the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by 'a' key");
+    ok(inputEvent.isTrusted, aDescription + "input event by 'a' key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_BACK_SPACE", { });
+    is(aElement.value, "", aDescription + "BackSpace key didn't remove the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by BackSpace key");
+    ok(inputEvent.isTrusted, aDescription + "input event by BackSpace key wasn't trusted event");
+
+    if (aIsTextarea) {
+      inputEvent = null;
+      synthesizeKey("VK_ENTER", { });
+      is(aElement.value, "\n", aDescription + "Enter key didn't change the value");
+      ok(inputEvent, aDescription + "input event wasn't fired by Enter key");
+      ok(inputEvent.isTrusted, aDescription + "input event by Enter key wasn't trusted event");
+    }
+
+    inputEvent = null;
+    aElement.value = "foo-bar";
+    is(aElement.value, "foo-bar", aDescription + "value wasn't set");
+    ok(!inputEvent, aDescription + "input event was fired by setting value");
+
+    inputEvent = null;
+    aElement.value = "";
+    is(aElement.value, "", aDescription + "value wasn't set (empty)");
+    ok(!inputEvent, aDescription + "input event was fired by setting empty value");
+
+    inputEvent = null;
+    synthesizeKey(" ", { });
+    is(aElement.value, " ", aDescription + "Space key didn't change the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by Space key");
+    ok(inputEvent.isTrusted, aDescription + "input event by Space key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("VK_DELETE", { });
+    is(aElement.value, " ", aDescription + "Delete key removed the value");
+    ok(!inputEvent, aDescription + "input event was fired by Delete key at the end");
+
+    inputEvent = null;
+    synthesizeKey("VK_LEFT", { });
+    is(aElement.value, " ", aDescription + "Left key removed the value");
+    ok(!inputEvent, aDescription + "input event was fired by Left key");
+
+    inputEvent = null;
+    synthesizeKey("VK_DELETE", { });
+    is(aElement.value, "", aDescription + "Delete key didn't remove the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by Delete key at the start");
+    ok(inputEvent.isTrusted, aDescription + "input event by Delete key wasn't trusted event");
+
+    inputEvent = null;
+    synthesizeKey("z", { accelKey: true });
+    is(aElement.value, (aIsTextarea ? " \n" : " "), aDescription + "Accel+Z key didn't undo the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by Undo");
+    ok(inputEvent.isTrusted, aDescription + "input event by Undo wasn't trusted event");
+
+    inputEvent = null;
+    if (kIsMac) {
+      synthesizeKey("z", { accelKey: true, shiftKey: true });
+    } else {
+      synthesizeKey("y", { accelKey: true });
+    }
+    is(aElement.value, "", aDescription + "Accel+Y key didn't redo the value");
+    ok(inputEvent, aDescription + "input event wasn't fired by Redo");
+    ok(inputEvent.isTrusted, aDescription + "input event by Redo wasn't trusted event");
+
+    aElement.removeEventListener("input", handler, true);
+  }
+
+  doTests(document.getElementById("input"), "<input type=\"text\">", false);
+  doTests(document.getElementById("textarea"), "<textarea>", true);
+
+  SimpleTest.finish();
+}
+
+</script>
+</body>
+
+</html>
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -164,17 +164,16 @@ private:
   bool mFirstEntry;
 };
 #endif
 
 nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext)
   : nsStackFrame(aShell, aContext)
   , mUseEditor(false)
   , mIsProcessing(false)
-  , mNotifyOnInput(true)
   , mFireChangeEventState(false)
 #ifdef DEBUG
   , mInEditorInitialization(false)
 #endif
 {
 }
 
 nsTextControlFrame::~nsTextControlFrame()
@@ -1377,33 +1376,16 @@ nsTextControlFrame::GetMaxLength(PRInt32
       *aSize = attr->GetIntegerValue();
 
       return true;
     }
   }
   return false;
 }
 
-// this is where we propagate a content changed event
-void
-nsTextControlFrame::FireOnInput(bool aTrusted)
-{
-  if (!mNotifyOnInput)
-    return; // if notification is turned off, do nothing
-  
-  // Dispatch the "input" event
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsUIEvent event(aTrusted, NS_FORM_INPUT, 0);
-
-  // Have the content handle the event, propagating it according to normal
-  // DOM rules.
-  nsCOMPtr<nsIPresShell> shell = PresContext()->PresShell();
-  shell->HandleEventWithTarget(&event, nsnull, mContent, &status);
-}
-
 nsresult
 nsTextControlFrame::InitFocusedValue()
 {
   return GetText(mFocusedValue);
 }
 
 NS_IMETHODIMP
 nsTextControlFrame::CheckFireOnChange()
@@ -1613,9 +1595,8 @@ nsTextControlFrame::RestoreState(nsPresS
   }
 
   // Most likely, we don't have our anonymous content constructed yet, which
   // would cause us to end up here.  In this case, we'll just store the scroll
   // pos ourselves, and forward it to the scroll frame later when it's created.
   Properties().Set(ContentScrollPos(), new nsPoint(aState->GetScrollState()));
   return NS_OK;
 }
-
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -44,18 +44,18 @@
 #include "nsIAnonymousContentCreator.h"
 #include "nsITextControlFrame.h"
 #include "nsDisplayList.h"
 #include "nsIScrollableFrame.h"
 #include "nsStubMutationObserver.h"
 #include "nsITextControlElement.h"
 #include "nsIStatefulFrame.h"
 #include "nsContentUtils.h" // nsAutoScriptBlocker
+#include "nsIEditor.h"
 
-class nsIEditor;
 class nsISelectionController;
 class nsIDOMCharacterData;
 #ifdef ACCESSIBILITY
 class nsIAccessible;
 #endif
 class EditorInitializerEntryTracker;
 class nsTextEditorState;
 
@@ -186,17 +186,16 @@ public:
   NS_DECL_QUERYFRAME
 
   // Temp reference to scriptrunner
   // We could make these auto-Revoking via the "delete" entry for safety
   NS_DECLARE_FRAME_PROPERTY(TextControlInitializer, nsnull)
 
 
 public: //for methods who access nsTextControlFrame directly
-  void FireOnInput(bool aTrusted);
   void SetValueChanged(bool aValueChanged);
   /** Called when the frame is focused, to remember the value for onChange. */
   nsresult InitFocusedValue();
 
   void SetFireChangeEventState(bool aNewState)
   {
     mFireChangeEventState = aNewState;
   }
@@ -205,67 +204,64 @@ public: //for methods who access nsTextC
   {
     return mFireChangeEventState;
   }    
 
   // called by the focus listener
   nsresult MaybeBeginSecureKeyboardInput();
   void MaybeEndSecureKeyboardInput();
 
-  class ValueSetter {
+  NS_STACK_CLASS class ValueSetter {
   public:
     ValueSetter(nsTextControlFrame* aFrame,
+                nsIEditor* aEditor,
                 bool aHasFocusValue)
       : mFrame(aFrame)
+      , mEditor(aEditor)
       // This method isn't used for user-generated changes, except for calls
       // from nsFileControlFrame which sets mFireChangeEventState==true and
       // restores it afterwards (ie. we want 'change' events for those changes).
       // Focused value must be updated to prevent incorrect 'change' events,
       // but only if user hasn't changed the value.
       , mFocusValueInit(!mFrame->mFireChangeEventState && aHasFocusValue)
-      , mOuterTransaction(false)
-      , mInited(false)
+      , mCanceled(false)
     {
-      NS_ASSERTION(aFrame, "Should pass a valid frame");
-    }
-    void Cancel() {
-      mInited = false;
-    }
-    void Init() {
-      // Since this code does not handle user-generated changes to the text,
-      // make sure we don't fire oninput when the editor notifies us.
-      // (mNotifyOnInput must be reset before we return).
+      MOZ_ASSERT(aFrame);
+      MOZ_ASSERT(aEditor);
 
       // To protect against a reentrant call to SetValue, we check whether
       // another SetValue is already happening for this frame.  If it is,
       // we must wait until we unwind to re-enable oninput events.
-      mOuterTransaction = mFrame->mNotifyOnInput;
-      if (mOuterTransaction)
-        mFrame->mNotifyOnInput = false;
-
-      mInited = true;
+      mEditor->GetSuppressDispatchingInputEvent(&mOuterTransaction);
+    }
+    void Cancel() {
+      mCanceled = true;
+    }
+    void Init() {
+      mEditor->SetSuppressDispatchingInputEvent(true);
     }
     ~ValueSetter() {
-      if (!mInited)
-        return;
+      mEditor->SetSuppressDispatchingInputEvent(mOuterTransaction);
 
-      if (mOuterTransaction)
-        mFrame->mNotifyOnInput = true;
+      if (mCanceled) {
+        return;
+      }
 
       if (mFocusValueInit) {
         // Reset mFocusedValue so the onchange event doesn't fire incorrectly.
         mFrame->InitFocusedValue();
       }
     }
 
   private:
     nsTextControlFrame* mFrame;
+    nsCOMPtr<nsIEditor> mEditor;
     bool mFocusValueInit;
     bool mOuterTransaction;
-    bool mInited;
+    bool mCanceled;
   };
   friend class ValueSetter;
 
 #define DEFINE_TEXTCTRL_FORWARDER(type, name)                                  \
   type name() {                                                                \
     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \
     NS_ASSERTION(txtCtrl, "Content not a text control element");               \
     return txtCtrl->name();                                                    \
@@ -401,34 +397,29 @@ private:
   //helper methods
   nsresult SetSelectionInternal(nsIDOMNode *aStartNode, PRInt32 aStartOffset,
                                 nsIDOMNode *aEndNode, PRInt32 aEndOffset,
                                 SelectionDirection aDirection = eNone);
   nsresult SelectAllOrCollapseToEndOfText(bool aSelect);
   nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd,
                                  SelectionDirection aDirection = eNone);
 
-  // accessors for the notify on input flag
-  bool GetNotifyOnInput() const { return mNotifyOnInput; }
-  void SetNotifyOnInput(bool val) { mNotifyOnInput = val; }
-
   /**
    * Return the root DOM element, and implicitly initialize the editor if needed.
    */
   nsresult GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement);
 
   void FinishedInitializer() {
     Properties().Delete(TextControlInitializer());
   }
 
 private:
   // these packed bools could instead use the high order bits on mState, saving 4 bytes 
   bool mUseEditor;
   bool mIsProcessing;
-  bool mNotifyOnInput;//default this to off to stop any notifications until setup is complete
   // Calls to SetValue will be treated as user values (i.e. trigger onChange
   // eventually) when mFireChangeEventState==true, this is used by nsFileControlFrame.
   bool mFireChangeEventState;
   // Keep track if we have asked a placeholder node creation.
   bool mUsePlaceholder;
 
 #ifdef DEBUG
   bool mInEditorInitialization;