Bug 1264769 - Part 1: Dispatch loadend event for image loading. r=hsivonen
☠☠ backed out by ba5c202573c0 ☠ ☠
authorBen Tian <btian@mozilla.com>
Wed, 20 Jul 2016 11:01:46 +0800
changeset 309515 780f7036c084
parent 309514 32eb078cd5dd
child 309516 7b9d3d0c09f5
push id30565
push userkwierso@gmail.com
push date2016-08-17 00:07 +0000
treeherdermozilla-central@1a0e253638fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1264769
milestone51.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 1264769 - Part 1: Dispatch loadend event for image loading. r=hsivonen
dom/base/nsImageLoadingContent.cpp
dom/base/nsImageLoadingContent.h
dom/events/EventNameList.h
dom/webidl/EventHandler.webidl
widget/EventMessageList.h
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -225,18 +225,25 @@ nsImageLoadingContent::OnLoadComplete(im
     MakePendingRequestCurrent();
   }
   MOZ_ASSERT(aRequest == mCurrentRequest,
              "One way or another, we should be current by now");
 
   // Fire the appropriate DOM event.
   if (NS_SUCCEEDED(aStatus)) {
     FireEvent(NS_LITERAL_STRING("load"));
+
+    // Do not fire loadend event for multipart/x-mixed-replace image streams.
+    bool isMultipart;
+    if (NS_FAILED(aRequest->GetMultipart(&isMultipart)) || !isMultipart) {
+      FireEvent(NS_LITERAL_STRING("loadend"));
+    }
   } else {
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
   }
 
   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
 
   return NS_OK;
 }
 
@@ -623,17 +630,19 @@ nsImageLoadingContent::LoadImageWithChan
     TrackImage(req);
     ResetAnimationIfNeeded();
   } else {
     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
     // If we don't have a current URI, we might as well store this URI so people
     // know what we tried (and failed) to load.
     if (!mCurrentRequest)
       aChannel->GetURI(getter_AddRefs(mCurrentURI));
+
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
     aError.Throw(rv);
   }
   return listener.forget();
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
                                             nsIStreamListener** aListener)
