Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 03 Jan 2013 17:01:32 -0500
changeset 126608 ea71cfcffb9fce065a8d038c47e47ded6bb1ac95
parent 126607 8b397adc49e9c280d469821402c972aaeca45fa2 (current diff)
parent 126474 38407b98003bd57a1cf03fe71a50f66761932174 (diff)
child 126609 c4bff11905a92c7565732a61221efce255b01804
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.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
Merge m-c to inbound.
content/html/content/src/nsGenericHTMLElement.h
content/xul/content/src/nsXULElement.cpp
dom/base/nsDOMWindowUtils.cpp
layout/base/nsPresShell.cpp
--- a/b2g/config/panda/releng-pandaboard.tt
+++ b/b2g/config/panda/releng-pandaboard.tt
@@ -1,8 +1,8 @@
 [
 {
-"size": 676536592,
-"digest": "5aa3f1b523faa8996dbcde44a99d846740f80b5361d3109f36688c7bac86979861311c4e7d69b67d9ea1d7c56e20947a30576b3e3f08f7c1e42ec4c2192d92e1",
+"size": 676733720,
+"digest": "6ae117e64af1e8532004e9de44f172b5db88f42a91b8821503b3832de6e168f8c000229705a5110ce294065780a6371e7852dd76ddd8f3c6113892a093b6fc55",
 "algorithm": "sha512",
 "filename": "gonk.tar.xz"
 }
 ]
--- a/b2g/config/panda/sources.xml
+++ b/b2g/config/panda/sources.xml
@@ -5,21 +5,21 @@
   <remote fetch="https://android.googlesource.com/" name="aosp"/>
   <remote fetch="git://github.com/mozilla-b2g/" name="b2g"/>
   <remote fetch="git://android.git.linaro.org/" name="linaro"/>
   <remote fetch="git://github.com/mozilla/" name="mozilla"/>
   <remote fetch="http://git.mozilla.org/" name="mozillaorg"/>
   <default remote="linaro" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
 
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="273ba23d5c6c9f6a34995a3cc429804d1449ca9f">
+  <project name="platform_build" path="build" remote="b2g" revision="69380784721ae11af93ef4e1b5ce8a54e8570574">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7c43e273991a8a66afc88c888befb2830b7640e1"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="ffc42185726384eaa80ea685bd9c95b7dab467c3"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="167b4c59a82b9130e385de786e8056d89a1cb8c3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="6ee1f8987ef36d688f97064c003ad57849dfadf2"/>
 
   <!-- Stock Android things -->
   <!-- Information: platform/abi/cpp is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <!-- Information: platform/bionic is tagged with android-4.0.4_r2.1 --><project name="platform/bionic" path="bionic" revision="3d11bf0f3f3cf848f6f1e8449bf8736d8d1c78a3"/>
   <!-- Information: platform/bootable/recovery is tagged with android-4.0.4_r2.1 --><project name="platform/bootable/recovery" path="bootable/recovery" revision="fadc5ac81d6400ebdd041f7d4ea64021596d6b7d"/>
   <!-- Information: device/common is tagged with android-sdk-adt_r20 --><project name="device/common" path="device/common" revision="7d4526582f88808a3194e1a3b304abb369d2745c"/>
@@ -89,10 +89,11 @@
   <!-- Information: platform/system/netd is tagged with android-4.0.4_r2.1 --><project name="platform/system/netd" path="system/netd" revision="3c903b555975fa59d6688a0a6417ac7512c202e7"/>
   <!-- Information: platform/system/vold is tagged with android-4.0.4_r2.1 --><project name="platform/system/vold" path="system/vold" revision="3ad9072a5d6f6bda32123b367545649364e3c11d"/>
 
   <!-- Pandaboard specific things -->
   <project name="android-device-panda" path="device/ti/panda" remote="b2g" revision="0e9a89187970d6fa99930c8d9cb438b935c2337c"/>
   <!-- Information: platform/hardware/ti/omap4xxx is tagged with android-4.0.4_r2.1 --><project name="platform/hardware/ti/omap4xxx" path="hardware/ti/omap4xxx" revision="8be8e9a68c96b6cf43c08a58e7ecd7708737c599"/>
   <project name="platform/hardware/ti/wlan" path="hardware/ti/wlan" revision="60dfeb6e4448bfed707946ebca6612980f525e69"/>
   <project name="platform/hardware/ti/wpan" path="hardware/ti/wpan" revision="3ece7d9e08052989401e008bc397dbcd2557cfd0"/>
