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
--- 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;
}