Bug 486990, move contextmenu listener to system event group, r=enn, sr=neil
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 25 Apr 2009 11:45:30 +0300
changeset 27832 dfd65697f1143ce85c6401f2c7e061416a9a49d8
parent 27831 5f4cbbe377fc74e2f495773e03e21a395a2eb843
child 27833 4113fe30352df6f757974b1db8043b211723bfc7
push id6735
push useropettay@mozilla.com
push dateSat, 25 Apr 2009 08:49:11 +0000
treeherdermozilla-central@dfd65697f114 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenn, neil
bugs486990
milestone1.9.2a1pre
Bug 486990, move contextmenu listener to system event group, r=enn, sr=neil
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventDispatcher.cpp
content/xbl/src/nsXBLBinding.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/content/test/Makefile.in
content/xul/content/test/test_bug486990.xul
dom/interfaces/events/nsIDOMNSEvent.idl
dom/interfaces/events/nsIDOMNSUIEvent.idl
js/src/xpconnect/src/dom_quickstubs.qsconf
security/manager/ssl/src/nsSmartCardEvent.cpp
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -1566,16 +1566,24 @@ nsDOMEvent::ReportWrongPropertyAccessWar
                                          "WrongEventPropertyAccessWarning",
                                          strings, NS_ARRAY_LENGTH(strings),
                                          doc ? doc->GetDocumentURI() : nsnull,
                                          EmptyString(), 0, 0,
                                          nsIScriptError::warningFlag,
                                          "DOM Events");
 }
 
+NS_IMETHODIMP
+nsDOMEvent::GetPreventDefault(PRBool* aReturn)
+{
+  NS_ENSURE_ARG_POINTER(aReturn);
+  *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
+  return NS_OK;
+}
+
 nsresult NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
                         nsPresContext* aPresContext,
                         nsEvent *aEvent) 
 {
   nsDOMEvent* it = new nsDOMEvent(aPresContext, aEvent);
   if (nsnull == it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -363,25 +363,16 @@ nsDOMUIEvent::GetIsChar(PRBool* aIsChar)
       *aIsChar = ((nsTextEvent*)mEvent)->isChar;
       return NS_OK;
     default:
       *aIsChar = PR_FALSE;
       return NS_OK;
   }
 }
 
-NS_IMETHODIMP
-nsDOMUIEvent::GetPreventDefault(PRBool* aReturn)
-{
-  NS_ENSURE_ARG_POINTER(aReturn);
-  *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
-
-  return NS_OK;
-}
-
 NS_METHOD nsDOMUIEvent::GetCompositionReply(nsTextEventReply** aReply)
 {
   if((mEvent->message == NS_COMPOSITION_START) ||
      (mEvent->message == NS_COMPOSITION_QUERY))
   {
     *aReply = &(static_cast<nsCompositionEvent*>(mEvent)->theReply);
     return NS_OK;
   }
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -66,16 +66,17 @@ public:
   NS_IMETHOD DuplicatePrivateData();
   
   // nsIPrivateCompositionEvent interface
   NS_IMETHOD GetCompositionReply(nsTextEventReply** aReply);
   
   // Forward to nsDOMEvent
   NS_FORWARD_TO_NSDOMEVENT
 
+  NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
 protected:
 
   // Internal helper functions
   nsIntPoint GetClientPoint();
   nsIntPoint GetScreenPoint();
   nsIntPoint GetLayerPoint();
   nsIntPoint GetPagePoint();
   
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -303,18 +303,16 @@ nsEventTargetChainItem::HandleEventTarge
       // Item is at anonymous boundary. Need to retarget for the current item
       // and for parent items.
       aVisitor.mEvent->target = newTarget;
     }
 
     if (!(aVisitor.mEvent->flags & NS_EVENT_FLAG_CANT_BUBBLE) || newTarget) {
       if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
            item->ForceContentDispatch()) &&