-
+  <project name="Negatus" path="external/negatus" remote="mozilla" revision="7ed4efcee655f605455f9375a4e6c68cd078c459"/>
+  
 </manifest>
\ No newline at end of file
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -427,17 +427,18 @@ nsContextMenu.prototype = {
       inspector.selection.setNode(this.target, "browser-context-menu");
     }.bind(this));
   },
 
   // Set various context menu attributes based on the state of the world.
   setTarget: function (aNode, aRangeParent, aRangeOffset) {
     const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     if (aNode.namespaceURI == xulNS ||
-        aNode.nodeType == Node.DOCUMENT_NODE) {
+        aNode.nodeType == Node.DOCUMENT_NODE ||
+        this.isDisabledForEvents(aNode)) {
       this.shouldDisplay = false;
       return;
     }
 
     // Initialize contextual info.
     this.onImage           = false;
     this.onLoadedImage     = false;
     this.onCompletedImage  = false;
@@ -1285,16 +1286,26 @@ nsContextMenu.prototype = {
     return "contextMenu.target     = " + this.target + "\n" +
            "contextMenu.onImage    = " + this.onImage + "\n" +
            "contextMenu.onLink     = " + this.onLink + "\n" +
            "contextMenu.link       = " + this.link + "\n" +
            "contextMenu.inFrame    = " + this.inFrame + "\n" +
            "contextMenu.hasBGImage = " + this.hasBGImage + "\n";
   },
 
+  isDisabledForEvents: function(aNode) {
+    let ownerDoc = aNode.ownerDocument;
+    return
+      ownerDoc.defaultView &&
+      ownerDoc.defaultView
+              .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+              .getInterface(Components.interfaces.nsIDOMWindowUtils)
+              .isNodeDisabledForEvents(aNode);
+  },
+
   isTargetATextBox: function(node) {
     if (node instanceof HTMLInputElement)
       return node.mozIsTextField(false);
 
     return (node instanceof HTMLTextAreaElement);
   },
 
   isTargetAKeywordField: function(aNode) {
--- a/content/base/src/contentAreaDropListener.js
+++ b/content/base/src/contentAreaDropListener.js
@@ -90,16 +90,19 @@ ContentAreaDropListener.prototype =
 
     secMan.checkLoadURIStrWithPrincipal(principal, uriString, flags);
 
     return uriString;
   },
 
   canDropLink: function(aEvent, aAllowSameDocument)
   {
+    if (this._eventTargetIsDisabled(aEvent))
+      return false;
+
     let dataTransfer = aEvent.dataTransfer;
     let types = dataTransfer.types;
     if (!types.contains("application/x-moz-file") &&
         !types.contains("text/x-moz-url") &&
         !types.contains("text/uri-list") &&
         !types.contains("text/x-moz-text-internal") &&
         !types.contains("text/plain"))
       return false;
@@ -126,29 +129,43 @@ ContentAreaDropListener.prototype =
     }
 
     return true;
   },
 
   dropLink: function(aEvent, aName, aDisallowInherit)
   {
     aName.value = "";
+    if (this._eventTargetIsDisabled(aEvent))
+      return "";
 
     let dataTransfer = aEvent.dataTransfer;
     let [url, name] = this._getDropURL(dataTransfer);
 
     try {
       url = this._validateURI(dataTransfer, url, aDisallowInherit);
     } catch (ex) {
       aEvent.stopPropagation();
       aEvent.preventDefault();
       throw ex;
     }
 
     if (name)
       aName.value = name;
 
     return url;
+  },
+
+  _eventTargetIsDisabled: function(aEvent)
+  {
+    let ownerDoc = aEvent.originalTarget.ownerDocument;
+    if (!ownerDoc || !ownerDoc.defaultView)
+      return false;
+
+    return ownerDoc.defaultView
+                   .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                   .getInterface(Components.interfaces.nsIDOMWindowUtils)
+                   .isNodeDisabledForEvents(aEvent.originalTarget);
   }
 };
 
 var components = [ContentAreaDropListener];
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/content/base/test/chrome/Makefile.in
+++ b/content/base/test/chrome/Makefile.in
@@ -44,15 +44,17 @@ MOCHITEST_CHROME_FILES = \
     test_bug752226-3.xul \
     test_bug752226-4.xul \
     test_bug682305.html \
     test_bug780199.xul \
     test_bug780529.xul \
     test_csp_bug768029.html \
     test_bug800386.xul \
     test_csp_bug773891.html \