@@ -747,19 +756,20 @@ nsImageLoadingContent::LoadImage(const n
     // No reason to bother, I think...
     return NS_OK;
   }
 
   // Second, parse the URI string to get image URI
   nsCOMPtr<nsIURI> imageURI;
   nsresult rv = StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
   if (NS_FAILED(rv)) {
-    // Cancel image requests and fire error event per spec
+    // Cancel image requests and then fire error and loadend events per spec
     CancelImageRequests(aNotify);
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
     return NS_OK;
   }
 
   bool equal;
 
   if (aNewURI.IsEmpty() &&
       doc->GetDocumentURI() &&
       NS_SUCCEEDED(doc->GetDocumentURI()->EqualsExceptRef(imageURI, &equal)) &&
@@ -788,16 +798,17 @@ nsImageLoadingContent::LoadImage(nsIURI*
                                  ImageLoadType aImageLoadType,
                                  nsIDocument* aDocument,
                                  nsLoadFlags aLoadFlags)
 {
   if (!mLoadingEnabled) {
     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
     // don't want/need it.
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
     return NS_OK;
   }
 
   NS_ASSERTION(!aDocument || aDocument == GetOurOwnerDoc(),
                "Bogus document passed in");
   // First, get a document (needed for security checks and the like)
   if (!aDocument) {
     aDocument = GetOurOwnerDoc();
@@ -844,16 +855,17 @@ nsImageLoadingContent::LoadImage(nsIURI*
   nsContentUtils::CanLoadImage(aNewURI,
                                static_cast<nsIImageLoadingContent*>(this),
                                aDocument,
                                aDocument->NodePrincipal(),
                                &cpDecision,
                                policyType);
   if (!NS_CP_ACCEPTED(cpDecision)) {
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
     SetBlockedRequest(aNewURI, cpDecision);
     return NS_OK;
   }
 
   nsLoadFlags loadFlags = aLoadFlags;
   int32_t corsmode = GetCORSMode();
   if (corsmode == CORS_ANONYMOUS) {
     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
@@ -916,17 +928,19 @@ nsImageLoadingContent::LoadImage(nsIURI*
       }
     }
   } else {
     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
     // If we don't have a current URI, we might as well store this URI so people
     // know what we tried (and failed) to load.
     if (!mCurrentRequest)
       mCurrentURI = aNewURI;
+
     FireEvent(NS_LITERAL_STRING("error"));
+    FireEvent(NS_LITERAL_STRING("loadend"));
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsImageLoadingContent::ForceImageState(bool aForce,
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -258,17 +258,18 @@ private:
    * content and updates what ImageState() returns accordingly.  It will also
    * fire a ContentStatesChanged() notification as needed if aNotify is true.
    */
   void UpdateImageState(bool aNotify);
 
   /**
    * Method to fire an event once we know what's going on with the image load.
    *
-   * @param aEventType "load" or "error" depending on how things went
+   * @param aEventType "loadstart", "loadend", "load", or "error" depending on
+   *                   how things went
    */
   nsresult FireEvent(const nsAString& aEventType);
 
 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.
@@ -313,17 +314,17 @@ protected:
   /**
    * Switch our pending request to be our current request.
    * mPendingRequest must be non-null!
    */
   void MakePendingRequestCurrent();
 
   /**
    * Cancels and nulls-out the "current" and "pending" requests if they exist.
-   * 
+   *
    * @param aNonvisibleAction An action to take if the image is no longer
    *                          visible as a result; see |UntrackImage|.
    */
   void ClearCurrentRequest(nsresult aReason,
                            const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
   void ClearPendingRequest(nsresult aReason,
                            const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
 
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -281,16 +281,20 @@ NON_IDL_EVENT(mozaccesskeynotfound,
 EVENT(loadeddata,
       eLoadedData,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(loadedmetadata,
       eLoadedMetaData,
       EventNameType_HTML,
       eBasicEventClass)
+EVENT(loadend,
+      eLoadEnd,
+      EventNameType_HTML,
+      eBasicEventClass)
 EVENT(loadstart,
       eLoadStart,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mousedown,
       eMouseDown,
       EventNameType_All,
       eMouseEventClass)
@@ -700,26 +704,26 @@ NON_IDL_EVENT(DOMActivate,
 NON_IDL_EVENT(DOMFocusIn,
               eLegacyDOMFocusIn,
               EventNameType_HTMLXUL,
               eUIEventClass)
 NON_IDL_EVENT(DOMFocusOut,
               eLegacyDOMFocusOut,
               EventNameType_HTMLXUL,
               eUIEventClass)
-                                  
+
 NON_IDL_EVENT(DOMMouseScroll,
               eLegacyMouseLineOrPageScroll,
               EventNameType_HTMLXUL,
               eMouseScrollEventClass)
 NON_IDL_EVENT(MozMousePixelScroll,
               eLegacyMousePixelScroll,
               EventNameType_HTMLXUL,
               eMouseScrollEventClass)
-                                                
+
 NON_IDL_EVENT(open,
               eOpen,
               EventNameType_None,
               eBasicEventClass)
 
 NON_IDL_EVENT(dataavailable,
               eMediaRecorderDataAvailable,
               EventNameType_None,
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -55,16 +55,17 @@ interface GlobalEventHandlers {
            attribute EventHandler oninput;
            attribute EventHandler oninvalid;
            attribute EventHandler onkeydown;
            attribute EventHandler onkeypress;
            attribute EventHandler onkeyup;
            attribute EventHandler onload;
            attribute EventHandler onloadeddata;
            attribute EventHandler onloadedmetadata;
+           attribute EventHandler onloadend;
            attribute EventHandler onloadstart;
            attribute EventHandler onmousedown;
   [LenientThis] attribute EventHandler onmouseenter;
   [LenientThis] attribute EventHandler onmouseleave;
            attribute EventHandler onmousemove;
            attribute EventHandler onmouseout;
            attribute EventHandler onmouseover;
            attribute EventHandler onmouseup;
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -108,21 +108,22 @@ NS_EVENT_MESSAGE_FIRST_LAST(ePointerEven
 
 NS_EVENT_MESSAGE(eContextMenu)
 
 NS_EVENT_MESSAGE(eLoad)
 NS_EVENT_MESSAGE(eUnload)
 NS_EVENT_MESSAGE(eHashChange)
 NS_EVENT_MESSAGE(eImageAbort)
 NS_EVENT_MESSAGE(eLoadError)
+NS_EVENT_MESSAGE(eLoadEnd)
 NS_EVENT_MESSAGE(ePopState)
 NS_EVENT_MESSAGE(eStorage)
 NS_EVENT_MESSAGE(eBeforeUnload)
 NS_EVENT_MESSAGE(eReadyStateChange)
- 
+
 NS_EVENT_MESSAGE(eFormSubmit)
 NS_EVENT_MESSAGE(eFormReset)
 NS_EVENT_MESSAGE(eFormChange)
 NS_EVENT_MESSAGE(eFormSelect)
 NS_EVENT_MESSAGE(eFormInvalid)
 
 //Need separate focus/blur notifications for non-native widgets
 NS_EVENT_MESSAGE(eFocus)
@@ -159,17 +160,17 @@ NS_EVENT_MESSAGE(eLegacyNodeRemoved)
 NS_EVENT_MESSAGE(eLegacyNodeRemovedFromDocument)
 NS_EVENT_MESSAGE(eLegacyNodeInsertedIntoDocument)
 NS_EVENT_MESSAGE(eLegacyAttrModified)
 NS_EVENT_MESSAGE(eLegacyCharacterDataModified)
 NS_EVENT_MESSAGE_FIRST_LAST(eLegacyMutationEvent,
   eLegacySubtreeModified, eLegacyCharacterDataModified)
 
 NS_EVENT_MESSAGE(eUnidentifiedEvent)
- 
+
 // composition events
 NS_EVENT_MESSAGE(eCompositionStart)
 // eCompositionEnd is the message for DOM compositionend event.
 // This event should NOT be dispatched from widget if eCompositionCommit
 // is available.
 NS_EVENT_MESSAGE(eCompositionEnd)
 // eCompositionUpdate is the message for DOM compositionupdate event.
 // This event should NOT be dispatched from widget since it will be dispatched