-          (!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) ||
-           aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) &&
           !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
         item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
                           createdELMs != nsEventListenerManager::sCreatedCount);
       }
       if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
         item->PostHandleEvent(aVisitor);
       }
     }
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -858,17 +858,18 @@ nsXBLBinding::InstallEventHandlers()
         eventAtom->ToString(type);
 
         // If this is a command, add it in the system event group, otherwise 
         // add it to the standard event group.
 
         // This is a weak ref. systemEventGroup above is already a
         // strong ref, so we are guaranteed it will not go away.
         nsIDOMEventGroup* eventGroup = nsnull;
-        if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
+        if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
+            (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
           if (!systemEventGroup)
             manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
           eventGroup = systemEventGroup;
         }
 
         nsXBLEventHandler* handler = curr->GetEventHandler();
         if (handler) {
           // Figure out if we're using capturing or not.
@@ -896,17 +897,18 @@ nsXBLBinding::InstallEventHandlers()
         handler->GetEventName(type);
 
         // If this is a command, add it in the system event group, otherwise 
         // add it to the standard event group.
 
         // This is a weak ref. systemEventGroup above is already a
         // strong ref, so we are guaranteed it will not go away.
         nsIDOMEventGroup* eventGroup = nsnull;
-        if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
+        if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
+            (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
           if (!systemEventGroup)
             manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
           eventGroup = systemEventGroup;
         }
 
         // Figure out if we're using capturing or not.
         PRInt32 flags = (handler->GetPhase() == NS_PHASE_CAPTURING) ?
           NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
@@ -994,17 +996,19 @@ nsXBLBinding::UnhookEventHandlers()
   nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
 
   if (handlerChain) {
     nsCOMPtr<nsIEventListenerManager> manager;
     mBoundElement->GetListenerManager(PR_FALSE, getter_AddRefs(manager));
     if (!manager) {
       return;
     }
-                                      
+
+    PRBool isChromeDoc =
+      nsContentUtils::IsChromeDoc(mBoundElement->GetOwnerDoc());
     nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
     nsXBLPrototypeHandler* curr;
     for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
       nsXBLEventHandler* handler = curr->GetCachedEventHandler();
       if (!handler) {
         continue;
       }
       
@@ -1023,17 +1027,18 @@ nsXBLBinding::UnhookEventHandlers()
         NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
 
       // If this is a command, remove it from the system event group,
       // otherwise remove it from the standard event group.
 
       // This is a weak ref. systemEventGroup above is already a
       // strong ref, so we are guaranteed it will not go away.
       nsIDOMEventGroup* eventGroup = nsnull;
-      if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
+      if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
+          (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
         if (!systemEventGroup)
           manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
         eventGroup = systemEventGroup;
       }
 
       manager->RemoveEventListenerByType(handler, type, flags, eventGroup);
     }
 
@@ -1051,17 +1056,18 @@ nsXBLBinding::UnhookEventHandlers()
         NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
 
       // If this is a command, remove it from the system event group, otherwise 
       // remove it from the standard event group.
 
       // This is a weak ref. systemEventGroup above is already a
       // strong ref, so we are guaranteed it will not go away.
       nsIDOMEventGroup* eventGroup = nsnull;
-      if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
+      if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
+          (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
         if (!systemEventGroup)
           manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
         eventGroup = systemEventGroup;
       }
 
       manager->RemoveEventListenerByType(handler, type, flags, eventGroup);
     }
   }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -134,17 +134,18 @@
 #include "nsDOMCSSDeclaration.h"
 #include "nsStyledElement.h"
 #include "nsGkAtoms.h"
 #include "nsXULContentUtils.h"
 #include "nsNodeUtils.h"
 #include "nsFrameLoader.h"
 #include "prlog.h"
 #include "rdf.h"