+    test_bug816340.xul \
+    file_bug816340.xul \
     test_domparsing.xul \
     test_bug814638.xul \
     host_bug814638.xul \
     frame_bug814638.xul \
     $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/base/test/chrome/file_bug816340.xul
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=816340
+-->
+<window title="Mozilla Bug 816340"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  onload="start();">
+  <label value="Mozilla Bug 816340"/>
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+
+    function ok(val, msg) {
+      opener.wrappedJSObject.ok(val, msg);
+    }
+
+    var elems = 
+      [
+        "input",
+        "textarea",
+        "select",
+        "fieldset",
+        "button",
+      ];
+
+    var chromeDidGetEvent = false;
+    function chromeListener() {
+      chromeDidGetEvent = true;
+    }
+
+    function testElement(el, disabled, contentShouldGetEvent) {
+      chromeDidGetEvent = false;
+      var b = document.getElementById("browser");
+      b.contentDocument.body.innerHTML = null;
+      var e = b.contentDocument.createElement(el);
+      if (disabled) {
+        e.setAttribute("disabled", "true");
+      }
+      b.contentDocument.body.appendChild(e);
+      var contentDidGetEvent = false;
+      b.contentDocument.body.addEventListener("foo",
+        function() { contentDidGetEvent = true }, true);
+
+      b.addEventListener("foo", chromeListener, true);
+      e.dispatchEvent(new Event("foo"));
+      b.removeEventListener("foo", chromeListener, true);
+      ok(contentDidGetEvent == contentShouldGetEvent, "content: " + el + (disabled ? " disabled" : ""));
+      ok(chromeDidGetEvent, "chrome: " + el + (disabled ? " disabled" : ""));
+    }
+      
+    function start() {
+      // Test common element.
+      testElement("div", false, true);
+      testElement("div", true, true);
+
+      for (var i = 0; i < elems.length; ++i) {
+        testElement(elems[i], false, true);
+        testElement(elems[i], true, false);
+      }
+      ok(true, "done");
+      opener.setTimeout("done()", 0);
+      window.close();
+    }
+
+  ]]></script>
+
+  <browser id="browser" type="content" src="about:blank"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/content/base/test/chrome/test_bug816340.xul
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=816340
+-->
+<window title="Mozilla Bug 816340"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=816340"
+     target="_blank">Mozilla Bug 816340</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+  SimpleTest.waitForExplicitFinish();
+
+  function done() {
+    SimpleTest.finish();
+  }
+
+  addLoadEvent(function() {
+    window.open("file_bug816340.xul", "", "chrome");
+  });
+  ]]></script>
+</window>
--- a/content/events/public/nsEventDispatcher.h
+++ b/content/events/public/nsEventDispatcher.h
@@ -95,41 +95,49 @@ public:
 class nsEventChainPreVisitor : public nsEventChainVisitor {
 public:
   nsEventChainPreVisitor(nsPresContext* aPresContext,
                          nsEvent* aEvent,
                          nsIDOMEvent* aDOMEvent,
                          nsEventStatus aEventStatus,
                          bool aIsInAnon)
   : nsEventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus),
