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 499925 81cff62bc428d4fc54c81d0445b69ad554b31cda
parent 499924 180eb0ea89bcf02d511d4e05f493583d125177ea
child 499926 5f197a31d28fb2524167a8cb92c45b2d7a64ea8a
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1466707
milestone64.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 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;
 }