Bug 1366875. Apply the same sync decoding heuristic to SVG <image> as we do to HTML <img>. r=mats

--HG--
rename : layout/svg/nsSVGImageFrame.cpp => layout/svg/nsSVGImageFrame.h
This commit is contained in:
Timothy Nikkel 2017-05-23 14:11:13 -05:00
parent 226f6b9185
commit c8ba76db41
4 changed files with 156 additions and 96 deletions

View File

@ -26,6 +26,7 @@
#include "nsThreadUtils.h"
#include "nsNetUtil.h"
#include "nsImageFrame.h"
#include "nsSVGImageFrame.h"
#include "nsIPresShell.h"
@ -1180,8 +1181,9 @@ nsImageLoadingContent::CancelPendingEvent()
RefPtr<imgRequestProxy>&
nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
{
nsImageFrame* frame = do_QueryFrame(GetOurPrimaryFrame());
if (frame) {
nsImageFrame* imageFrame = do_QueryFrame(GetOurPrimaryFrame());
nsSVGImageFrame* svgImageFrame = do_QueryFrame(GetOurPrimaryFrame());
if (imageFrame || svgImageFrame) {
// Detect JavaScript-based animations created by changing the |src|
// attribute on a timer.
TimeStamp now = TimeStamp::Now();
@ -1191,7 +1193,12 @@ nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
// If the length of time between request changes is less than the threshold,
// then force sync decoding to eliminate flicker from the animation.
frame->SetForceSyncDecoding(now - mMostRecentRequestChange < threshold);
bool forceSync = (now - mMostRecentRequestChange < threshold);
if (imageFrame) {
imageFrame->SetForceSyncDecoding(forceSync);
} else {
svgImageFrame->SetForceSyncDecoding(forceSync);
}
mMostRecentRequestChange = now;
}

View File

@ -20,6 +20,7 @@ EXPORTS += [
'nsSVGEffects.h',
'nsSVGFilterInstance.h',
'nsSVGForeignObjectFrame.h',
'nsSVGImageFrame.h',
'nsSVGIntegrationUtils.h',
'nsSVGUtils.h',
'SVGImageContext.h',

View File

@ -3,6 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGImageFrame.h"
// Keep in (case-insensitive) order:
#include "gfxContext.h"
#include "gfxPlatform.h"
@ -29,97 +31,11 @@ using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::image;
class nsSVGImageFrame;
class nsSVGImageListener final : public imgINotificationObserver
{
public:
explicit nsSVGImageListener(nsSVGImageFrame *aFrame);
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
private:
~nsSVGImageListener() {}
nsSVGImageFrame *mFrame;
};
class nsSVGImageFrame final
: public SVGGeometryFrame
, public nsIReflowCallback
{
friend nsIFrame*
NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
protected:
explicit nsSVGImageFrame(nsStyleContext* aContext)
: SVGGeometryFrame(aContext, LayoutFrameType::SVGImage)
, mReflowCallbackPosted(false)
{
EnableVisibilityTracking();
}
virtual ~nsSVGImageFrame();
public:
NS_DECL_FRAMEARENA_HELPERS
// nsSVGDisplayableFrame interface:
virtual void PaintSVG(gfxContext& aContext,
const gfxMatrix& aTransform,
imgDrawingParams& aImgParams,
const nsIntRect* aDirtyRect = nullptr) override;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
virtual void ReflowSVG() override;
// SVGGeometryFrame methods:
virtual uint16_t GetHitTestFlags() override;
// nsIFrame interface:
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType) override;
void OnVisibilityChange(Visibility aNewVisibility,
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;
virtual void Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override
{
return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
}
#endif
// nsIReflowCallback
virtual bool ReflowFinished() override;
virtual void ReflowCallbackCanceled() override;
private:
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
int32_t aNativeHeight);
gfx::Matrix GetVectorImageTransform();
bool TransformContextForPainting(gfxContext* aGfxContext,
const gfxMatrix& aTransform);
nsCOMPtr<imgINotificationObserver> mListener;
nsCOMPtr<imgIContainer> mImageContainer;
bool mReflowCallbackPosted;
friend class nsSVGImageListener;
};
//----------------------------------------------------------------------
// Implementation
// ---------------------------------------------------------------------
// nsQueryFrame methods
NS_QUERYFRAME_HEAD(nsSVGImageFrame)
NS_QUERYFRAME_ENTRY(nsSVGImageFrame)
NS_QUERYFRAME_TAIL_INHERITING(SVGGeometryFrame)
nsIFrame*
NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
@ -397,6 +313,11 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext,
dirtyRect.MoveBy(-rootRect.TopLeft());
}
uint32_t flags = aImgParams.imageFlags;
if (mForceSyncDecoding) {
flags |= imgIContainer::FLAG_SYNC_DECODE;
}
if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
// Package up the attributes of this image element which can override the
// attributes of mImageContainer's internal SVG document. The 'width' &
@ -426,7 +347,7 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext,
destRect,
aDirtyRect ? dirtyRect : destRect,
context,
aImgParams.imageFlags);
flags);
} else { // mImageContainer->GetType() == TYPE_RASTER
aImgParams.result &= nsLayoutUtils::DrawSingleUnscaledImage(
aContext,
@ -435,7 +356,7 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext,
nsLayoutUtils::GetSamplingFilterForFrame(this),
nsPoint(0, 0),
aDirtyRect ? &dirtyRect : nullptr,
aImgParams.imageFlags);
flags);
}
if (opacity != 1.0f || StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {

View File

@ -0,0 +1,131 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __NS_SVGIMAGEFRAME_H__
#define __NS_SVGIMAGEFRAME_H__
// Keep in (case-insensitive) order:
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "imgIContainer.h"
#include "nsContainerFrame.h"
#include "nsIDOMMutationEvent.h"
#include "nsIImageLoadingContent.h"
#include "nsLayoutUtils.h"
#include "imgINotificationObserver.h"
#include "nsSVGEffects.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "nsSVGUtils.h"
#include "SVGContentUtils.h"
#include "SVGGeometryFrame.h"
#include "SVGImageContext.h"
#include "mozilla/dom/SVGImageElement.h"
#include "nsContentUtils.h"
#include "nsIReflowCallback.h"
#include "mozilla/Unused.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::image;
class nsSVGImageFrame;
class nsSVGImageListener final : public imgINotificationObserver
{
public:
explicit nsSVGImageListener(nsSVGImageFrame *aFrame);
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
private:
~nsSVGImageListener() {}
nsSVGImageFrame *mFrame;
};
class nsSVGImageFrame final
: public SVGGeometryFrame
, public nsIReflowCallback
{
friend nsIFrame*
NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
protected:
explicit nsSVGImageFrame(nsStyleContext* aContext)
: SVGGeometryFrame(aContext, LayoutFrameType::SVGImage)
, mReflowCallbackPosted(false)
, mForceSyncDecoding(false)
{
EnableVisibilityTracking();
}
virtual ~nsSVGImageFrame();
public:
NS_DECL_QUERYFRAME_TARGET(nsSVGImageFrame)
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS
// nsSVGDisplayableFrame interface:
virtual void PaintSVG(gfxContext& aContext,
const gfxMatrix& aTransform,
imgDrawingParams& aImgParams,
const nsIntRect* aDirtyRect = nullptr) override;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
virtual void ReflowSVG() override;
// SVGGeometryFrame methods:
virtual uint16_t GetHitTestFlags() override;
// nsIFrame interface:
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType) override;
void OnVisibilityChange(Visibility aNewVisibility,
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;
virtual void Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override
{
return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult);
}
#endif
// nsIReflowCallback
virtual bool ReflowFinished() override;
virtual void ReflowCallbackCanceled() override;
/// Always sync decode our image when painting if @aForce is true.
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
private:
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
int32_t aNativeHeight);
gfx::Matrix GetVectorImageTransform();
bool TransformContextForPainting(gfxContext* aGfxContext,
const gfxMatrix& aTransform);
nsCOMPtr<imgINotificationObserver> mListener;
nsCOMPtr<imgIContainer> mImageContainer;
bool mReflowCallbackPosted;
bool mForceSyncDecoding;
friend class nsSVGImageListener;
};
#endif // __NS_SVGIMAGEFRAME_H__