Bug 1308069 - Clear pending error event fired by src="" case if src changed before it fired. r=bz
authorEdgar Chen <echen@mozilla.com>
Thu, 06 Oct 2016 12:30:35 +0800
changeset 360970 688b4667b8101490d062e927eafa1306abf515da
parent 360969 c3477c91656b57e3f983e1708e261afe8a2d6c8f
child 360971 d2b4e898107635cdc9d6b688fc852923257f684c
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1308069
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1308069 - Clear pending error event fired by src="" case if src changed before it fired. r=bz MozReview-Commit-ID: B8f975mZNN9
dom/base/nsImageLoadingContent.cpp
dom/base/nsImageLoadingContent.h
dom/base/test/mochitest.ini
dom/base/test/test_bug1308069.html
dom/events/AsyncEventDispatcher.cpp
dom/events/EventTarget.h
dom/html/HTMLImageElement.cpp
dom/html/HTMLImageElement.h
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/HTMLObjectElement.cpp
dom/html/HTMLObjectElement.h
dom/html/HTMLSharedObjectElement.cpp
dom/html/HTMLSharedObjectElement.h
dom/svg/SVGFEImageElement.cpp
dom/svg/SVGFEImageElement.h
dom/svg/SVGImageElement.cpp
dom/svg/SVGImageElement.h
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -741,20 +741,27 @@ nsImageLoadingContent::LoadImage(const n
 {
   // First, get a document (needed for security checks and the like)
   nsIDocument* doc = GetOurOwnerDoc();
   if (!doc) {
     // No reason to bother, I think...
     return NS_OK;
   }
 
+  // Pending load/error events need to be canceled in some situations. This
+  // is not documented in the spec, but can cause site compat problems if not
+  // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
+  CancelPendingEvent();
+
   if (aNewURI.IsEmpty()) {
     // Cancel image requests and then fire only error event per spec.
     CancelImageRequests(aNotify);
-    FireEvent(NS_LITERAL_STRING("error"));
+    // Mark error event as cancelable only for src="" case, since only this
+    // error causes site compat problem (bug 1308069) for now.
+    FireEvent(NS_LITERAL_STRING("error"), true);
     return NS_OK;
   }
 
   // Fire loadstart event
   FireEvent(NS_LITERAL_STRING("loadstart"));
 
   // Parse the URI string to get image URI
   nsCOMPtr<nsIURI> imageURI;
@@ -776,16 +783,21 @@ nsresult
 nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
                                  bool aForce,
                                  bool aNotify,
                                  ImageLoadType aImageLoadType,
                                  bool aLoadStart,
                                  nsIDocument* aDocument,
                                  nsLoadFlags aLoadFlags)
 {
+  // Pending load/error events need to be canceled in some situations. This
+  // is not documented in the spec, but can cause site compat problems if not
+  // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
+  CancelPendingEvent();
+
   // Fire loadstart event if required
   if (aLoadStart) {
     FireEvent(NS_LITERAL_STRING("loadstart"));
   }
 
   if (!mLoadingEnabled) {
     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
     // don't want/need it.
@@ -1138,36 +1150,57 @@ nsImageLoadingContent::StringToURI(const
   return NS_NewURI(aURI,
                    aSpec,
                    charset.IsEmpty() ? nullptr : charset.get(),
                    baseURL,
                    nsContentUtils::GetIOService());
 }
 
 nsresult
-nsImageLoadingContent::FireEvent(const nsAString& aEventType)
+nsImageLoadingContent::FireEvent(const nsAString& aEventType, bool aIsCancelable)
 {
   if (nsContentUtils::DocumentInactiveForImageLoads(GetOurOwnerDoc())) {
     // Don't bother to fire any events, especially error events.
     return NS_OK;
   }
 
   // We have to fire the event asynchronously so that we won't go into infinite
   // loops in cases when onLoad handlers reset the src and the new src is in
   // cache.
 
   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
     new LoadBlockingAsyncEventDispatcher(thisNode, aEventType, false, false);
   loadBlockingAsyncDispatcher->PostDOMEvent();
 
+  if (aIsCancelable) {
+    mPendingEvent = loadBlockingAsyncDispatcher;
+  }
+
   return NS_OK;
 }
 
+void
+nsImageLoadingContent::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  if (mPendingEvent == aEvent) {
+    mPendingEvent = nullptr;
+  }
+}
+
+void
+nsImageLoadingContent::CancelPendingEvent()
+{
+  if (mPendingEvent) {
+    mPendingEvent->Cancel();
+    mPendingEvent = nullptr;
+  }
+}
+
 RefPtr<imgRequestProxy>&
 nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
 {
   nsImageFrame* frame = do_QueryFrame(GetOurPrimaryFrame());
   if (frame) {
     // Detect JavaScript-based animations created by changing the |src|
     // attribute on a timer.
     TimeStamp now = TimeStamp::Now();
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -27,16 +27,20 @@
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsIURI;
 class nsIDocument;
 class nsPresContext;
 class nsIContent;
 class imgRequestProxy;
 
+namespace mozilla {
+class AsyncEventDispatcher;
+} // namespace mozilla
+
 #ifdef LoadImage
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
 class nsImageLoadingContent : public nsIImageLoadingContent,
                               public imgIOnloadBlocker
 {
@@ -208,16 +212,18 @@ protected:
 
   nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
   void OnUnlockedDraw();
   nsresult OnImageIsAnimated(imgIRequest *aRequest);
 
   // The nsContentPolicyType we would use for this ImageLoadType
   static nsContentPolicyType PolicyTypeForLoad(ImageLoadType aImageLoadType);
 
+  void AsyncEventRunning(mozilla::AsyncEventDispatcher* aEvent);
+
 private:
   /**
    * Struct used to manage the image observers.
    */
   struct ImageObserver {
     explicit ImageObserver(imgINotificationObserver* aObserver);
     ~ImageObserver();
 
@@ -255,18 +261,26 @@ private:
    */
   void UpdateImageState(bool aNotify);
 
   /**
    * Method to fire an event once we know what's going on with the image load.
    *
    * @param aEventType "loadstart", "loadend", "load", or "error" depending on
    *                   how things went
+   * @param aIsCancelable true if event is cancelable.
    */
-  nsresult FireEvent(const nsAString& aEventType);
+  nsresult FireEvent(const nsAString& aEventType, bool aIsCancelable = false);
+
+  /**
+   * Method to cancel and null-out pending event if they exist.
+   */
+  void CancelPendingEvent();
+
+  RefPtr<mozilla::AsyncEventDispatcher> mPendingEvent;
 
 protected:
   /**
    * Method to create an nsIURI object from the given string (will
    * handle getting the right charset, base, etc).  You MUST pass in a
    * non-null document to this function.
    *
    * @param aSpec the string spec (from an HTML attribute, eg)
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -626,16 +626,17 @@ skip-if = buildapp == 'b2g'
 [test_bug1250148.html]
 [test_bug1259588.html]
 [test_bug1263696.html]
 [test_bug1268962.html]
 [test_bug1274806.html]
 [test_bug1281963.html]
 [test_bug1295852.html]
 [test_bug1307730.html]
+[test_bug1308069.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_classList.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_copyimage.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1308069.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1308069
+-->
+<head>
+<title>Bug 1308069</title>
+<script 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=1308069">Mozilla Bug 1308069</a>
+<script class="testbody" type="text/javascript">
+
+function testClearPendingErrorEvent() {
+  return new Promise(function(aResolve, aReject) {
+    var hasErrorEvent = false;
+    var imgTarget = new Image();
+
+    var imgForChangingTargetSrc = new Image();
+    // Queue an error event for changing imgTarget's src.
+    imgForChangingTargetSrc.src = '';
+    imgForChangingTargetSrc.onerror = function() {
+      // This clears imgTarget's pending error event.
+      imgTarget.src = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96"><path d="M10,10L32,90L90,32z" fill="lightgreen"/></svg>';
+
+      // Queue an error event for checking and resolving promise.
+      var imgForCheckingAndResolvingPromise = new Image();
+      imgForCheckingAndResolvingPromise.src = '';
+      imgForCheckingAndResolvingPromise.onerror = function() {
+        ok(!hasErrorEvent,
+           'Should not receive an error event since the pending error event ' +
+           'should be cleared before it fired');
+        aResolve();
+      };
+    };
+
+    // Setting src to empty string queues an error event.
+    imgTarget.src = '';
+    imgTarget.onerror = function() {
+      hasErrorEvent = true;
+    };
+  });
+}
+
+function testReplacePendingErrorEvent() {
+  return new Promise(function(aResolve) {
+    var numOfErrorEvent = 0;
+    var imgTarget = new Image();
+
+    var imgForChangingTargetSrc = new Image();
+    // Queue an error event for changing imgTarget's src.
+    imgForChangingTargetSrc.src = '';
+    imgForChangingTargetSrc.onerror = function() {
+      // This clears pending error event and fires a new one.
+      imgTarget.src = '';
+
+      // Queue an error event for checking and resolving promise.
+      var imgForCheckingAndResolvingPromise = new Image();
+      imgForCheckingAndResolvingPromise.src = '';
+      imgForCheckingAndResolvingPromise.onerror = function() {
+        is(numOfErrorEvent, 1,
+           'Should only receive one error event since the first pending error ' +
+           'event should be cleared before it fired');
+        aResolve();
+      };
+    };
+
+    // Setting src to empty string queues an error event.
+    imgTarget.src = '';
+    imgTarget.onerror = function() {
+      numOfErrorEvent++;
+    };
+  });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+Promise.resolve()
+.then(() => testClearPendingErrorEvent())
+.then(() => testReplacePendingErrorEvent())
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
--- a/dom/events/AsyncEventDispatcher.cpp
+++ b/dom/events/AsyncEventDispatcher.cpp
@@ -34,16 +34,17 @@ AsyncEventDispatcher::AsyncEventDispatch
 }
 
 NS_IMETHODIMP
 AsyncEventDispatcher::Run()
 {
   if (mCanceled) {
     return NS_OK;
   }
+  mTarget->AsyncEventRunning(this);
   RefPtr<Event> event = mEvent ? mEvent->InternalDOMEvent() : nullptr;
   if (!event) {
     event = NS_NewDOMEvent(mTarget, nullptr, nullptr);
     event->InitEvent(mEventType, mBubbles, false);
     event->SetTrusted(true);
   }
   if (mOnlyChromeDispatch) {
     MOZ_ASSERT(event->IsTrusted());
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -11,16 +11,17 @@
 #include "nsWrapperCache.h"
 #include "nsIAtom.h"
 
 class nsPIDOMWindowOuter;
 class nsIGlobalObject;
 
 namespace mozilla {
 
+class AsyncEventDispatcher;
 class ErrorResult;
 class EventListenerManager;
 
 namespace dom {
 
 class AddEventListenerOptionsOrBoolean;
 class Event;
 class EventListener;
@@ -86,16 +87,19 @@ public:
   virtual EventListenerManager* GetOrCreateListenerManager() = 0;
 
   /**
    * Get the event listener manager, returning null if it does not already
    * exist.
    */
   virtual EventListenerManager* GetExistingListenerManager() const = 0;
 
+  // Called from AsyncEventDispatcher to notify it is running.
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {}
+
   virtual bool IsApzAware() const;
 
 protected:
   EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
                                        const nsAString& aTypeString);
   void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                        EventHandlerNonNull* aHandler);
 };
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -161,16 +161,22 @@ NS_IMPL_INT_ATTR(HTMLImageElement, Vspac
 
 bool
 HTMLImageElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
           nsGenericHTMLElement::IsInteractiveHTMLContent(aIgnoreTabindex);
 }
 
+void
+HTMLImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
 nsresult
 HTMLImageElement::GetCurrentSrc(nsAString& aValue)
 {
   nsCOMPtr<nsIURI> currentURI;
   GetCurrentURI(getter_AddRefs(currentURI));
   if (currentURI) {
     nsAutoCString spec;
     currentURI->GetSpec(spec);
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -44,16 +44,19 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual bool Draggable() const override;
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   // nsIDOMHTMLImageElement
   NS_DECL_NSIDOMHTMLIMAGEELEMENT
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLImageElement, img)
 
   // override from nsImageLoadingContent
   CORSMode GetCORSMode() override;
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3666,16 +3666,22 @@ HTMLInputElement::IsNodeApzAwareInternal
 
 bool
 HTMLInputElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return mType != NS_FORM_INPUT_HIDDEN ||
          nsGenericHTMLFormElementWithState::IsInteractiveHTMLContent(aIgnoreTabindex);
 }
 
+void
+HTMLInputElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
 NS_IMETHODIMP
 HTMLInputElement::Select()
 {
   if (mType == NS_FORM_INPUT_NUMBER) {
     nsNumberControlFrame* numberControlFrame =
       do_QueryFrame(GetPrimaryFrame());
     if (numberControlFrame) {
       return numberControlFrame->HandleSelectCall();
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -137,16 +137,19 @@ public:
   // nsINode
 #if !defined(ANDROID) && !defined(XP_MACOSX)
   virtual bool IsNodeApzAwareInternal() const override;
 #endif
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   // nsIDOMHTMLInputElement
   NS_DECL_NSIDOMHTMLINPUTELEMENT
 
   // nsIPhonetic
   NS_DECL_NSIPHONETIC
 
   // nsIDOMNSEditableElement
   NS_IMETHOD GetEditor(nsIEditor** aEditor) override
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -54,16 +54,22 @@ HTMLObjectElement::~HTMLObjectElement()
 
 bool
 HTMLObjectElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
          nsGenericHTMLFormElement::IsInteractiveHTMLContent(aIgnoreTabindex);
 }
 
+void
+HTMLObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
 bool
 HTMLObjectElement::IsDoneAddingChildren()
 {
   return mIsDoneAddingChildren;
 }
 
 void
 HTMLObjectElement::DoneAddingChildren(bool aHaveNotified)
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -43,16 +43,19 @@ public:
   static void HandlePluginInstantiated(Element* aElement);
   // Weak pointer. Null if last action was blur.
   static Element* sLastFocused;
 #endif
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   // nsIDOMHTMLObjectElement
   NS_DECL_NSIDOMHTMLOBJECTELEMENT
 
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -103,16 +103,22 @@ NS_IMETHODIMP
 HTMLSharedObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   HTMLObjectElement::HandleFocusBlurPlugin(this, aVisitor.mEvent);
   return NS_OK;
 }
 
 #endif // #ifdef XP_MACOSX
 
+void
+HTMLSharedObjectElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
 nsresult
 HTMLSharedObjectElement::BindToTree(nsIDocument *aDocument,
                                     nsIContent *aParent,
                                     nsIContent *aBindingParent,
                                     bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
--- a/dom/html/HTMLSharedObjectElement.h
+++ b/dom/html/HTMLSharedObjectElement.h
@@ -38,16 +38,19 @@ public:
 #endif
 
   // nsIDOMHTMLAppletElement
   NS_DECL_NSIDOMHTMLAPPLETELEMENT
 
   // Can't use macro for nsIDOMHTMLEmbedElement because it has conflicts with
   // NS_DECL_NSIDOMHTMLAPPLETELEMENT.
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   // nsIDOMHTMLEmbedElement
   NS_IMETHOD GetSrc(nsAString &aSrc) override;
   NS_IMETHOD SetSrc(const nsAString &aSrc) override;
   NS_IMETHOD GetType(nsAString &aType) override;
   NS_IMETHOD SetType(const nsAString &aType) override;
 
   virtual nsresult BindToTree(nsIDocument *aDocument, nsIContent *aParent,
                               nsIContent *aBindingParent,
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -90,16 +90,25 @@ SVGFEImageElement::LoadSVGImage(bool aFo
       return NS_OK;
     }
   }
 
   return LoadImage(href, aForce, aNotify, eImageLoadType_Normal);
 }
 
 //----------------------------------------------------------------------
+// EventTarget methods:
+
+void
+SVGFEImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
+//----------------------------------------------------------------------
 // nsIContent methods:
 
 NS_IMETHODIMP_(bool)
 SVGFEImageElement::IsAttributeMapped(const nsIAtom* name) const
 {
   static const MappedAttributeEntry* const map[] = {
     sGraphicsMap
   };
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -33,16 +33,19 @@ protected:
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 public:
   virtual bool SubregionIsUnionOfRegions() override { return false; }
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   virtual FilterPrimitiveDescription
     GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                             const IntRect& aFilterSubregion,
                             const nsTArray<bool>& aInputsAreTainted,
                             nsTArray<RefPtr<SourceSurface>>& aInputImages) override;
   virtual bool AttributeAffectsRendering(
           int32_t aNameSpaceID, nsIAtom* aAttribute) const override;
   virtual nsSVGString& GetResultImageName() override { return mStringAttributes[RESULT]; }
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -132,16 +132,25 @@ SVGImageElement::LoadSVGImage(bool aForc
 
   if (baseURI && !href.IsEmpty())
     NS_MakeAbsoluteURI(href, href, baseURI);
 
   return LoadImage(href, aForce, aNotify, eImageLoadType_Normal);
 }
 
 //----------------------------------------------------------------------
+// EventTarget methods:
+
+void
+SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
+{
+  nsImageLoadingContent::AsyncEventRunning(aEvent);
+}
+
+//----------------------------------------------------------------------
 // nsIContent methods:
 
 nsresult
 SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                               const nsAttrValue* aValue, bool aNotify)
 {
   if (aName == nsGkAtoms::href &&
       (aNamespaceID == kNameSpaceID_None ||
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -36,16 +36,19 @@ protected:
   friend nsresult (::NS_NewSVGImageElement(nsIContent **aResult,
                                            already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
 
+  // EventTarget
+  virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+
   // nsIContent interface
   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) override;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;