-    mCanHandle(true), mForceContentDispatch(false),
-    mRelatedTargetIsInAnon(false), mOriginalTargetIsInAnon(aIsInAnon),
-    mWantsWillHandleEvent(false), mMayHaveListenerManager(true),
-    mParentTarget(nullptr), mEventTargetAtParent(nullptr) {}
+    mCanHandle(true), mAutomaticChromeDispatch(true),
+    mForceContentDispatch(false), mRelatedTargetIsInAnon(false),
+    mOriginalTargetIsInAnon(aIsInAnon), mWantsWillHandleEvent(false),
+    mMayHaveListenerManager(true), mParentTarget(nullptr),
+    mEventTargetAtParent(nullptr) {}
 
   void Reset() {
     mItemFlags = 0;
     mItemData = nullptr;
     mCanHandle = true;
+    mAutomaticChromeDispatch = true;
     mForceContentDispatch = false;
     mWantsWillHandleEvent = false;
     mMayHaveListenerManager = true;
     mParentTarget = nullptr;
     mEventTargetAtParent = nullptr;
   }
 
   /**
    * Member that must be set in PreHandleEvent by event targets. If set to false,
    * indicates that this event target will not be handling the event and
    * construction of the event target chain is complete. The target that sets
    * mCanHandle to false is NOT included in the event target chain.
    */
   bool                  mCanHandle;
 
   /**
+   * If mCanHandle is false and mAutomaticChromeDispatch is also false
+   * event will not be dispatched to the chrome event handler.
+   */
+  bool                  mAutomaticChromeDispatch;
+
+  /**
    * If mForceContentDispatch is set to true,
    * content dispatching is not disabled for this event target.
    * FIXME! This is here for backward compatibility. Bug 329119
    */
   bool                  mForceContentDispatch;
 
   /**
    * true if it is known that related target is or is a descendant of an
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -192,17 +192,17 @@ public:
    */
   nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor,
                            nsCxPusher* aPusher);
 
   static uint32_t MaxEtciCount() { return sMaxEtciCount; }
 
   static void ResetMaxEtciCount()
   {
-    NS_ASSERTION(!sCurrentEtciCount, "Wrong time to call ResetMaxEtciCount()!");
+    MOZ_ASSERT(!sCurrentEtciCount, "Wrong time to call ResetMaxEtciCount()!");
     sMaxEtciCount = 0;
   }
 
   nsCOMPtr<nsIDOMEventTarget>       mTarget;
   nsEventTargetChainItem*           mChild;
   union {
     nsEventTargetChainItem*         mParent;
      // This is used only when caching ETCI objects.
@@ -433,16 +433,40 @@ public:
   static int32_t               sEtciPoolUsers;
 };
 
 nsFixedSizeAllocator* ChainItemPool::sEtciPool = nullptr;
 int32_t ChainItemPool::sEtciPoolUsers = 0;
 
 void NS_ShutdownChainItemPool() { ChainItemPool::Shutdown(); }
 
+nsEventTargetChainItem*
+EventTargetChainItemForChromeTarget(ChainItemPool& aPool,
+                                    nsINode* aNode,
+                                    nsEventTargetChainItem* aChild = nullptr)
+{
+  if (!aNode->IsInDoc()) {
+    return nullptr;
+  }
+  nsPIDOMWindow* win = aNode->OwnerDoc()->GetInnerWindow();
+  nsIDOMEventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
+  NS_ENSURE_TRUE(piTarget, nullptr);
+
+  nsEventTargetChainItem* etci =
+    nsEventTargetChainItem::Create(aPool.GetPool(),
+                                   piTarget->GetTargetForEventTargetChain(),
+                                   aChild);
+  NS_ENSURE_TRUE(etci, nullptr);
+  if (!etci->IsValid()) {
+    nsEventTargetChainItem::Destroy(aPool.GetPool(), etci);
+    return nullptr;
+  }
+  return etci;
+}
+
 /* static */ nsresult
 nsEventDispatcher::Dispatch(nsISupports* aTarget,
                             nsPresContext* aPresContext,
                             nsEvent* aEvent,
                             nsIDOMEvent* aDOMEvent,
                             nsEventStatus* aEventStatus,
                             nsDispatchingCallback* aCallback,
                             nsCOMArray<nsIDOMEventTarget>* aTargets)
@@ -572,23 +596,31 @@ nsEventDispatcher::Dispatch(nsISupports*
 
   // Create visitor object and start event dispatching.
   // PreHandleEvent for the original target.
   nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
   nsEventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
                                     isInAnon);
   targetEtci->PreHandleEvent(preVisitor);
 
