2010-09-08 13:40:39 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* 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/. */
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
#include "VectorImage.h"
|
2011-10-15 00:33:26 -07:00
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
#include "imgIDecoderObserver.h"
|
|
|
|
#include "SVGDocumentWrapper.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxPlatform.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsRect.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIStreamListener.h"
|
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsSVGUtils.h" // for nsSVGUtils::ConvertToSurfaceSize
|
|
|
|
#include "nsSVGEffects.h" // for nsSVGRenderingObserver
|
|
|
|
#include "gfxDrawable.h"
|
|
|
|
#include "gfxUtils.h"
|
2010-09-08 13:40:40 -07:00
|
|
|
#include "nsSVGSVGElement.h"
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
namespace mozilla {
|
2011-10-15 00:33:26 -07:00
|
|
|
|
|
|
|
using namespace dom;
|
|
|
|
|
2012-01-06 08:02:27 -08:00
|
|
|
namespace image {
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2010-09-08 13:40:40 -07:00
|
|
|
// Helper-class: SVGRootRenderingObserver
|
|
|
|
class SVGRootRenderingObserver : public nsSVGRenderingObserver {
|
|
|
|
public:
|
|
|
|
SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
|
|
|
|
VectorImage* aVectorImage)
|
|
|
|
: nsSVGRenderingObserver(),
|
|
|
|
mDocWrapper(aDocWrapper),
|
|
|
|
mVectorImage(aVectorImage)
|
|
|
|
{
|
|
|
|
StartListening();
|
|
|
|
Element* elem = GetTarget();
|
|
|
|
if (elem) {
|
|
|
|
nsSVGEffects::AddRenderingObserver(elem, this);
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = true;
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
2010-09-13 14:06:53 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
else {
|
|
|
|
NS_ABORT_IF_FALSE(!mInObserverList,
|
|
|
|
"Have no target, so we can't be in "
|
|
|
|
"target's observer list...");
|
|
|
|
}
|
|
|
|
#endif
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~SVGRootRenderingObserver()
|
|
|
|
{
|
|
|
|
StopListening();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Element* GetTarget()
|
|
|
|
{
|
|
|
|
return mDocWrapper->GetRootSVGElem();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void DoUpdate()
|
|
|
|
{
|
|
|
|
Element* elem = GetTarget();
|
|
|
|
if (!elem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!mDocWrapper->ShouldIgnoreInvalidation()) {
|
|
|
|
nsIFrame* frame = elem->GetPrimaryFrame();
|
|
|
|
if (!frame || frame->PresContext()->PresShell()->IsDestroying()) {
|
|
|
|
// We're being destroyed. Bail out.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mVectorImage->InvalidateObserver();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Our caller might've removed us from rendering-observer list.
|
|
|
|
// Add ourselves back!
|
|
|
|
if (!mInObserverList) {
|
|
|
|
nsSVGEffects::AddRenderingObserver(elem, this);
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = true;
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Private data
|
|
|
|
nsRefPtr<SVGDocumentWrapper> mDocWrapper;
|
|
|
|
VectorImage* mVectorImage; // Raw pointer because it owns me.
|
|
|
|
};
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
// Helper-class: SVGDrawingCallback
|
|
|
|
class SVGDrawingCallback : public gfxDrawingCallback {
|
|
|
|
public:
|
|
|
|
SVGDrawingCallback(SVGDocumentWrapper* aSVGDocumentWrapper,
|
|
|
|
const nsIntRect& aViewport,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aImageFlags) :
|
2010-09-08 13:40:39 -07:00
|
|
|
mSVGDocumentWrapper(aSVGDocumentWrapper),
|
|
|
|
mViewport(aViewport),
|
|
|
|
mImageFlags(aImageFlags)
|
|
|
|
{}
|
2011-09-28 23:19:26 -07:00
|
|
|
virtual bool operator()(gfxContext* aContext,
|
2010-09-08 13:40:39 -07:00
|
|
|
const gfxRect& aFillRect,
|
|
|
|
const gfxPattern::GraphicsFilter& aFilter,
|
|
|
|
const gfxMatrix& aTransform);
|
|
|
|
private:
|
|
|
|
nsRefPtr<SVGDocumentWrapper> mSVGDocumentWrapper;
|
|
|
|
const nsIntRect mViewport;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t mImageFlags;
|
2010-09-08 13:40:39 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// Based loosely on nsSVGIntegrationUtils' PaintFrameCallback::operator()
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-09-08 13:40:39 -07:00
|
|
|
SVGDrawingCallback::operator()(gfxContext* aContext,
|
|
|
|
const gfxRect& aFillRect,
|
|
|
|
const gfxPattern::GraphicsFilter& aFilter,
|
|
|
|
const gfxMatrix& aTransform)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mSVGDocumentWrapper, "need an SVGDocumentWrapper");
|
|
|
|
|
|
|
|
// Get (& sanity-check) the helper-doc's presShell
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
if (NS_FAILED(mSVGDocumentWrapper->GetPresShell(getter_AddRefs(presShell)))) {
|
|
|
|
NS_WARNING("Unable to draw -- presShell lookup failed");
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
NS_ABORT_IF_FALSE(presShell, "GetPresShell succeeded but returned null");
|
|
|
|
|
2011-01-24 10:32:34 -08:00
|
|
|
gfxContextAutoSaveRestore contextRestorer(aContext);
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
// Clip to aFillRect so that we don't paint outside.
|
|
|
|
aContext->NewPath();
|
|
|
|
aContext->Rectangle(aFillRect);
|
|
|
|
aContext->Clip();
|
|
|
|
|
2011-01-24 10:32:34 -08:00
|
|
|
gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
|
2010-09-08 13:40:39 -07:00
|
|
|
aContext->Multiply(gfxMatrix(aTransform).Invert());
|
|
|
|
|
|
|
|
nsPresContext* presContext = presShell->GetPresContext();
|
|
|
|
NS_ABORT_IF_FALSE(presContext, "pres shell w/out pres context");
|
|
|
|
|
|
|
|
nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
|
|
|
|
presContext->DevPixelsToAppUnits(mViewport.y),
|
|
|
|
presContext->DevPixelsToAppUnits(mViewport.width),
|
|
|
|
presContext->DevPixelsToAppUnits(mViewport.height));
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
|
2010-09-08 13:40:39 -07:00
|
|
|
if (!(mImageFlags & imgIContainer::FLAG_SYNC_DECODE)) {
|
|
|
|
renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES;
|
|
|
|
}
|
|
|
|
|
|
|
|
presShell->RenderDocument(svgRect, renderDocFlags,
|
|
|
|
NS_RGBA(0, 0, 0, 0), // transparent
|
|
|
|
aContext);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Implement VectorImage's nsISupports-inherited methods
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMPL_ISUPPORTS3(VectorImage,
|
|
|
|
imgIContainer,
|
|
|
|
nsIStreamListener,
|
|
|
|
nsIRequestObserver)
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Constructor / Destructor
|
|
|
|
|
|
|
|
VectorImage::VectorImage(imgStatusTracker* aStatusTracker) :
|
2010-09-08 13:40:39 -07:00
|
|
|
Image(aStatusTracker), // invoke superclass's constructor
|
|
|
|
mRestrictedRegion(0, 0, 0, 0),
|
|
|
|
mLastRenderedSize(0, 0),
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsInitialized(false),
|
|
|
|
mIsFullyLoaded(false),
|
|
|
|
mIsDrawing(false),
|
|
|
|
mHaveAnimations(false),
|
|
|
|
mHaveRestrictedRegion(false)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorImage::~VectorImage()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Methods inherited from Image.h
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
VectorImage::Init(imgIDecoderObserver* aObserver,
|
|
|
|
const char* aMimeType,
|
2010-09-12 08:22:26 -07:00
|
|
|
const char* aURIString,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
// We don't support re-initialization
|
|
|
|
if (mIsInitialized)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations &&
|
|
|
|
!mHaveRestrictedRegion && !mError,
|
|
|
|
"Flags unexpectedly set before initialization");
|
|
|
|
|
|
|
|
mObserver = do_GetWeakReference(aObserver);
|
|
|
|
NS_ABORT_IF_FALSE(!strcmp(aMimeType, SVG_MIMETYPE), "Unexpected mimetype");
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsInitialized = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VectorImage::GetCurrentFrameRect(nsIntRect& aRect)
|
|
|
|
{
|
2010-09-09 09:41:58 -07:00
|
|
|
aRect = nsIntRect::GetMaxSizedIntRect();
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
VectorImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2012-02-19 19:51:48 -08:00
|
|
|
// We're not storing the source data -- we just feed that directly to
|
|
|
|
// our helper SVG document as we receive it, for it to parse.
|
|
|
|
// So 0 is an appropriate return value here.
|
|
|
|
return 0;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
VectorImage::HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const
|
2011-07-18 06:20:27 -07:00
|
|
|
{
|
2012-02-19 19:51:48 -08:00
|
|
|
// XXXdholbert TODO: return num bytes used by helper SVG doc. (bug 590790)
|
2011-07-18 06:20:27 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
VectorImage::NonHeapSizeOfDecoded() const
|
2011-07-18 06:20:27 -07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-19 19:51:48 -08:00
|
|
|
size_t
|
|
|
|
VectorImage::OutOfProcessSizeOfDecoded() const
|
2010-10-06 08:37:12 -07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
nsresult
|
|
|
|
VectorImage::StartAnimation()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-11-17 12:39:23 -08:00
|
|
|
NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
mSVGDocumentWrapper->StartAnimation();
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
VectorImage::StopAnimation()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-11-17 12:39:23 -08:00
|
|
|
NS_ABORT_IF_FALSE(mIsFullyLoaded && mHaveAnimations,
|
|
|
|
"Should not have been animating!");
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
mSVGDocumentWrapper->StopAnimation();
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2011-08-05 06:57:16 -07:00
|
|
|
bool
|
2010-11-17 12:39:23 -08:00
|
|
|
VectorImage::ShouldAnimate()
|
|
|
|
{
|
|
|
|
return Image::ShouldAnimate() && mIsFullyLoaded && mHaveAnimations;
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// imgIContainer methods
|
|
|
|
|
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* readonly attribute int32_t width; */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::GetWidth(int32_t* aWidth)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError || !mIsFullyLoaded) {
|
2010-10-06 15:18:52 -07:00
|
|
|
*aWidth = 0;
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
|
|
|
|
*aWidth)) {
|
2010-10-06 15:18:52 -07:00
|
|
|
*aWidth = 0;
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2011-11-09 13:39:15 -08:00
|
|
|
//******************************************************************************
|
|
|
|
/* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
|
|
|
|
NS_IMETHODIMP_(void)
|
|
|
|
VectorImage::RequestRefresh(const mozilla::TimeStamp& aTime)
|
|
|
|
{
|
|
|
|
// TODO: Implement for b666446.
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* readonly attribute int32_t height; */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::GetHeight(int32_t* aHeight)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError || !mIsFullyLoaded) {
|
2010-10-06 15:18:52 -07:00
|
|
|
*aHeight = 0;
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2010-09-08 15:56:15 -07:00
|
|
|
if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
|
|
|
|
*aHeight)) {
|
2010-10-06 15:18:52 -07:00
|
|
|
*aHeight = 0;
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* readonly attribute unsigned short type; */
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::GetType(uint16_t* aType)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-12-07 10:40:28 -08:00
|
|
|
NS_ENSURE_ARG_POINTER(aType);
|
|
|
|
|
|
|
|
*aType = GetType();
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-12-07 10:40:28 -08:00
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* [noscript, notxpcom] uint16_t GetType(); */
|
|
|
|
NS_IMETHODIMP_(uint16_t)
|
2010-12-07 10:40:28 -08:00
|
|
|
VectorImage::GetType()
|
|
|
|
{
|
|
|
|
return imgIContainer::TYPE_VECTOR;
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* readonly attribute boolean animated; */
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
VectorImage::GetAnimated(bool* aAnimated)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError || !mIsFullyLoaded)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*aAnimated = mSVGDocumentWrapper->IsAnimated();
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* readonly attribute boolean currentFrameIsOpaque; */
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
VectorImage::GetCurrentFrameIsOpaque(bool* aIsOpaque)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aIsOpaque);
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsOpaque = false; // In general, SVG content is not opaque.
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* [noscript] gfxASurface getFrame(in uint32_t aWhichFrame,
|
|
|
|
* in uint32_t aFlags; */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::GetFrame(uint32_t aWhichFrame,
|
|
|
|
uint32_t aFlags,
|
2010-09-08 13:40:39 -07:00
|
|
|
gfxASurface** _retval)
|
|
|
|
{
|
2010-10-12 12:00:30 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
nsRefPtr<gfxImageSurface> surface;
|
|
|
|
nsresult rv = CopyFrame(aWhichFrame, aFlags, getter_AddRefs(surface));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
*_retval = surface.forget().get();
|
|
|
|
}
|
|
|
|
return rv;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* [noscript] gfxImageSurface copyFrame(in uint32_t aWhichFrame,
|
|
|
|
* in uint32_t aFlags); */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::CopyFrame(uint32_t aWhichFrame,
|
|
|
|
uint32_t aFlags,
|
2010-09-08 13:40:39 -07:00
|
|
|
gfxImageSurface** _retval)
|
|
|
|
{
|
2010-10-12 12:00:30 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
// XXXdholbert NOTE: Currently assuming FRAME_CURRENT for simplicity.
|
|
|
|
// Could handle FRAME_FIRST by saving helper-doc current time, seeking
|
|
|
|
// to time 0, rendering, and then seeking to saved time.
|
2010-09-08 13:40:39 -07:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE)
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
|
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-10-12 12:00:30 -07:00
|
|
|
// Look up height & width
|
|
|
|
// ----------------------
|
|
|
|
nsIntSize imageIntSize;
|
|
|
|
if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
|
|
|
|
imageIntSize.width) ||
|
|
|
|
!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
|
|
|
|
imageIntSize.height)) {
|
|
|
|
// We'll get here if our SVG doc has a percent-valued width or height.
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a surface that we'll ultimately return
|
|
|
|
// ---------------------------------------------
|
|
|
|
// Make our surface the size of what will ultimately be drawn to it.
|
|
|
|
// (either the full image size, or the restricted region)
|
|
|
|
gfxIntSize surfaceSize;
|
|
|
|
if (mHaveRestrictedRegion) {
|
|
|
|
surfaceSize.width = mRestrictedRegion.width;
|
|
|
|
surfaceSize.height = mRestrictedRegion.height;
|
|
|
|
} else {
|
|
|
|
surfaceSize.width = imageIntSize.width;
|
|
|
|
surfaceSize.height = imageIntSize.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<gfxImageSurface> surface =
|
|
|
|
new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
|
|
|
|
nsRefPtr<gfxContext> context = new gfxContext(surface);
|
|
|
|
|
|
|
|
// Draw to our surface!
|
|
|
|
// --------------------
|
|
|
|
nsresult rv = Draw(context, gfxPattern::FILTER_NEAREST, gfxMatrix(),
|
|
|
|
gfxRect(gfxPoint(0,0), gfxIntSize(imageIntSize.width,
|
|
|
|
imageIntSize.height)),
|
|
|
|
nsIntRect(nsIntPoint(0,0), imageIntSize),
|
|
|
|
imageIntSize, aFlags);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
*_retval = surface.forget().get();
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2012-08-22 08:56:38 -07:00
|
|
|
/* [noscript] imgIContainer extractFrame(uint32_t aWhichFrame,
|
2010-09-08 13:40:39 -07:00
|
|
|
* [const] in nsIntRect aRegion,
|
2012-08-22 08:56:38 -07:00
|
|
|
* in uint32_t aFlags); */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
VectorImage::ExtractFrame(uint32_t aWhichFrame,
|
2010-09-08 13:40:39 -07:00
|
|
|
const nsIntRect& aRegion,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags,
|
2010-09-08 13:40:39 -07:00
|
|
|
imgIContainer** _retval)
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
if (mError || !mIsFullyLoaded)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// XXXdholbert NOTE: This method assumes FRAME_CURRENT (not FRAME_FIRST)
|
|
|
|
// right now, because mozilla doesn't actually contain any clients of this
|
|
|
|
// method that use FRAME_FIRST. If it's needed, we *could* handle
|
|
|
|
// FRAME_FIRST by saving the helper-doc's current SMIL time, seeking it to
|
|
|
|
// time 0, rendering to a RasterImage, and then restoring our saved time.
|
|
|
|
if (aWhichFrame != FRAME_CURRENT) {
|
|
|
|
NS_WARNING("VectorImage::ExtractFrame with something other than "
|
|
|
|
"FRAME_CURRENT isn't supported yet. Assuming FRAME_CURRENT.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXXdholbert This method also doesn't actually freeze animation in the
|
|
|
|
// returned imgIContainer, because it shares our helper-document. To
|
|
|
|
// get a true snapshot, we need to clone the document - see bug 590792.
|
|
|
|
|
|
|
|
// Make a new container with same SVG document.
|
|
|
|
nsRefPtr<VectorImage> extractedImg = new VectorImage();
|
|
|
|
extractedImg->mSVGDocumentWrapper = mSVGDocumentWrapper;
|
|
|
|
extractedImg->mAnimationMode = kDontAnimMode;
|
|
|
|
|
|
|
|
extractedImg->mRestrictedRegion.x = aRegion.x;
|
|
|
|
extractedImg->mRestrictedRegion.y = aRegion.y;
|
|
|
|
|
|
|
|
// (disallow negative width/height on our restricted region)
|
|
|
|
extractedImg->mRestrictedRegion.width = NS_MAX(aRegion.width, 0);
|
|
|
|
extractedImg->mRestrictedRegion.height = NS_MAX(aRegion.height, 0);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
extractedImg->mIsInitialized = true;
|
|
|
|
extractedImg->mIsFullyLoaded = true;
|
|
|
|
extractedImg->mHaveRestrictedRegion = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
*_retval = extractedImg.forget().get();
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] void draw(in gfxContext aContext,
|
|
|
|
* in gfxGraphicsFilter aFilter,
|
|
|
|
* [const] in gfxMatrix aUserSpaceToImageSpace,
|
|
|
|
* [const] in gfxRect aFill,
|
|
|
|
* [const] in nsIntRect aSubimage,
|
|
|
|
* [const] in nsIntSize aViewportSize,
|
2012-08-22 08:56:38 -07:00
|
|
|
* in uint32_t aFlags); */
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::Draw(gfxContext* aContext,
|
|
|
|
gfxPattern::GraphicsFilter aFilter,
|
|
|
|
const gfxMatrix& aUserSpaceToImageSpace,
|
|
|
|
const gfxRect& aFill,
|
|
|
|
const nsIntRect& aSubimage,
|
|
|
|
const nsIntSize& aViewportSize,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2010-11-19 08:56:06 -08:00
|
|
|
NS_ENSURE_ARG_POINTER(aContext);
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError || !mIsFullyLoaded)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-11-19 08:56:06 -08:00
|
|
|
if (mIsDrawing) {
|
|
|
|
NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsDrawing = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
if (aViewportSize != mLastRenderedSize) {
|
|
|
|
mSVGDocumentWrapper->UpdateViewportBounds(aViewportSize);
|
|
|
|
mLastRenderedSize = aViewportSize;
|
|
|
|
}
|
2011-02-09 12:13:18 -08:00
|
|
|
mSVGDocumentWrapper->FlushImageTransformInvalidation();
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
nsIntSize imageSize = mHaveRestrictedRegion ?
|
|
|
|
mRestrictedRegion.Size() : aViewportSize;
|
|
|
|
|
|
|
|
// XXXdholbert Do we need to convert image size from
|
|
|
|
// CSS pixels to dev pixels here? (is gfxCallbackDrawable's 2nd arg in dev
|
|
|
|
// pixels?)
|
|
|
|
gfxIntSize imageSizeGfx(imageSize.width, imageSize.height);
|
|
|
|
|
|
|
|
// Based on imgFrame::Draw
|
|
|
|
gfxRect sourceRect = aUserSpaceToImageSpace.Transform(aFill);
|
|
|
|
gfxRect imageRect(0, 0, imageSize.width, imageSize.height);
|
|
|
|
gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
|
|
|
|
|
|
|
|
|
|
|
|
nsRefPtr<gfxDrawingCallback> cb =
|
|
|
|
new SVGDrawingCallback(mSVGDocumentWrapper,
|
|
|
|
mHaveRestrictedRegion ?
|
|
|
|
mRestrictedRegion :
|
|
|
|
nsIntRect(nsIntPoint(0, 0), aViewportSize),
|
|
|
|
aFlags);
|
|
|
|
|
|
|
|
nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, imageSizeGfx);
|
|
|
|
|
|
|
|
gfxUtils::DrawPixelSnapped(aContext, drawable,
|
|
|
|
aUserSpaceToImageSpace,
|
|
|
|
subimage, sourceRect, imageRect, aFill,
|
|
|
|
gfxASurface::ImageFormatARGB32, aFilter);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsDrawing = false;
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [notxpcom] nsIFrame GetRootLayoutFrame() */
|
|
|
|
nsIFrame*
|
|
|
|
VectorImage::GetRootLayoutFrame()
|
|
|
|
{
|
2011-05-22 19:22:13 -07:00
|
|
|
if (mError)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2011-05-22 19:22:13 -07:00
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
return mSVGDocumentWrapper->GetRootLayoutFrame();
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void requestDecode() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::RequestDecode()
|
|
|
|
{
|
|
|
|
// Nothing to do for SVG images
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-04 13:02:15 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::StartDecoding()
|
|
|
|
{
|
|
|
|
// Nothing to do for SVG images
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* void lockImage() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::LockImage()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
// This method is for image-discarding, which only applies to RasterImages.
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void unlockImage() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::UnlockImage()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
// This method is for image-discarding, which only applies to RasterImages.
|
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2012-03-09 22:29:28 -08:00
|
|
|
//******************************************************************************
|
|
|
|
/* void requestDiscard() */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::RequestDiscard()
|
|
|
|
{
|
|
|
|
// This method is for image-discarding, which only applies to RasterImages.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* void resetAnimation (); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::ResetAnimation()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (!mIsFullyLoaded || !mHaveAnimations) {
|
|
|
|
return NS_OK; // There are no animations to be reset.
|
|
|
|
}
|
|
|
|
|
|
|
|
mSVGDocumentWrapper->ResetAnimation();
|
2011-02-02 22:36:09 -08:00
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_OK;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// nsIRequestObserver methods
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStartRequest(in nsIRequest request, in nsISupports ctxt); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
NS_ABORT_IF_FALSE(!mSVGDocumentWrapper,
|
|
|
|
"Repeated call to OnStartRequest -- can this happen?");
|
|
|
|
|
|
|
|
mSVGDocumentWrapper = new SVGDocumentWrapper();
|
|
|
|
nsresult rv = mSVGDocumentWrapper->OnStartRequest(aRequest, aCtxt);
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-07-30 07:20:58 -07:00
|
|
|
mSVGDocumentWrapper = nullptr;
|
2011-10-17 07:59:28 -07:00
|
|
|
mError = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onStopRequest(in nsIRequest request, in nsISupports ctxt,
|
|
|
|
in nsresult status); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
|
|
|
|
nsresult aStatus)
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations,
|
|
|
|
"these flags shouldn't get set until OnStopRequest. "
|
|
|
|
"Duplicate calls to OnStopRequest?");
|
|
|
|
|
|
|
|
nsresult rv = mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus);
|
|
|
|
if (!mSVGDocumentWrapper->ParsedSuccessfully()) {
|
|
|
|
// XXXdholbert Need to do something more here -- right now, this just
|
|
|
|
// makes us draw the "object" icon, rather than the (jagged) "broken image"
|
|
|
|
// icon. See bug 594505.
|
2011-10-17 07:59:28 -07:00
|
|
|
mError = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsFullyLoaded = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
mHaveAnimations = mSVGDocumentWrapper->IsAnimated();
|
|
|
|
|
2010-09-08 13:40:40 -07:00
|
|
|
// Start listening to our image for rendering updates
|
|
|
|
mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this);
|
|
|
|
|
|
|
|
// Tell *our* observers that we're done loading
|
2010-09-08 13:40:39 -07:00
|
|
|
nsCOMPtr<imgIDecoderObserver> observer = do_QueryReferent(mObserver);
|
|
|
|
if (observer) {
|
|
|
|
// NOTE: This signals that width/height are available.
|
2012-10-11 18:58:24 -07:00
|
|
|
observer->OnStartContainer(nullptr, this);
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2012-10-11 18:58:24 -07:00
|
|
|
observer->FrameChanged(nullptr, this, &nsIntRect::GetMaxSizedIntRect());
|
|
|
|
observer->OnStopFrame(nullptr, 0);
|
2012-10-12 09:11:22 -07:00
|
|
|
observer->OnStopDecode(nullptr, NS_OK);
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
2010-12-19 16:45:29 -08:00
|
|
|
EvaluateAnimation();
|
2010-09-08 13:40:39 -07:00
|
|
|
|
|
|
|
return rv;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// nsIStreamListener method
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* void onDataAvailable(in nsIRequest request, in nsISupports ctxt,
|
|
|
|
in nsIInputStream inStr, in unsigned long sourceOffset,
|
|
|
|
in unsigned long count); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt,
|
2012-09-05 19:41:02 -07:00
|
|
|
nsIInputStream* aInStr, uint64_t aSourceOffset,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aCount)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2011-05-22 19:22:13 -07:00
|
|
|
if (mError)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
return mSVGDocumentWrapper->OnDataAvailable(aRequest, aCtxt, aInStr,
|
|
|
|
aSourceOffset, aCount);
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:40 -07:00
|
|
|
// --------------------------
|
|
|
|
// Invalidation helper method
|
|
|
|
|
|
|
|
void
|
|
|
|
VectorImage::InvalidateObserver()
|
|
|
|
{
|
2011-04-28 19:11:16 -07:00
|
|
|
if (!mObserver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<imgIContainerObserver> containerObs(do_QueryReferent(mObserver));
|
|
|
|
if (containerObs) {
|
2012-10-11 18:58:24 -07:00
|
|
|
containerObs->FrameChanged(nullptr, this, &nsIntRect::GetMaxSizedIntRect());
|
2011-04-28 19:11:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<imgIDecoderObserver> decoderObs(do_QueryReferent(mObserver));
|
|
|
|
if (decoderObs) {
|
2012-10-11 18:58:24 -07:00
|
|
|
decoderObs->OnStopFrame(nullptr, imgIContainer::FRAME_CURRENT);
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-06 08:02:27 -08:00
|
|
|
} // namespace image
|
2010-09-08 13:40:39 -07:00
|
|
|
} // namespace mozilla
|