-
+#include "nsIDOM3EventTarget.h"
+#include "nsIDOMEventGroup.h"
 #include "nsIControllers.h"
 
 // The XUL doc interface
 #include "nsIDOMXULDocument.h"
 
 #include "nsReadableUtils.h"
 #include "nsITimelineService.h"
 #include "nsIFrame.h"
@@ -1536,16 +1537,27 @@ nsXULElement::List(FILE* out, PRInt32 aI
 }
 #endif
 
 nsresult
 nsXULElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
     aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
     nsIAtom* tag = Tag();
+    if (IsRootOfNativeAnonymousSubtree() &&
+        (tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner) &&
+        (aVisitor.mEvent->message == NS_MOUSE_CLICK ||
+         aVisitor.mEvent->message == NS_MOUSE_DOUBLECLICK ||
+         aVisitor.mEvent->message == NS_XUL_COMMAND ||
+         aVisitor.mEvent->message == NS_CONTEXTMENU)) {
+        // Don't propagate these events from native anonymous scrollbar.
+        aVisitor.mCanHandle = PR_TRUE;
+        aVisitor.mParentTarget = nsnull;
+        return NS_OK;
+    }
     if (aVisitor.mEvent->message == NS_XUL_COMMAND &&
         aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this) &&
         tag != nsGkAtoms::command) {
         // See if we have a command elt.  If so, we execute on the command
         // instead of on our content element.
         nsAutoString command;
         GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
         if (!command.IsEmpty()) {
@@ -2172,23 +2184,29 @@ static void
 PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
                           void* aPropertyValue, void* aData)
 {
   nsIDOMEventListener* listener =
     static_cast<nsIDOMEventListener*>(aPropertyValue);
   if (!listener) {
     return;
   }
-  nsCOMPtr<nsIDOMEventTarget> target =
+  nsCOMPtr<nsIDOM3EventTarget> target =
     do_QueryInterface(static_cast<nsINode*>(aObject));
   if (target) {
-    target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), listener,
-                                PR_FALSE);
-    target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), listener,
-                                PR_FALSE);
+    nsCOMPtr<nsIDOMEventGroup> systemGroup;
+    static_cast<nsPIDOMEventTarget*>(aObject)->
+      GetSystemEventGroup(getter_AddRefs(systemGroup));
+    if (systemGroup) {
+      target->RemoveGroupedEventListener(NS_LITERAL_STRING("mousedown"),
+                                         listener, PR_FALSE, systemGroup);
+
+      target->RemoveGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
+                                         listener, PR_FALSE, systemGroup);
+    }
   }
   NS_RELEASE(listener);
 }
 
 nsresult
 nsXULElement::AddPopupListener(nsIAtom* aName)
 {
     // Add a popup listener to the element
@@ -2200,34 +2218,42 @@ nsXULElement::AddPopupListener(nsIAtom* 
 
     nsCOMPtr<nsIDOMEventListener> popupListener =
         static_cast<nsIDOMEventListener*>(GetProperty(listenerAtom));
     if (popupListener) {
         // Popup listener is already installed.
         return NS_OK;
     }
 
+    nsCOMPtr<nsIDOMEventGroup> systemGroup;
+    GetSystemEventGroup(getter_AddRefs(systemGroup));
+    NS_ENSURE_STATE(systemGroup);
+
     nsresult rv = NS_NewXULPopupListener(this, isContext,
                                          getter_AddRefs(popupListener));
     if (NS_FAILED(rv))
         return rv;
 
     // Add the popup as a listener on this element.
-    nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent *>(this)));
+    nsCOMPtr<nsIDOM3EventTarget> target(do_QueryInterface(static_cast<nsIContent *>(this)));
     NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
     rv = SetProperty(listenerAtom, popupListener, PopupListenerPropertyDtor,
                      PR_TRUE);
     NS_ENSURE_SUCCESS(rv, rv);
     // Want the property to have a reference to the listener.
     nsIDOMEventListener* listener = nsnull;
     popupListener.swap(listener);
