Bug 484775 - DocumentFragments and Attribute nodes should expose nsIDOMEventTarget to JS, r+sr=peterv
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 07 May 2009 16:59:51 +0300
changeset 28073 db76f7da877dca1c8babb710fc4116343ccd2f63
parent 28072 1ac2f774cabb96cbc1b400be0bec007e2f6048ee
child 28074 c1b04224d6cf4ee99dfd03c9ceb6faabe82e0094
push id6881
push useropettay@mozilla.com
push dateThu, 07 May 2009 14:02:30 +0000
treeherdermozilla-central@db76f7da877d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs484775
milestone1.9.2a1pre
Bug 484775 - DocumentFragments and Attribute nodes should expose nsIDOMEventTarget to JS, r+sr=peterv
content/base/public/nsIContent.h
content/base/public/nsINode.h
content/base/src/nsDOMAttribute.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/events/src/nsEventListenerManager.cpp
dom/base/nsDOMClassInfo.cpp
dom/tests/mochitest/bugs/Makefile.in
dom/tests/mochitest/bugs/test_bug484775.html
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -37,17 +37,16 @@
 #ifndef nsIContent_h___
 #define nsIContent_h___
 
 #include "nsCOMPtr.h" // for already_AddRefed
 #include "nsStringGlue.h"
 #include "nsCaseTreatment.h"
 #include "nsChangeHint.h"
 #include "nsINode.h"
-#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
 
 // Forward declarations
 class nsIAtom;
 class nsIDocument;
 class nsPresContext;
 class nsIDOMEvent;
 class nsIContent;
 class nsIEventListenerManager;
@@ -59,18 +58,18 @@ class nsAttrName;
 class nsTextFragment;
 class nsIDocShell;
 #ifdef MOZ_SMIL
 class nsISMILAttr;
 #endif // MOZ_SMIL
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID       \
-{ 0x48cb2d6d, 0x9ccc, 0x4d0b, \
-  { 0x8c, 0x07, 0x29, 0x96, 0xb5, 0xf9, 0x68, 0x55 } }
+{ 0x3ca5afbe, 0x1052, 0x4682, \
+  { 0x9f, 0xa0, 0x0e, 0x39, 0xe4, 0xf8, 0xef, 0x9d } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
 #ifdef MOZILLA_INTERNAL_API
@@ -750,29 +749,16 @@ public:
    * the state that is independent of the node's presentation.  To get the full
    * content state, use nsIEventStateManager.  Also see nsIEventStateManager
    * for the possible bits that could be set here.
    */
   // XXXbz this is PRInt32 because all the ESM content state APIs use
   // PRInt32.  We should really use PRUint32 instead.
   virtual PRInt32 IntrinsicState() const;
 
-  /* The default script type (language) ID for this content.
-     All content must support fetching the default script language.
-   */
-  virtual PRUint32 GetScriptTypeID() const
-  { return nsIProgrammingLanguage::JAVASCRIPT; }
-
-  /* Not all content supports setting a new default language */
-  virtual nsresult SetScriptTypeID(PRUint32 aLang)
-  {
-    NS_NOTREACHED("SetScriptTypeID not implemented");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-
   /**
    * Get the ID of this content node (the atom corresponding to the
    * value of the null-namespace attribute whose name is given by
    * GetIDAttributeName().  This may be null if there is no ID.
    */
   virtual nsIAtom* GetID() const = 0;
 
   /**
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -40,16 +40,17 @@
 
 #include "nsPIDOMEventTarget.h"
 #include "nsEvent.h"
 #include "nsPropertyTable.h"
 #include "nsTObserverArray.h"
 #include "nsINodeInfo.h"
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
+#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
 
 class nsIContent;
 class nsIDocument;
 class nsIDOMEvent;
 class nsIDOMNode;
 class nsIDOMNodeList;
 class nsINodeList;
 class nsIPresShell;
@@ -234,18 +235,18 @@ private:
   // sMutationCount is a global mutation counter which is decreased by one at
   // every mutation. It is capped at 0 to avoid wrapping.
   // Its value is always between 0 and 300, inclusive.
   static PRUint32 sMutationCount;
 };
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x7bccc9bd, 0x30eb, 0x47c0, \
- { 0x8b, 0xc7, 0x6f, 0x19, 0x75, 0xc8, 0xe7, 0xd7 } }
+{ 0xfc22c6df, 0x3e8e, 0x47c3, \
+  { 0x96, 0xa6, 0xaf, 0x14, 0x3c, 0x05, 0x88, 0x68 } }
  
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public nsPIDOMEventTarget,
                 public nsWrapperCache
@@ -857,16 +858,31 @@ public:
     }
 #ifdef DEBUG
     nsMutationGuard mGuard;
 #endif
     nsIContent* const * mCur;
     nsIContent* const * mEnd;
   };
 
+  /**
+   * The default script type (language) ID for this node.
+   * All nodes must support fetching the default script language.
+   */
+  virtual PRUint32 GetScriptTypeID() const
+  { return nsIProgrammingLanguage::JAVASCRIPT; }
+
+  /**
+   * Not all nodes support setting a new default language.
+   */
+  NS_IMETHOD SetScriptTypeID(PRUint32 aLang)
+  {
+    NS_NOTREACHED("SetScriptTypeID not implemented");
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
 protected:
 
   // Override this function to create a custom slots class.
   virtual nsINode::nsSlots* CreateSlots();
 
   PRBool HasSlots() const
   {
     return !(mFlagsOrSlots & NODE_DOESNT_HAVE_SLOTS);
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -106,16 +106,22 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_INTERFACE_TABLE_HEAD(nsDOMAttribute)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_NODE_INTERFACE_TABLE7(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsINode,
                            nsIDOMNode, nsIDOM3Node, nsIDOM3Attr,
                            nsPIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttribute)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
+  NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
+                                 nsDOMEventRTTearoff::Create(this))
+  NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
+                                 nsDOMEventRTTearoff::Create(this))
+  NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
+                                 nsDOMEventRTTearoff::Create(this))
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Attr)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMAttribute, nsIDOMAttr)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsDOMAttribute, nsIDOMAttr,
                                       nsNodeUtils::LastRelease(this))
 
 void