+  if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
+    // Event target couldn't handle the event. Try to propagate to chrome.
+    nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci);
+    targetEtci = EventTargetChainItemForChromeTarget(pool, content);
+    NS_ENSURE_STATE(targetEtci);
+    targetEtci->PreHandleEvent(preVisitor);
+  }
   if (preVisitor.mCanHandle) {
     // At least the original target can handle the event.
     // Setting the retarget to the |target| simplifies retargeting code.
     nsCOMPtr<nsIDOMEventTarget> t = aEvent->target;
     targetEtci->SetNewTarget(t);
     nsEventTargetChainItem* topEtci = targetEtci;
     while (preVisitor.mParentTarget) {
+      nsIDOMEventTarget* parentTarget = preVisitor.mParentTarget;
       nsEventTargetChainItem* parentEtci =
         nsEventTargetChainItem::Create(pool.GetPool(), preVisitor.mParentTarget,
                                        topEtci);
       if (!parentEtci) {
         rv = NS_ERROR_OUT_OF_MEMORY;
         break;
       }
       if (!parentEtci->IsValid()) {
@@ -605,16 +637,34 @@ nsEventDispatcher::Dispatch(nsISupports*
       }
 
       parentEtci->PreHandleEvent(preVisitor);
       if (preVisitor.mCanHandle) {
         topEtci = parentEtci;
       } else {
         nsEventTargetChainItem::Destroy(pool.GetPool(), parentEtci);
         parentEtci = nullptr;
+        if (preVisitor.mAutomaticChromeDispatch && content) {
+          // Even if the current target can't handle the event, try to
+          // propagate to chrome.
+          nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
+          if (disabledTarget) {
+            parentEtci = EventTargetChainItemForChromeTarget(pool,
+                                                             disabledTarget,
+                                                             topEtci);
+            if (parentEtci) {
+              parentEtci->PreHandleEvent(preVisitor);
+              if (preVisitor.mCanHandle) {
+                targetEtci->SetNewTarget(parentTarget);
+                topEtci = parentEtci;
+                continue;
+              }
+            }
+          }
+        }
         break;
       }
     }
     if (NS_SUCCEEDED(rv)) {
       if (aTargets) {
         aTargets->Clear();
         nsEventTargetChainItem* item = targetEtci;
         while(item) {
--- a/content/html/content/public/nsIFormControl.h
+++ b/content/html/content/public/nsIFormControl.h
@@ -65,18 +65,18 @@ enum InputElementTypes {
   eInputElementTypesMax
 };
 
 PR_STATIC_ASSERT((uint32_t)eFormControlsWithoutSubTypesMax < (uint32_t)NS_FORM_BUTTON_ELEMENT);
 PR_STATIC_ASSERT((uint32_t)eButtonElementTypesMax < (uint32_t)NS_FORM_INPUT_ELEMENT);
 PR_STATIC_ASSERT((uint32_t)eInputElementTypesMax  < 1<<8);
 
 #define NS_IFORMCONTROL_IID   \
-{ 0xbc53dcf5, 0xbd4f, 0x4991, \
- { 0xa1, 0x87, 0xc4, 0x57, 0x98, 0x54, 0xda, 0x6e } }
+{ 0x4b89980c, 0x4dcd, 0x428f, \
+  { 0xb7, 0xad, 0x43, 0x5b, 0x93, 0x29, 0x79, 0xec } }
 
 /**
  * Interface which all form controls (e.g. buttons, checkboxes, text,
  * radio buttons, select, etc) implement in addition to their dom specific
  * interface.
  */
 class nsIFormControl : public nsISupports
 {
@@ -177,16 +177,20 @@ public:
   inline bool IsSubmittableControl() const;
 
   /**
    * Returns whether this form control can have draggable children.
    * @return whether this form control can have draggable children.
    */
   inline bool AllowDraggableChildren() const;
 
+  virtual bool IsDisabledForEvents(uint32_t aMessage)
+  {
+    return false;
+  }
 protected:
 
   /**
    * Returns whether mType corresponds to a single line text control type.
    * @param aExcludePassword to have NS_FORM_INPUT_PASSWORD ignored.
    * @param aType the type to be tested.
    * @return whether mType corresponds to a single line text control type.
    */
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -1183,17 +1183,17 @@ protected:
    * This method is a a callback for IDTargetObserver (from nsIDocument).
    * It will be called each time the element associated with the id in @form
    * changes.
    */
   static bool FormIdUpdated(Element* aOldElement, Element* aNewElement,
                               void* aData);
 
   // Returns true if the event should not be handled from PreHandleEvent
-  virtual bool IsElementDisabledForEvents(uint32_t aMessage, nsIFrame* aFrame);
+  bool IsElementDisabledForEvents(uint32_t aMessage, nsIFrame* aFrame);
 
   // The focusability state of this form control.  eUnfocusable means that it
   // shouldn't be focused at all, eInactiveWindow means it's in an inactive
   // window, eActiveWindow means it's in an active window.
   enum FocusTristate {
     eUnfocusable,
     eInactiveWindow,
     eActiveWindow
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -77,16 +77,17 @@ public:
   NS_DECL_NSIDOMHTMLBUTTONELEMENT
 
   // overriden nsIFormControl methods
   NS_IMETHOD_(uint32_t) GetType() const { return mType; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   bool RestoreState(nsPresState* aState);
+  virtual bool IsDisabledForEvents(uint32_t aMessage);
 
   nsEventStates IntrinsicState() const;
 
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
@@ -246,27 +247,32 @@ nsHTMLButtonElement::ParseAttribute(int3
       return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-nsresult
-nsHTMLButtonElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+bool
+nsHTMLButtonElement::IsDisabledForEvents(uint32_t aMessage)
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
   nsIFrame* formFrame = NULL;
   if (formControlFrame) {
     formFrame = do_QueryFrame(formControlFrame);
   }
+  return IsElementDisabledForEvents(aMessage, formFrame);
+}
 
+nsresult
+nsHTMLButtonElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+{
   aVisitor.mCanHandle = false;
-  if (IsElementDisabledForEvents(aVisitor.mEvent->message, formFrame)) {
+  if (IsDisabledForEvents(aVisitor.mEvent->message)) {
     return NS_OK;
   }
 
   // Track whether we're in the outermost Dispatch invocation that will
   // cause activation of the input.  That is, if we're a click event, or a
   // DOMActivate that was dispatched directly, this will be set, but if we're
   // a DOMActivate dispatched from click handling, it will not be set.
   bool outerActivateEvent =
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -69,23 +69,29 @@ NS_IMPL_ELEMENT_CLONE(nsHTMLFieldSetElem
 
 
 NS_IMPL_BOOL_ATTR(nsHTMLFieldSetElement, Disabled, disabled)
 NS_IMPL_STRING_ATTR(nsHTMLFieldSetElement, Name, name)
 
 // nsIConstraintValidation
 NS_IMPL_NSICONSTRAINTVALIDATION(nsHTMLFieldSetElement)
 
+bool
+nsHTMLFieldSetElement::IsDisabledForEvents(uint32_t aMessage)
+{
+  return IsElementDisabledForEvents(aMessage, nullptr);
+}
+
 // nsIContent
 nsresult
 nsHTMLFieldSetElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled.
   aVisitor.mCanHandle = false;
-  if (IsElementDisabledForEvents(aVisitor.mEvent->message, NULL)) {
+  if (IsDisabledForEvents(aVisitor.mEvent->message)) {
     return NS_OK;
   }
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
 }
 
 nsresult
 nsHTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
--- a/content/html/content/src/nsHTMLFieldSetElement.h
+++ b/content/html/content/src/nsHTMLFieldSetElement.h
@@ -46,16 +46,17 @@ public:
   virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
                                      bool aNotify);
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify);
 
   // nsIFormControl
   NS_IMETHOD_(uint32_t) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
+  virtual bool IsDisabledForEvents(uint32_t aMessage);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
   virtual nsIDOMNode* AsDOMNode() { return this; }
 
   const nsIContent* GetFirstLegend() const { return mFirstLegend; }
 
   void AddElement(nsGenericHTMLFormElement* aElement) {
     mDependentElements.AppendElement(aElement);
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -2238,22 +2238,28 @@ nsHTMLInputElement::NeedToInitializeEdit
   case NS_MOUSE_ENTER_SYNTH:
   case NS_MOUSE_EXIT_SYNTH:
     return false;
   default:
     return true;
   }
 }
 
+bool
+nsHTMLInputElement::IsDisabledForEvents(uint32_t aMessage)
+{
+  return IsElementDisabledForEvents(aMessage, GetPrimaryFrame());
+}
+
 nsresult
 nsHTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled
   aVisitor.mCanHandle = false;
-  if (IsElementDisabledForEvents(aVisitor.mEvent->message, GetPrimaryFrame())) {
+  if (IsDisabledForEvents(aVisitor.mEvent->message)) {
     return NS_OK;
   }
 
   // Initialize the editor if needed.
   if (NeedToInitializeEditorForEvent(aVisitor)) {
     nsITextControlFrame* textControlFrame = do_QueryFrame(GetPrimaryFrame());
     if (textControlFrame)
       textControlFrame->EnsureEditorInitialized();
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -99,16 +99,17 @@ public:
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(uint32_t) GetType() const { return mType; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual bool RestoreState(nsPresState* aState);
   virtual bool AllowDrop();
+  virtual bool IsDisabledForEvents(uint32_t aMessage);
 
   virtual void FieldSetDisabledChanged(bool aNotify);
 
   // nsIContent
   virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex);
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -1478,28 +1478,32 @@ nsHTMLSelectElement::IsAttributeMapped(c
 }
 
 nsMapRuleToAttributesFunc
 nsHTMLSelectElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
-
-nsresult
-nsHTMLSelectElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+bool
+nsHTMLSelectElement::IsDisabledForEvents(uint32_t aMessage)
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
   nsIFrame* formFrame = nullptr;
   if (formControlFrame) {
     formFrame = do_QueryFrame(formControlFrame);
   }
+  return IsElementDisabledForEvents(aMessage, formFrame);
+}
 
+nsresult
+nsHTMLSelectElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+{
   aVisitor.mCanHandle = false;
-  if (IsElementDisabledForEvents(aVisitor.mEvent->message, formFrame)) {
+  if (IsDisabledForEvents(aVisitor.mEvent->message)) {
     return NS_OK;
   }
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
 }
 
 nsresult
 nsHTMLSelectElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -266,16 +266,17 @@ public:
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify);
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(uint32_t) GetType() const { return NS_FORM_SELECT; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual bool RestoreState(nsPresState* aState);
+  virtual bool IsDisabledForEvents(uint32_t aMessage);
 
   virtual void FieldSetDisabledChanged(bool aNotify);
 
   nsEventStates IntrinsicState() const;
 
   /**
    * To be called when stuff is added under a child of the select--but *before*
    * they are actually added.
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -92,16 +92,17 @@ public:
   NS_IMETHOD SetUserInput(const nsAString& aInput);
 
   // nsIFormControl
   NS_IMETHOD_(uint32_t) GetType() const { return NS_FORM_TEXTAREA; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual bool RestoreState(nsPresState* aState);
+  virtual bool IsDisabledForEvents(uint32_t aMessage);
 
   virtual void FieldSetDisabledChanged(bool aNotify);
 
   virtual nsEventStates IntrinsicState() const;
 
   // nsITextControlElemet
   NS_IMETHOD SetValueChanged(bool aValueChanged);
   NS_IMETHOD_(bool) IsSingleLineTextControl() const;
@@ -660,27 +661,32 @@ nsHTMLTextAreaElement::IsAttributeMapped
 }
 
 nsMapRuleToAttributesFunc
 nsHTMLTextAreaElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
-nsresult
-nsHTMLTextAreaElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+bool
+nsHTMLTextAreaElement::IsDisabledForEvents(uint32_t aMessage)
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
   nsIFrame* formFrame = NULL;
   if (formControlFrame) {
     formFrame = do_QueryFrame(formControlFrame);
   }
+  return IsElementDisabledForEvents(aMessage, formFrame);
+}
 
+nsresult
+nsHTMLTextAreaElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+{
   aVisitor.mCanHandle = false;
-  if (IsElementDisabledForEvents(aVisitor.mEvent->message, formFrame)) {
+  if (IsDisabledForEvents(aVisitor.mEvent->message)) {
     return NS_OK;
   }
 
   // Don't dispatch a second select event if we are already handling
   // one.
   if (aVisitor.mEvent->message == NS_FORM_SELECTED) {
     if (mHandlingSelect) {
       return NS_OK;
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1121,16 +1121,17 @@ nsXULElement::PreHandleEvent(nsEventChai
         // See if we have a command elt.  If so, we execute on the command
         // instead of on our content element.
         nsAutoString command;
         if (xulEvent && GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
             !command.IsEmpty()) {
             // Stop building the event target chain for the original event.
             // We don't want it to propagate to any DOM nodes.
             aVisitor.mCanHandle = false;
+            aVisitor.mAutomaticChromeDispatch = false;
 
             // XXX sXBL/XBL2 issue! Owner or current document?
             nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetCurrentDoc()));
             NS_ENSURE_STATE(domDoc);
             nsCOMPtr<nsIDOMElement> commandElt;
             domDoc->GetElementById(command, getter_AddRefs(commandElt));
             nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
             if (commandContent) {
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "sampler.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsIDOMFileHandle.h"
 #include "nsPrintfCString.h"
 #include "nsViewportInfo.h"
+#include "nsIFormControl.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 DOMCI_DATA(WindowUtils, nsDOMWindowUtils)
 
@@ -3085,8 +3086,31 @@ nsDOMWindowUtils::AllowScriptsToClose()
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
   static_cast<nsGlobalWindow*>(window.get())->AllowScriptsToClose();
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDOMWindowUtils::IsNodeDisabledForEvents(nsIDOMNode* aNode, bool* aRetVal)
+{
+  *aRetVal = false;
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+  nsCOMPtr<nsINode> n = do_QueryInterface(aNode);
+  nsINode* node = n;
+  while (node) {
+    if (node->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
+      nsCOMPtr<nsIFormControl> fc = do_QueryInterface(node);
+      if (fc && fc->IsDisabledForEvents(NS_EVENT_NULL)) {
+        *aRetVal = true;
+        break;
+      }
+    }
+    node = node->GetParentNode();
+  }
+
+  return NS_OK;
+}
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -35,17 +35,17 @@ interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
 interface nsIURI;
 
-[scriptable, uuid(C98B7275-93C4-4EAD-B7CF-573D872C1071)]
+[scriptable, uuid(2196a216-ed3c-46dd-aa24-9f5b3ac17539)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1280,9 +1280,16 @@ interface nsIDOMWindowUtils : nsISupport
    */
   readonly attribute boolean isHandlingUserInput;
 
   /**
    * After calling the method, the window for which this DOMWindowUtils
    * was created can be closed using scripts.
    */
    void allowScriptsToClose();
+
+   /**
+    * In certain cases the event handling of nodes, form controls in practice,
+    * may be disabled. Such cases are for example the existence of disabled
+    * attribute or -moz-user-input: none/disabled.
+    */
+   boolean isNodeDisabledForEvents(in nsIDOMNode aNode);
 };
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6558,44 +6558,16 @@ PresShell::HandleEventInternal(nsEvent* 
             } else if (mDocument) {
               eventTarget = do_QueryInterface(mDocument);
               // If we don't have any content, the callback wouldn't probably
               // do nothing.
               eventCBPtr = nullptr;
             }
           }
           if (eventTarget) {
-#ifdef MOZ_B2G
-            // Horrible hack for B2G to propagate events even from
-            // disabled form elements to chrome. See bug 804811.
-            // See also nsGenericHTMLFormElement::IsElementDisabledForEvents.
-            if (aEvent->message != NS_MOUSE_MOVE) {
-              nsINode* possibleFormElement = eventTarget->ChromeOnlyAccess() ?
-                static_cast<nsIContent*>(eventTarget.get())->
-                  FindFirstNonChromeOnlyAccessContent() :
-                eventTarget;
-              if (possibleFormElement &&
-                  possibleFormElement->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
-                nsEvent event(true, NS_EVENT_TYPE_NULL);
-                nsCOMArray<nsIDOMEventTarget> targets;
-                nsEventDispatcher::Dispatch(eventTarget, nullptr, &event, nullptr,
-                                            nullptr, nullptr, &targets);
-                nsCOMPtr<nsIContent> last;
-                if (targets.Count()) {
-                  last = do_QueryInterface(targets[targets.Count() - 1]);
-                }
-                if (!targets.Count() ||
-                    (last &&
-                     nsContentUtils::ContentIsDescendantOf(last,
-                                                           possibleFormElement))) {
-                  aEvent->mFlags.mOnlyChromeDispatch = true;
-                }
-              }
-            }
-#endif
             if (aEvent->eventStructType == NS_COMPOSITION_EVENT ||
                 aEvent->eventStructType == NS_TEXT_EVENT) {
               nsIMEStateManager::DispatchCompositionEvent(eventTarget,
                 mPresContext, aEvent, aStatus, eventCBPtr);
             } else {
               nsEventDispatcher::Dispatch(eventTarget, mPresContext,
                                           aEvent, nullptr, aStatus, eventCBPtr);
             }