Bug 985988 = Event handlers should update preventDefault flag similar way to event.preventDefault(). r=masayuki, a=sledru
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Mon, 24 Mar 2014 11:50:13 -0400
changeset 192244 6a3cd07007aa31a8b04eae97cef386e51db24ee4
parent 192243 a5bb91ab9c00b415d51a0a22fcc865b3a4705810
child 192245 c81e196a69d40e5dae1aacc41c3b69bab3c3a8b9
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki, sledru
bugs985988
milestone30.0a2
Bug 985988 = Event handlers should update preventDefault flag similar way to event.preventDefault(). r=masayuki, a=sledru
dom/events/Event.h
dom/events/moz.build
dom/events/nsJSEventListener.cpp
dom/events/test/mochitest.ini
dom/events/test/test_bug985988.html
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -199,36 +199,41 @@ public:
     aRv = InitEvent(aType, aBubbles, aCancelable);
   }
 
   EventTarget* GetOriginalTarget() const;
   EventTarget* GetExplicitOriginalTarget() const;
 
   bool GetPreventDefault() const;
 
+  /**
+   * @param aCalledByDefaultHandler     Should be true when this is called by
+   *                                    C++ or Chrome.  Otherwise, e.g., called
+   *                                    by a call of Event.preventDefault() in
+   *                                    content script, false.
+   */
+  void PreventDefaultInternal(bool aCalledByDefaultHandler);
+
+  bool IsMainThreadEvent()
+  {
+    return mIsMainThreadEvent;
+  }
+
 protected:
 
   // Internal helper functions
   void SetEventType(const nsAString& aEventTypeArg);
   already_AddRefed<nsIContent> GetTargetFromFrame();
 
   /**
    * IsChrome() returns true if aCx is chrome context or the event is created
    * in chrome's thread.  Otherwise, false.
    */
   bool IsChrome(JSContext* aCx) const;
 
-  /**
-   * @param aCalledByDefaultHandler     Should be true when this is called by
-   *                                    C++ or Chrome.  Otherwise, e.g., called
-   *                                    by a call of Event.preventDefault() in
-   *                                    content script, false.
-   */
-  void PreventDefaultInternal(bool aCalledByDefaultHandler);
-
   mozilla::WidgetEvent*       mEvent;
   nsRefPtr<nsPresContext>     mPresContext;
   nsCOMPtr<EventTarget>       mExplicitOriginalTarget;
   nsCOMPtr<nsPIDOMWindow>     mOwner; // nsPIDOMWindow for now.
   bool                        mEventIsInternal;
   bool                        mPrivateDataDuplicated;
   bool                        mIsMainThreadEvent;
 };
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -125,16 +125,17 @@ FINAL_LIBRARY = 'gklayout'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/content/html/content/src',
     '/content/xml/content/src',
     '/content/xul/content/src',
     '/dom/base',
     '/dom/settings',
     '/dom/src/storage',
+    '/dom/workers',
     '/js/xpconnect/wrappers',
     '/layout/generic',
     '/layout/xul',
     '/layout/xul/tree/',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     LOCAL_INCLUDES += [
--- a/dom/events/nsJSEventListener.cpp
+++ b/dom/events/nsJSEventListener.cpp
@@ -12,16 +12,17 @@
 #include "nsIXPConnect.h"
 #include "nsIMutableArray.h"
 #include "nsVariant.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsGkAtoms.h"
 #include "xpcpublic.h"
 #include "nsJSEnvironment.h"
 #include "nsDOMJSUtils.h"
+#include "WorkerPrivate.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/UnionTypes.h"
 
 #ifdef DEBUG
 
 #include "nspr.h" // PR_fprintf
@@ -149,18 +150,29 @@ nsJSEventListener::IsBlackForCC()
   }
   return false;
 }
 
 nsresult
 nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsCOMPtr<EventTarget> target = do_QueryInterface(mTarget);