@@ -726,33 +732,34 @@ nsDOMAttribute::RemoveChildAt(PRUint32 a
   SetDOMStringToNull(nullString);
   SetValue(nullString);
   return NS_OK;
 }
 
 nsresult
 nsDOMAttribute::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
-  // We don't support event dispatching to attributes yet.
-  aVisitor.mCanHandle = PR_FALSE;
+  aVisitor.mCanHandle = PR_TRUE;
   return NS_OK;
 }
 
 nsresult
 nsDOMAttribute::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
 
 nsresult
 nsDOMAttribute::DispatchDOMEvent(nsEvent* aEvent, nsIDOMEvent* aDOMEvent,
                                  nsPresContext* aPresContext,
                                  nsEventStatus* aEventStatus)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  return nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode*>(this),
+                                             aEvent, aDOMEvent,
+                                             aPresContext, aEventStatus);
 }
 
 nsresult
 nsDOMAttribute::GetListenerManager(PRBool aCreateIfNotFound,
                                    nsIEventListenerManager** aResult)
 {
   return nsContentUtils::GetListenerManager(this, aCreateIfNotFound, aResult);
 }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1531,56 +1531,56 @@ nsNodeSupportsWeakRefTearoff::GetWeakRef
 //----------------------------------------------------------------------
 
 nsDOMEventRTTearoff *
 nsDOMEventRTTearoff::mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
 
 PRUint32 nsDOMEventRTTearoff::mCachedEventTearoffCount = 0;
 
 
-nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsIContent *aContent)
-  : mContent(aContent)
+nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsINode *aNode)
+  : mNode(aNode)
 {
 }
 
 nsDOMEventRTTearoff::~nsDOMEventRTTearoff()
 {
 }
 