-    if (isContext)
-      target->AddEventListener(NS_LITERAL_STRING("contextmenu"), listener, PR_FALSE);
-    else
-      target->AddEventListener(NS_LITERAL_STRING("mousedown"), listener, PR_FALSE);
+
+    if (isContext) {
+      target->AddGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
+                                      listener, PR_FALSE, systemGroup);
+    } else {
+      target->AddGroupedEventListener(NS_LITERAL_STRING("mousedown"),
+                                      listener, PR_FALSE, systemGroup);
+    }
     return NS_OK;
 }
 
 PRInt32
 nsXULElement::IntrinsicState() const
 {
     PRInt32 state = nsGenericElement::IntrinsicState();
 
--- a/content/xul/content/test/Makefile.in
+++ b/content/xul/content/test/Makefile.in
@@ -41,16 +41,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/xul/content/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = 	test_bug330705-2.xul \
 		test_bug233643.xul \
+		test_bug486990.xul \
 		$(NULL)
 	
 _CHROME_FILES = \
  		test_bug398289.html \
  		398289-resource.xul \
  		$(NULL)
 
 libs:: $(_TEST_FILES)
new file mode 100644
--- /dev/null
+++ b/content/xul/content/test/test_bug486990.xul
@@ -0,0 +1,168 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=486990
+-->
+<window title="Mozilla Bug 486990"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="setTimeout(runTests, 0);">
+  <script type="application/javascript" src="/MochiKit/packed.js"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
+
+  <!-- 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=486990"
+     target="_blank">Mozilla Bug 486990</a>
+
+  </body>
+  <div xmlns="http://www.w3.org/1999/xhtml">
+  <select size="5" id="select">
+    <option>1</option>
+    <option>2</option>
+    <option>3</option>
+    <option>4</option>
+    <option>5</option>
+    <option>6</option>
+    <option>7</option>
+    <option>8</option>
+    <option>9</option>
+    <option>10</option>
+  </select>
+  </div>
+  <menupopup id="cm" onpopupshowing="popupShowing(event);">
+    <menuitem label="Mozilla" value="http://mozilla.org"/>
+    <menuitem label="Slashdot" value="http://slashdot.org"/>
+    <menuitem label="Sourceforge" value="http://sf.net"/>
+    <menuitem label="Freshmeat" value="http://freshmeat.net"/>
+  </menupopup>
+  <button label="test button" contextmenu="cm" id="testbutton"/>
+  
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 486990 **/
+
+  SimpleTest.waitForExplicitFinish();
+
+  var prevented = false;
+  var eventCount = 0;
+
+  function fooListener(evt) {
+    evt.preventDefault();
+    prevented = evt.getPreventDefault();
+    ++eventCount;
+  };
+
+  var clickCount = 0;
+  var mouseDownCount = 0;
+  var mouseUpCount = 0;
+  function clickListener(evt) {
+    ++clickCount;
+  }
+
+  function mouseDownListener(evt) {
+    ++mouseDownCount;
+  }
+
+  function mouseUpListener(evt) {
+    ++mouseUpCount;
+  }
+
+  var popupshowingcount = 0;
+
+  function popupShowing(evt) {
+    ++popupshowingcount;
+    evt.preventDefault();
+  }
+
+  function contextMenuStopper(evt) {
+    evt.stopPropagation();
+  }
+
+  function contextMenuPreventer(evt) {
+    evt.preventDefault();
+  }
+
+  function allowDisableContextMenu(allow) {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    const prefSvcContractID = "@mozilla.org/preferences-service;1";
+    const prefSvcIID = Components.interfaces.nsIPrefService;
+    var prefs = Components.classes[prefSvcContractID].getService(prefSvcIID)
+                                                     .getBranch("dom.event.contextmenu.");
+    try {
+      if (allow) {
+        prefs.clearUserPref("enabled");
+      } else {
+        prefs.setBoolPref("enabled", allow);
+      }
+    } catch(ex) {}
+  }
+  
+  function runTests() {
+    document.addEventListener("foo", fooListener, true);
+    var e1 = document.createEvent("Event");
+    e1.initEvent("foo", true, true);
+    document.dispatchEvent(e1);
+    is(eventCount, 1, "Wrong event count");
+    ok(prevented, "Default handling should have been prevented.");
+
+    prevented = false;
+    var e2 = document.createEvent("Event");
+    e2.initEvent("foo", false, false);
+    document.dispatchEvent(e1);
+    is(eventCount, 2, "Wrong event count");
+    ok(prevented, "Default handling should have been prevented.");
+
+    var tb = document.getElementById("testbutton");
+    dispatchTrustedContextMenuEvent(tb);
+    is(popupshowingcount, 1, "Should have got 'popupShowing' event!");
+
+    tb.addEventListener("contextmenu", contextMenuStopper, true);
+    dispatchTrustedContextMenuEvent(tb);
+    is(popupshowingcount, 2, "Should have got 'popupShowing' event!");
+
+    tb.addEventListener("contextmenu", contextMenuPreventer, true);
+    dispatchTrustedContextMenuEvent(tb);
+    is(popupshowingcount, 2, "Should not have got 'popupShowing' event!");
+
+    allowDisableContextMenu(false);
+    dispatchTrustedContextMenuEvent(tb);
+    is(popupshowingcount, 3, "Should have got 'popupShowing' event!");
+
+    allowDisableContextMenu(true);
+    dispatchTrustedContextMenuEvent(tb);
+    is(popupshowingcount, 3, "Should not have got 'popupshowing' event!");
+
+    var s = document.getElementById("select");
+    s.addEventListener("click", clickListener, true);
+    s.addEventListener("mousedown", mouseDownListener, true);
+    s.addEventListener("mouseup", mouseUpListener, true);
+
+    synthesizeMouse(s, 1, 10, {}, window);
+    is(clickCount, 1, "Should have got click event!");
+    is(mouseDownCount, 1, "Should have got mousedown event!");
+    is(mouseUpCount, 1, "Should have got mouseup event!");
+
+    // Dispatch to scrollbar.
+    synthesizeMouse(s, s.getBoundingClientRect().right - 3, 10, {}, window);
+    is(clickCount, 1, "Should not have got click event!");
+    is(mouseDownCount, 2, "Should have got mousedown event!");
+    is(mouseUpCount, 2, "Should have got mouseup event!");
+
+    SimpleTest.finish();
+  }
+
+  function dispatchTrustedContextMenuEvent(target) {
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    var e = document.createEvent("MouseEvent");
+    e.initMouseEvent("contextmenu", true, true, window, 0, 0, 0, 0, 0, 
+                      false, false, false, false, 2, null);
+    return target.dispatchEvent(e);
+  }
+
+  ]]>
+  </script>
+</window>
--- a/dom/interfaces/events/nsIDOMNSEvent.idl
+++ b/dom/interfaces/events/nsIDOMNSEvent.idl
@@ -39,17 +39,17 @@
 #include "domstubs.idl"
 
 %{C++
 #ifdef ERROR
 #undef ERROR
 #endif
 %}
 
