Bug 1466707 - Ensure that animated images always honour the animated image mode. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 12 Oct 2018 14:25:49 -0400
changeset 489765 81cff62bc428d4fc54c81d0445b69ad554b31cda
parent 489764 180eb0ea89bcf02d511d4e05f493583d125177ea
child 489766 5f197a31d28fb2524167a8cb92c45b2d7a64ea8a
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerstnikkel
bugs1466707
milestone64.0a1
Bug 1466707 - Ensure that animated images always honour the animated image mode. r=tnikkel Animated images inside of SVGs and used in XUL frames did not get the configured animation image mode from the pres context. Differential Revision: https://phabricator.services.mozilla.com/D8586
dom/svg/SVGFEImageElement.cpp
dom/svg/SVGFEImageElement.h
layout/svg/nsSVGImageFrame.cpp
layout/xul/nsImageBoxFrame.cpp
layout/xul/tree/nsTreeImageListener.cpp
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -46,16 +46,17 @@ nsSVGElement::StringInfo SVGFEImageEleme
 NS_IMPL_ISUPPORTS_INHERITED(SVGFEImageElement, SVGFEImageElementBase,
                             imgINotificationObserver, nsIImageLoadingContent)
 
 //----------------------------------------------------------------------
 // Implementation
 
 SVGFEImageElement::SVGFEImageElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
   : SVGFEImageElementBase(std::move(aNodeInfo))
+  , mImageAnimationMode(0)
 {
   // We start out broken
   AddStatesSilently(NS_EVENT_STATE_BROKEN);
 }
 
 SVGFEImageElement::~SVGFEImageElement()
 {
   DestroyImageLoadingContent();
@@ -334,29 +335,61 @@ SVGFEImageElement::GetPreserveAspectRati
 nsSVGElement::StringAttributesInfo
 SVGFEImageElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               ArrayLength(sStringInfo));
 }
 
 //----------------------------------------------------------------------
+// nsIImageLoadingContent methods
+NS_IMETHODIMP_(void)
+SVGFEImageElement::FrameCreated(nsIFrame* aFrame)
+{
+  nsImageLoadingContent::FrameCreated(aFrame);
+
+  uint64_t mode = aFrame->PresContext()->ImageAnimationMode();
+  if (mode == mImageAnimationMode) {
+    return;
+  }
+
+  mImageAnimationMode = mode;
+
+  if (mPendingRequest) {
+    nsCOMPtr<imgIContainer> container;
+    mPendingRequest->GetImage(getter_AddRefs(container));
+    if (container) {
+      container->SetAnimationMode(mode);
+    }
+  }
+
+  if (mCurrentRequest) {
+    nsCOMPtr<imgIContainer> container;
+    mCurrentRequest->GetImage(getter_AddRefs(container));
+    if (container) {
+      container->SetAnimationMode(mode);
+    }
+  }
+}
+
+//----------------------------------------------------------------------
 // imgINotificationObserver methods
 
 NS_IMETHODIMP
 SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
   nsresult rv = nsImageLoadingContent::Notify(aRequest, aType, aData);
 
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Request a decode
     nsCOMPtr<imgIContainer> container;
     aRequest->GetImage(getter_AddRefs(container));
     MOZ_ASSERT(container, "who sent the notification then?");
     container->StartDecoding(imgIContainer::FLAG_NONE);
+    container->SetAnimationMode(mImageAnimationMode);
   }
 
   if (aType == imgINotificationObserver::LOAD_COMPLETE ||
       aType == imgINotificationObserver::FRAME_UPDATE ||
       aType == imgINotificationObserver::SIZE_AVAILABLE) {
     if (GetParent() && GetParent()->IsSVGElement(nsGkAtoms::filter)) {
       SVGObserverUtils::InvalidateDirectRenderingObservers(
         static_cast<SVGFilterElement*>(GetParent()));
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -64,16 +64,19 @@ public:
                                 bool aNotify) override;
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
   virtual EventStates IntrinsicState() const override;
 
   NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) override;
 
+  // Override for nsIImageLoadingContent.
+  NS_IMETHOD_(void) FrameCreated(nsIFrame* aFrame) override;
+
   void MaybeLoadSVGImage();
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> Href();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
 
 private:
   nsresult LoadSVGImage(bool aForce, bool aNotify);
@@ -87,14 +90,15 @@ protected:
   // Override for nsImageLoadingContent.
   nsIContent* AsContent() override { return this; }
 
   enum { RESULT, HREF, XLINK_HREF };
   nsSVGString mStringAttributes[3];
   static StringInfo sStringInfo[3];
 
   SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
+  uint16_t mImageAnimationMode;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -564,17 +564,22 @@ nsSVGImageListener::Notify(imgIRequest *
     nsLayoutUtils::PostRestyleEvent(
       mFrame->GetContent()->AsElement(), nsRestyleHint(0),
       nsChangeHint_InvalidateRenderingObservers);
     mFrame->InvalidateFrame();
   }
 
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Called once the resource's dimensions have been obtained.
-    aRequest->GetImage(getter_AddRefs(mFrame->mImageContainer));
+    nsCOMPtr<imgIContainer> image;
+    aRequest->GetImage(getter_AddRefs(image));
+    if (image) {
+      image->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
+      mFrame->mImageContainer = image.forget();
+    }
     mFrame->InvalidateFrame();
     nsLayoutUtils::PostRestyleEvent(
       mFrame->GetContent()->AsElement(), nsRestyleHint(0),
       nsChangeHint_InvalidateRenderingObservers);
     nsSVGUtils::ScheduleReflowSVG(mFrame);
   }
 
   return NS_OK;
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -846,16 +846,18 @@ nsImageBoxFrame::OnSizeAvailable(imgIReq
 {
   NS_ENSURE_ARG_POINTER(aImage);
 
   // Ensure the animation (if any) is started. Note: There is no
   // corresponding call to Decrement for this. This Increment will be
   // 'cleaned up' by the Request when it is destroyed, but only then.
   aRequest->IncrementAnimationConsumers();
 
+  aImage->SetAnimationMode(PresContext()->ImageAnimationMode());
+
   nscoord w, h;
   aImage->GetWidth(&w);
   aImage->GetHeight(&h);
 
   mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w),
                         nsPresContext::CSSPixelsToAppUnits(h));
 
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
--- a/layout/xul/tree/nsTreeImageListener.cpp
+++ b/layout/xul/tree/nsTreeImageListener.cpp
@@ -32,16 +32,25 @@ nsTreeImageListener::Notify(imgIRequest 
     return mTreeFrame ? mTreeFrame->OnImageIsAnimated(aRequest) : NS_OK;
   }
 
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Ensure the animation (if any) is started. Note: There is no
     // corresponding call to Decrement for this. This Increment will be
     // 'cleaned up' by the Request when it is destroyed, but only then.
     aRequest->IncrementAnimationConsumers();
+
+    if (mTreeFrame) {
+      nsCOMPtr<imgIContainer> image;
+      aRequest->GetImage(getter_AddRefs(image));
+      if (image) {
+        nsPresContext* presContext = mTreeFrame->PresContext();
+        image->SetAnimationMode(presContext->ImageAnimationMode());
+      }
+    }
   }
 
   if (aType == imgINotificationObserver::FRAME_UPDATE) {
     Invalidate();
   }
 
   return NS_OK;
 }