-NS_IMPL_CYCLE_COLLECTION_1(nsDOMEventRTTearoff, mContent)
+NS_IMPL_CYCLE_COLLECTION_1(nsDOMEventRTTearoff, mNode)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventRTTearoff)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
-NS_INTERFACE_MAP_END_AGGREGATED(mContent)
+NS_INTERFACE_MAP_END_AGGREGATED(mNode)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMEventRTTearoff,
                                           nsIDOMEventTarget)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDOMEventRTTearoff,
                                                         nsIDOMEventTarget,
                                                         LastRelease())
 
 nsDOMEventRTTearoff *
-nsDOMEventRTTearoff::Create(nsIContent *aContent)
+nsDOMEventRTTearoff::Create(nsINode *aNode)
 {
   if (mCachedEventTearoffCount) {
     // We have cached unused instances of this class, return a cached
     // instance in stead of always creating a new one.
     nsDOMEventRTTearoff *tearoff =
       mCachedEventTearoff[--mCachedEventTearoffCount];
 
     // Set the back pointer to the content object
-    tearoff->mContent = aContent;
+    tearoff->mNode = aNode;
 
     return tearoff;
   }
 
   // The cache is empty, this means we haveto create a new instance.
-  return new nsDOMEventRTTearoff(aContent);
+  return new nsDOMEventRTTearoff(aNode);
 }
 
 // static
 void
 nsDOMEventRTTearoff::Shutdown()
 {
   // Clear our cache.
   while (mCachedEventTearoffCount) {
@@ -1595,18 +1595,18 @@ nsDOMEventRTTearoff::LastRelease()
     // There's still space in the cache for one more instance, put
     // this instance in the cache in stead of deleting it.
     mCachedEventTearoff[mCachedEventTearoffCount++] = this;
 
     // Don't set mContent to null directly since setting mContent to null
     // could result in code that grabs a tearoff from the cache and we don't
     // want to get reused while still being torn down.
     // See bug 330526.
-    nsCOMPtr<nsIContent> kungFuDeathGrip;
-    kungFuDeathGrip.swap(mContent);
+    nsCOMPtr<nsINode> kungFuDeathGrip;
+    kungFuDeathGrip.swap(mNode);
 
     // The refcount balancing and destructor re-entrancy protection
     // code in Release() sets mRefCnt to 1 so we have to set it to 0
     // here to prevent leaks
     mRefCnt = 0;
 
     return;
   }
@@ -1614,61 +1614,61 @@ nsDOMEventRTTearoff::LastRelease()
   delete this;
 }
 
 nsresult
 nsDOMEventRTTearoff::GetDOM3EventTarget(nsIDOM3EventTarget **aTarget)
 {
   nsCOMPtr<nsIEventListenerManager> listener_manager;
   nsresult rv =
-    mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
+    mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(listener_manager, aTarget);
 }
 
 NS_IMETHODIMP
 nsDOMEventRTTearoff::GetScriptTypeID(PRUint32 *aLang)
 {
-    *aLang = mContent->GetScriptTypeID();
-    return NS_OK;
+  *aLang = mNode->GetScriptTypeID();
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEventRTTearoff::SetScriptTypeID(PRUint32 aLang)
 {
-    return mContent->SetScriptTypeID(aLang);
+  return mNode->SetScriptTypeID(aLang);
 }
 
 
 // nsIDOMEventTarget
 NS_IMETHODIMP
 nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
                                       nsIDOMEventListener *aListener,
                                       PRBool useCapture)
 {
   return
     AddEventListener(aType, aListener, useCapture,
-                     !nsContentUtils::IsChromeDoc(mContent->GetOwnerDoc()));
+                     !nsContentUtils::IsChromeDoc(mNode->GetOwnerDoc()));
 }
 
 NS_IMETHODIMP
 nsDOMEventRTTearoff::RemoveEventListener(const nsAString& aType,
                                          nsIDOMEventListener* aListener,
                                          PRBool aUseCapture)
 {
   return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
 }
 
 NS_IMETHODIMP
 nsDOMEventRTTearoff::DispatchEvent(nsIDOMEvent *aEvt, PRBool* _retval)
 {
   nsCOMPtr<nsIEventListenerManager> listener_manager;
   nsresult rv =
-    mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
+    mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(listener_manager);
   NS_ENSURE_STATE(target);
   return target->DispatchEvent(aEvt, _retval);
 }
 
 // nsIDOM3EventTarget
 NS_IMETHODIMP