-[scriptable, uuid(e565d518-4510-407f-a3d9-3b4107549c6d)]
+[scriptable, uuid(9be8096b-f795-4045-9664-0c275f36fe5b)]
 interface nsIDOMNSEvent : nsISupports
 {
   const long MOUSEDOWN    = 0x00000001;
   const long MOUSEUP      = 0x00000002;
   const long MOUSEOVER    = 0x00000004;
   const long MOUSEOUT     = 0x00000008;
   const long MOUSEMOVE    = 0x00000010;
   const long MOUSEDRAG    = 0x00000020;
@@ -109,10 +109,12 @@ interface nsIDOMNSEvent : nsISupports
    */
   void                      preventBubble();
 
   /**
    * @deprecated Use nsIDOMEvent::stopPropagation.
    */
   void                      preventCapture();
 
+  boolean                   getPreventDefault();
+
   readonly attribute boolean isTrusted;
 };
--- a/dom/interfaces/events/nsIDOMNSUIEvent.idl
+++ b/dom/interfaces/events/nsIDOMNSUIEvent.idl
@@ -32,26 +32,24 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "domstubs.idl"
+#include "nsIDOMNSEvent.idl"
 
-[scriptable, uuid(a6cf90c4-15b3-11d2-932e-00805f8add32)]
-interface nsIDOMNSUIEvent : nsISupports
+[scriptable, uuid(72c9f79c-98cd-4224-a467-86b59c0a38f7)]
+interface nsIDOMNSUIEvent : nsIDOMNSEvent
 {
   const long SCROLL_PAGE_UP = -32768;
   const long SCROLL_PAGE_DOWN = 32768;
 
-  boolean                   getPreventDefault();
-
   readonly attribute long             layerX;
   readonly attribute long             layerY;
   readonly attribute long             pageX;
   readonly attribute long             pageY;
   readonly attribute unsigned long    which;
   readonly attribute nsIDOMNode       rangeParent;
   readonly attribute long             rangeOffset;
 
--- a/js/src/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/src/xpconnect/src/dom_quickstubs.qsconf
@@ -278,28 +278,28 @@ members = [
     'nsIDOMMouseEvent.button',
     'nsIDOMMouseEvent.altKey',
     'nsIDOMMouseEvent.metaKey',
     'nsIDOMMouseEvent.ctrlKey',
     'nsIDOMMouseEvent.screenY',
     'nsIDOMMouseEvent.screenX',
     'nsIDOMNSEvent.originalTarget',
     'nsIDOMNSEvent.preventCapture',
+    'nsIDOMNSEvent.getPreventDefault',
     'nsIDOMKeyEvent.ctrlKey',
     'nsIDOMKeyEvent.shiftKey',
     'nsIDOMKeyEvent.keyCode',
     'nsIDOMKeyEvent.metaKey',
     'nsIDOMKeyEvent.charCode',
     'nsIDOMKeyEvent.altKey',
     'nsIDOMMutationEvent.attrName',
     'nsIDOMMutationEvent.relatedNode',
     'nsIDOMMutationEvent.attrChange',
     'nsIDOMMutationEvent.newValue',
     'nsIDOMMutationEvent.prevValue',
-    'nsIDOMNSUIEvent.getPreventDefault',
     'nsIDOMNSUIEvent.which',
     'nsIDOMNSUIEvent.rangeParent',
     'nsIDOMNSUIEvent.rangeOffset',
     'nsIDOMNSUIEvent.pageX',
     'nsIDOMNSUIEvent.pageY',
     'nsIDOMNSUIEvent.isChar',
 
     # dom/public/idl/geolocation - None.
--- a/security/manager/ssl/src/nsSmartCardEvent.cpp
+++ b/security/manager/ssl/src/nsSmartCardEvent.cpp
@@ -181,16 +181,22 @@ NS_IMETHODIMP nsSmartCardEvent::PreventC
 }
 
 NS_IMETHODIMP nsSmartCardEvent::GetIsTrusted(PRBool *aIsTrusted)
 {
   NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init");
   return mNSEvent->GetIsTrusted(aIsTrusted);
 }
 
+NS_IMETHODIMP
+nsSmartCardEvent::GetPreventDefault(PRBool* aReturn)
+{
+  NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init");
+  return mNSEvent->GetPreventDefault(aReturn);
+}
 
 // IDOMEvent maps
 NS_IMETHODIMP nsSmartCardEvent::GetType(nsAString & aType)
 {
   NS_ASSERTION(mInner, "SmartCardEvent called without Init");
   return mInner->GetType(aType);
 }