-  if (!target || !mHandler.HasEventHandler())
+  if (!target || !mHandler.HasEventHandler() ||
+      !GetHandler().Ptr()->CallbackPreserveColor()) {
     return NS_ERROR_FAILURE;
+  }
+
+  Event* event = aEvent->InternalDOMEvent();
+  bool isMainThread = event->IsMainThreadEvent();
+  bool isChromeHandler =
+    isMainThread ?
+      nsContentUtils::GetObjectPrincipal(
+        GetHandler().Ptr()->CallbackPreserveColor()) ==
+        nsContentUtils::GetSystemPrincipal() :
+      mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
 
   if (mHandler.Type() == nsEventHandler::eOnError) {
     MOZ_ASSERT_IF(mEventName, mEventName == nsGkAtoms::onerror);
 
     nsString errorMsg, file;
     EventOrString msgOrEvent;
     Optional<nsAString> fileName;
     Optional<uint32_t> lineNumber;
@@ -186,17 +198,17 @@ nsJSEventListener::HandleEvent(nsIDOMEve
     ErrorResult rv;
     bool handled = handler->Call(mTarget, msgOrEvent, fileName, lineNumber,
                                  columnNumber, rv);
     if (rv.Failed()) {
       return rv.ErrorCode();
     }
 
     if (handled) {
-      aEvent->PreventDefault();
+      event->PreventDefaultInternal(isChromeHandler);
     }
     return NS_OK;
   }
 
   if (mHandler.Type() == nsEventHandler::eOnBeforeUnload) {
     MOZ_ASSERT(mEventName == nsGkAtoms::onbeforeunload);
 
     nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler =
@@ -207,17 +219,17 @@ nsJSEventListener::HandleEvent(nsIDOMEve
     if (rv.Failed()) {
       return rv.ErrorCode();
     }
 
     nsCOMPtr<nsIDOMBeforeUnloadEvent> beforeUnload = do_QueryInterface(aEvent);
     NS_ENSURE_STATE(beforeUnload);
 
     if (!DOMStringIsNull(retval)) {
-      aEvent->PreventDefault();
+      event->PreventDefaultInternal(isChromeHandler);
 
       nsAutoString text;
       beforeUnload->GetReturnValue(text);
 
       // Set the text in the beforeUnload event as long as it wasn't
       // already set (through event.returnValue, which takes
       // precedence over a value returned from a JS function in IE)
       if (text.IsEmpty()) {
@@ -238,17 +250,17 @@ nsJSEventListener::HandleEvent(nsIDOMEve
   }
 
   // If the handler returned false and its sense is not reversed,
   // or the handler returned true and its sense is reversed from
   // the usual (false means cancel), then prevent default.
   if (retval.isBoolean() &&
       retval.toBoolean() == (mEventName == nsGkAtoms::onerror ||
                              mEventName == nsGkAtoms::onmouseover)) {
-    aEvent->PreventDefault();
+    event->PreventDefaultInternal(isChromeHandler);
   }
 
   return NS_OK;
 }
 
 /*
  * Factory functions
  */
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -147,8 +147,9 @@ skip-if = buildapp == 'b2g' # b2g(drag e
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_eventctors.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_focus_disabled.html]
 [test_messageEvent.html]
 [test_moz_mouse_pixel_scroll_event.html]
 [test_wheel_default_action.html]
 skip-if = buildapp == 'b2g' || e10s
+[test_bug985988.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug985988.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=985988
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 985988</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 985988 **/
+
+  function handler() {
+    return false;
+  }
+
+  function reversedHandler() {
+    return true;
+  }
+
+  function test() {
+    var t = document.getElementById("testtarget");
+
+    t.onclick = handler;
+    var e = new MouseEvent("click", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(e.defaultPrevented, "Should have prevented default handling.");
+
+    t.onclick = reversedHandler;
+    e = new MouseEvent("click", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+    // mouseover has reversed meaning for handler return value.
+    t.onmouseover = reversedHandler;
+    e = new MouseEvent("mouseover", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(e.defaultPrevented, "Should have prevented default handling.");
+
+    t.onmouseover = handler;
+    e = new MouseEvent("mouseover", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+    // error has reversed meaning for handler return value.
+    t.onerror = reversedHandler;
+    e = new ErrorEvent("error", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(e.defaultPrevented, "Should have prevented default handling.");
+
+    t.onerror = handler;
+    e = new MouseEvent("error", {cancelable: true});
+    t.dispatchEvent(e);
+    ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  addLoadEvent(test);
+
+  </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985988">Mozilla Bug 985988</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<a href="#" id="testtarget">test target</a>
+<pre id="test">
+</pre>
+</body>
+</html>