@@ -1715,17 +1715,17 @@ nsDOMEventRTTearoff::IsRegisteredHere(co
 NS_IMETHODIMP
 nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
                                       nsIDOMEventListener *aListener,
                                       PRBool aUseCapture,
                                       PRBool aWantsUntrusted)
 {
   nsCOMPtr<nsIEventListenerManager> listener_manager;
   nsresult rv =
-    mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
+    mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
 
   if (aWantsUntrusted) {
     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
   }
 
@@ -3193,17 +3193,17 @@ PRUint32
 nsGenericElement::GetScriptTypeID() const
 {
     PtrBits flags = GetFlags();
 
     /* 4 bits reserved for script-type ID. */
     return (flags >> NODE_SCRIPT_TYPE_OFFSET) & 0x000F;
 }
 
-nsresult
+NS_IMETHODIMP
 nsGenericElement::SetScriptTypeID(PRUint32 aLang)
 {
     if ((aLang & 0x000F) != aLang) {
         NS_ERROR("script ID too large!");
         return NS_ERROR_FAILURE;
     }
     /* SetFlags will just mask in the specific flags set, leaving existing
        ones alone.  So we must clear all the bits first */
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -244,17 +244,17 @@ class nsDOMEventRTTearoff : public nsIDO
 {
 private:
   // This class uses a caching scheme so we don't let users of this
   // class create new instances with 'new', in stead the callers
   // should use the static method
   // nsDOMEventRTTearoff::Create(). That's why the constructor and
   // destrucor of this class is private.
 
-  nsDOMEventRTTearoff(nsIContent *aContent);
+  nsDOMEventRTTearoff(nsINode *aNode);
 
   static nsDOMEventRTTearoff *mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
   static PRUint32 mCachedEventTearoffCount;
 
   /**
    * This method gets called by Release() when it's time to delete the
    * this object, in stead of always deleting the object we'll put the
    * object in the cache if unless the cache is already full.
@@ -265,17 +265,17 @@ private:
 
 public:
   virtual ~nsDOMEventRTTearoff();
 
   /**
    * Use this static method to create instances of nsDOMEventRTTearoff.
    * @param aContent the content to create a tearoff for
    */
-  static nsDOMEventRTTearoff *Create(nsIContent *aContent);
+  static nsDOMEventRTTearoff *Create(nsINode *aNode);
 
   /**
    * Call before shutdown to clear the cache and free memory for this class.
    */
   static void Shutdown();
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -292,17 +292,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMEventRTTearoff,
                                            nsIDOMEventTarget)
 
 private:
   /**
    * Strong reference back to the content object from where an instance of this
    * class was 'torn off'
    */
-  nsCOMPtr<nsIContent> mContent;
+  nsCOMPtr<nsINode> mNode;
 };
 
 /**
  * A tearoff class for nsGenericElement to implement NodeSelector
  */
 class nsNodeSelectorTearoff : public nsIDOMNodeSelector
 {
 public:
@@ -421,17 +421,17 @@ public:
   virtual nsIContent *GetBindingParent() const;
   virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void SetMayHaveFrame(PRBool aMayHaveFrame);
   virtual PRBool MayHaveFrame() const;
 
   virtual PRUint32 GetScriptTypeID() const;
-  virtual nsresult SetScriptTypeID(PRUint32 aLang);
+  NS_IMETHOD SetScriptTypeID(PRUint32 aLang);
 
   virtual void DestroyContent();
   virtual void SaveSubtreeState();
 
 #ifdef MOZ_SMIL
   virtual nsISMILAttr* GetAnimatedAttr(const nsIAtom* /*aName*/)
   {
     return nsnull;
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -1279,41 +1279,41 @@ nsEventListenerManager::RemoveEventListe
   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
   
   return RemoveEventListenerByType(aListener, aType, flags, nsnull);
 }
 
 NS_IMETHODIMP
 nsEventListenerManager::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
 {
-  nsCOMPtr<nsIContent> targetContent(do_QueryInterface(mTarget));
-  if (!targetContent) {
+  nsCOMPtr<nsINode> targetNode(do_QueryInterface(mTarget));
+  if (!targetNode) {
     // nothing to dispatch on -- bad!
     return NS_ERROR_FAILURE;
   }
   
   // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
   // if that's the XBL document?  Would we want its presshell?  Or what?
-  nsCOMPtr<nsIDocument> document = targetContent->GetOwnerDoc();
+  nsCOMPtr<nsIDocument> document = targetNode->GetOwnerDoc();
 
   // Do nothing if the element does not belong to a document
   if (!document) {
     return NS_OK;
   }
 
   // Obtain a presentation shell
   nsIPresShell *shell = document->GetPrimaryShell();
   nsCOMPtr<nsPresContext> context;
   if (shell) {
     context = shell->GetPresContext();
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
   nsresult rv =
-    nsEventDispatcher::DispatchDOMEvent(targetContent, nsnull, aEvent,
+    nsEventDispatcher::DispatchDOMEvent(targetNode, nsnull, aEvent,
                                         context, &status);
   *_retval = (status != nsEventStatus_eConsumeNoDefault);
   return rv;
 }
 
 // nsIDOM3EventTarget interface
 NS_IMETHODIMP 
 nsEventListenerManager::AddGroupedEventListener(const nsAString& aType, 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2045,30 +2045,32 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMException)
     DOM_CLASSINFO_MAP_ENTRY(nsIException)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DocumentFragment, nsIDOMDocumentFragment)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentFragment)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Element, nsIDOMElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Attr, nsIDOMAttr)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMAttr)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Attr)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Text, nsIDOMText)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMText)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Text)
   DOM_CLASSINFO_MAP_END
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -92,13 +92,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug437361.html \
 		test_bug458091.html \
 		bug458091_child.html \
 		test_bug459848.html \
 		test_bug463000.html \
 		iframe_bug463000.html \
 		test_bug465263.html \
 		test_bug479143.html \
+		test_bug484775.html \
 		test_bug427744.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug484775.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=484775
+-->
+<head>
+  <title>Test for Bug 484775</title>
+  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=484775">Mozilla Bug 484775</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 484775 **/
+
+var expectedTarget = null;
+var expectedType = null;
+var eventCount = 0;
+
+function listener(evt) {
+  ++eventCount;
+  ok(evt.type, expectedType, "Wrong event type!");
+  ok(evt.target, expectedTarget, "Wrong event type!");
+}
+
+expectedType = "TestEvent";
+var event = document.createEvent("Event");
+event.initEvent(expectedType, true, true);
+ok(event.type, expectedType, "Wrong event type!");
+
+var attr = document.createAttribute("attribute");
+attr.addEventListener(expectedType, listener, false);
+attr.dispatchEvent(event);
+is(eventCount, 1, "Should have fired an event!");
+attr.removeEventListener(expectedType, listener, false);
+
+var df = document.createDocumentFragment();
+df.addEventListener(expectedType, listener, false);
+df.dispatchEvent(event);
+is(eventCount, 2, "Should have fired an event!");
+df.removeEventListener(expectedType, listener, false);
+
+</script>
+</pre>
+</body>
+</html>