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
|
|
|
|
2012-12-18 08:37:15 -08:00
|
|
|
#include "imgDecoderObserver.h"
|
2010-09-08 13:40:39 -07:00
|
|
|
#include "SVGDocumentWrapper.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxPlatform.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsRect.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIStreamListener.h"
|
2013-01-08 13:40:47 -08:00
|
|
|
#include "nsMimeTypes.h"
|
2010-09-08 13:40:39 -07:00
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsSVGUtils.h" // for nsSVGUtils::ConvertToSurfaceSize
|
|
|
|
#include "nsSVGEffects.h" // for nsSVGRenderingObserver
|
|
|
|
#include "gfxDrawable.h"
|
|
|
|
#include "gfxUtils.h"
|
2013-02-28 22:44:57 -08:00
|
|
|
#include "mozilla/AutoRestore.h"
|
2013-01-09 15:02:45 -08:00
|
|
|
#include "mozilla/dom/SVGSVGElement.h"
|
2013-01-15 04:22:03 -08:00
|
|
|
#include <algorithm>
|
2010-09-08 13:40:40 -07:00
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
namespace mozilla {
|
2011-10-15 00:33:26 -07:00
|
|
|
|
|
|
|
using namespace dom;
|
2012-11-27 18:34:45 -08:00
|
|
|
using namespace layers;
|
2011-10-15 00:33:26 -07:00
|
|
|
|
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
|
2013-02-28 22:44:59 -08:00
|
|
|
class SVGRootRenderingObserver MOZ_FINAL : public nsSVGRenderingObserver {
|
2010-09-08 13:40:40 -07:00
|
|
|
public:
|
|
|
|
SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
|
|
|
|
VectorImage* aVectorImage)
|
|
|
|
: nsSVGRenderingObserver(),
|
|
|
|
mDocWrapper(aDocWrapper),
|
|
|
|
mVectorImage(aVectorImage)
|
|
|
|
{
|
2013-02-28 22:44:59 -08:00
|
|
|
MOZ_ASSERT(mDocWrapper, "Need a non-null SVG document wrapper");
|
|
|
|
MOZ_ASSERT(mVectorImage, "Need a non-null VectorImage");
|
|
|
|
|
2010-09-08 13:40:40 -07:00
|
|
|
StartListening();
|
|
|
|
Element* elem = GetTarget();
|
2013-02-28 22:44:59 -08:00
|
|
|
MOZ_ASSERT(elem, "no root SVG node for us to observe");
|
|
|
|
|
|
|
|
nsSVGEffects::AddRenderingObserver(elem, this);
|
|
|
|
mInObserverList = true;
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
|
|
|
|
2013-02-28 16:43:43 -08:00
|
|
|
void ResumeListening()
|
|
|
|
{
|
|
|
|
// GetReferencedElement adds us back to our target's observer list.
|
|
|
|
GetReferencedElement();
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:40 -07:00
|
|
|
virtual ~SVGRootRenderingObserver()
|
|
|
|
{
|
|
|
|
StopListening();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2013-02-28 22:44:59 -08:00
|
|
|
virtual Element* GetTarget() MOZ_OVERRIDE
|
2010-09-08 13:40:40 -07:00
|
|
|
{
|
|
|
|
return mDocWrapper->GetRootSVGElem();
|
|
|
|
}
|
|
|
|
|
2013-02-28 22:44:59 -08:00
|
|
|
virtual void DoUpdate() MOZ_OVERRIDE
|
2010-09-08 13:40:40 -07:00
|
|
|
{
|
|
|
|
Element* elem = GetTarget();
|
2013-02-28 22:44:59 -08:00
|
|
|
MOZ_ASSERT(elem, "missing root SVG node");
|
2010-09-08 13:40:40 -07:00
|
|
|
|
|
|
|
if (!mDocWrapper->ShouldIgnoreInvalidation()) {
|
|
|
|
nsIFrame* frame = elem->GetPrimaryFrame();
|
|
|
|
if (!frame || frame->PresContext()->PresShell()->IsDestroying()) {
|
|
|
|
// We're being destroyed. Bail out.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mVectorImage->InvalidateObserver();
|
|
|
|
}
|
|
|
|
|
2013-02-28 16:43:43 -08:00
|
|
|
// We may have been removed from the observer list by our caller. Rather
|
|
|
|
// than add ourselves back here, we wait until Draw gets called, ensuring
|
|
|
|
// that we coalesce invalidations between Draw calls.
|
2010-09-08 13:40:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Private data
|
2013-02-28 22:44:59 -08:00
|
|
|
const nsRefPtr<SVGDocumentWrapper> mDocWrapper;
|
|
|
|
VectorImage* const mVectorImage; // Raw pointer because it owns me.
|
2010-09-08 13:40:40 -07:00
|
|
|
};
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
class SVGParseCompleteListener MOZ_FINAL : public nsStubDocumentObserver {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
SVGParseCompleteListener(nsIDocument* aDocument,
|
|
|
|
VectorImage* aImage)
|
|
|
|
: mDocument(aDocument)
|
|
|
|
, mImage(aImage)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mDocument, "Need an SVG document");
|
|
|
|
NS_ABORT_IF_FALSE(mImage, "Need an image");
|
|
|
|
|
|
|
|
mDocument->AddObserver(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
~SVGParseCompleteListener()
|
|
|
|
{
|
|
|
|
if (mDocument) {
|
|
|
|
// The document must have been destroyed before we got our event.
|
|
|
|
// Otherwise this can't happen, since documents hold strong references to
|
|
|
|
// their observers.
|
|
|
|
Cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EndLoad(nsIDocument* aDocument) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aDocument == mDocument, "Got EndLoad for wrong document?");
|
|
|
|
|
|
|
|
// OnSVGDocumentParsed will release our owner's reference to us, so ensure
|
|
|
|
// we stick around long enough to complete our work.
|
|
|
|
nsRefPtr<SVGParseCompleteListener> kungFuDeathGroup(this);
|
|
|
|
|
|
|
|
mImage->OnSVGDocumentParsed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Cancel()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mDocument, "Duplicate call to Cancel");
|
2013-02-26 13:21:07 -08:00
|
|
|
if (mDocument) {
|
|
|
|
mDocument->RemoveObserver(this);
|
|
|
|
mDocument = nullptr;
|
|
|
|
}
|
2013-02-13 18:04:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIDocument> mDocument;
|
2013-02-28 22:44:59 -08:00
|
|
|
VectorImage* const mImage; // Raw pointer to owner.
|
2013-02-13 18:04:08 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(SVGParseCompleteListener, nsIDocumentObserver)
|
|
|
|
|
|
|
|
class SVGLoadEventListener MOZ_FINAL : public nsIDOMEventListener {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
SVGLoadEventListener(nsIDocument* aDocument,
|
|
|
|
VectorImage* aImage)
|
|
|
|
: mDocument(aDocument)
|
|
|
|
, mImage(aImage)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mDocument, "Need an SVG document");
|
|
|
|
NS_ABORT_IF_FALSE(mImage, "Need an image");
|
|
|
|
|
|
|
|
mDocument->AddEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true, false);
|
|
|
|
mDocument->AddEventListener(NS_LITERAL_STRING("SVGAbort"), this, true, false);
|
|
|
|
mDocument->AddEventListener(NS_LITERAL_STRING("SVGError"), this, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
~SVGLoadEventListener()
|
|
|
|
{
|
|
|
|
if (mDocument) {
|
|
|
|
// The document must have been destroyed before we got our event.
|
|
|
|
// Otherwise this can't happen, since documents hold strong references to
|
|
|
|
// their observers.
|
|
|
|
Cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mDocument, "Need an SVG document. Received multiple events?");
|
|
|
|
|
|
|
|
// OnSVGDocumentLoaded/OnSVGDocumentError will release our owner's reference
|
|
|
|
// to us, so ensure we stick around long enough to complete our work.
|
|
|
|
nsRefPtr<SVGLoadEventListener> kungFuDeathGroup(this);
|
|
|
|
|
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
|
|
|
NS_ABORT_IF_FALSE(eventType.EqualsLiteral("MozSVGAsImageDocumentLoad") ||
|
|
|
|
eventType.EqualsLiteral("SVGAbort") ||
|
|
|
|
eventType.EqualsLiteral("SVGError"),
|
|
|
|
"Received unexpected event");
|
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("MozSVGAsImageDocumentLoad")) {
|
|
|
|
mImage->OnSVGDocumentLoaded();
|
|
|
|
} else {
|
|
|
|
mImage->OnSVGDocumentError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Cancel()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mDocument, "Duplicate call to Cancel");
|
2013-02-26 13:21:07 -08:00
|
|
|
if (mDocument) {
|
|
|
|
mDocument->RemoveEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true);
|
|
|
|
mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGAbort"), this, true);
|
|
|
|
mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGError"), this, true);
|
|
|
|
mDocument = nullptr;
|
|
|
|
}
|
2013-02-13 18:04:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIDocument> mDocument;
|
2013-02-28 22:44:59 -08:00
|
|
|
VectorImage* const mImage; // Raw pointer to owner.
|
2013-02-13 18:04:08 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(SVGLoadEventListener, nsIDOMEventListener)
|
|
|
|
|
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
|
|
|
|
|
2012-12-19 13:28:54 -08:00
|
|
|
VectorImage::VectorImage(imgStatusTracker* aStatusTracker,
|
|
|
|
nsIURI* aURI /* = nullptr */) :
|
2012-12-19 14:24:32 -08:00
|
|
|
ImageResource(aStatusTracker, aURI), // invoke superclass's constructor
|
2010-09-08 13:40:39 -07:00
|
|
|
mRestrictedRegion(0, 0, 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()
|
|
|
|
{
|
2013-02-25 17:40:13 -08:00
|
|
|
CancelAllListeners();
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Methods inherited from Image.h
|
|
|
|
|
|
|
|
nsresult
|
2013-02-12 19:00:03 -08:00
|
|
|
VectorImage::Init(const char* aMimeType,
|
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");
|
2013-01-08 13:40:47 -08:00
|
|
|
NS_ABORT_IF_FALSE(!strcmp(aMimeType, IMAGE_SVG_XML), "Unexpected mimetype");
|
2010-09-08 13:40:39 -07:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-02-04 16:06:14 -08:00
|
|
|
nsIntRect
|
|
|
|
VectorImage::FrameRect(uint32_t aWhichFrame)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2013-02-04 16:06:14 -08:00
|
|
|
return 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;
|
|
|
|
}
|
|
|
|
|
2012-12-17 14:05:18 -08:00
|
|
|
nsresult
|
|
|
|
VectorImage::OnImageDataComplete(nsIRequest* aRequest,
|
|
|
|
nsISupports* aContext,
|
2013-02-13 18:41:10 -08:00
|
|
|
nsresult aStatus,
|
|
|
|
bool aLastPart)
|
2012-12-17 14:05:18 -08:00
|
|
|
{
|
2013-02-13 18:41:10 -08:00
|
|
|
NS_ABORT_IF_FALSE(mStopRequest.empty(), "Duplicate call to OnImageDataComplete?");
|
|
|
|
|
|
|
|
// Call our internal OnStopRequest method, which only talks to our embedded
|
|
|
|
// SVG document. This won't have any effect on our imgStatusTracker.
|
|
|
|
nsresult finalStatus = OnStopRequest(aRequest, aContext, aStatus);
|
|
|
|
|
|
|
|
// Give precedence to Necko failure codes.
|
|
|
|
if (NS_FAILED(aStatus))
|
|
|
|
finalStatus = aStatus;
|
|
|
|
|
|
|
|
// If there's an error already, we need to fire OnStopRequest on our
|
|
|
|
// imgStatusTracker immediately. We might not get another chance.
|
|
|
|
if (mError || NS_FAILED(finalStatus)) {
|
|
|
|
GetStatusTracker().OnStopRequest(aLastPart, finalStatus);
|
|
|
|
return finalStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we record the parameters we'll use to call OnStopRequest, and
|
|
|
|
// return. We'll actually call it in OnSVGDocumentLoaded or
|
|
|
|
// OnSVGDocumentError.
|
|
|
|
mStopRequest.construct(aLastPart, finalStatus);
|
|
|
|
|
|
|
|
return finalStatus;
|
2012-12-17 14:05:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
VectorImage::OnImageDataAvailable(nsIRequest* aRequest,
|
|
|
|
nsISupports* aContext,
|
|
|
|
nsIInputStream* aInStr,
|
|
|
|
uint64_t aSourceOffset,
|
|
|
|
uint32_t aCount)
|
|
|
|
{
|
|
|
|
return OnDataAvailable(aRequest, aContext, aInStr, aSourceOffset, aCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
VectorImage::OnNewSourceData()
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
{
|
2012-12-19 14:24:32 -08:00
|
|
|
return ImageResource::ShouldAnimate() && mIsFullyLoaded && mHaveAnimations;
|
2010-11-17 12:39:23 -08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-01-10 19:38:34 -08:00
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] readonly attribute nsSize intrinsicSize; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::GetIntrinsicSize(nsSize* aSize)
|
|
|
|
{
|
2013-02-28 12:22:46 -08:00
|
|
|
if (mError || !mIsFullyLoaded)
|
2013-01-10 19:38:34 -08:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-02-28 12:22:46 -08:00
|
|
|
nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame();
|
2013-01-10 19:38:34 -08:00
|
|
|
*aSize = nsSize(-1, -1);
|
|
|
|
nsIFrame::IntrinsicSize rfSize = rootFrame->GetIntrinsicSize();
|
|
|
|
if (rfSize.width.GetUnit() == eStyleUnit_Coord)
|
|
|
|
aSize->width = rfSize.width.GetCoordValue();
|
|
|
|
if (rfSize.height.GetUnit() == eStyleUnit_Coord)
|
|
|
|
aSize->height = rfSize.height.GetCoordValue();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] readonly attribute nsSize intrinsicRatio; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VectorImage::GetIntrinsicRatio(nsSize* aRatio)
|
|
|
|
{
|
2013-02-28 12:22:46 -08:00
|
|
|
if (mError || !mIsFullyLoaded)
|
2013-01-10 19:38:34 -08:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-02-28 12:22:46 -08:00
|
|
|
nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame();
|
2013-01-10 19:38:34 -08:00
|
|
|
*aRatio = rootFrame->GetIntrinsicRatio();
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
2013-02-04 14:22:30 -08:00
|
|
|
/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */
|
|
|
|
NS_IMETHODIMP_(bool)
|
|
|
|
VectorImage::FrameIsOpaque(uint32_t aWhichFrame)
|
2010-09-08 13:40:39 -07:00
|
|
|
{
|
2013-02-04 14:22:30 -08:00
|
|
|
if (aWhichFrame > FRAME_MAX_VALUE)
|
|
|
|
NS_WARNING("aWhichFrame outside valid range!");
|
|
|
|
|
|
|
|
return false; // In general, SVG content is not opaque.
|
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-10-19 13:27:11 -07:00
|
|
|
//******************************************************************************
|
|
|
|
/* [noscript] ImageContainer getImageContainer(); */
|
|
|
|
NS_IMETHODIMP
|
2012-11-27 18:34:45 -08:00
|
|
|
VectorImage::GetImageContainer(LayerManager* aManager,
|
|
|
|
mozilla::layers::ImageContainer** _retval)
|
2012-10-19 13:27:11 -07:00
|
|
|
{
|
|
|
|
*_retval = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
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),
|
2013-02-28 12:22:43 -08:00
|
|
|
imageIntSize, nullptr, aFlags);
|
2010-10-12 12:00:30 -07:00
|
|
|
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)
|
2013-01-15 04:22:03 -08:00
|
|
|
extractedImg->mRestrictedRegion.width = std::max(aRegion.width, 0);
|
|
|
|
extractedImg->mRestrictedRegion.height = std::max(aRegion.height, 0);
|
2010-09-08 13:40:39 -07:00
|
|
|
|
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,
|
2013-02-28 12:22:43 -08:00
|
|
|
* [const] in SVGImageContext aSVGContext,
|
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,
|
2013-02-28 12:22:43 -08:00
|
|
|
const SVGImageContext* aSVGContext,
|
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;
|
|
|
|
}
|
2013-02-28 22:44:57 -08:00
|
|
|
AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsDrawing = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2013-02-28 12:22:43 -08:00
|
|
|
AutoSVGRenderingState autoSVGState(aSVGContext,
|
|
|
|
mSVGDocumentWrapper->GetRootSVGElem());
|
2012-11-08 11:54:47 -08:00
|
|
|
mSVGDocumentWrapper->UpdateViewportBounds(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);
|
|
|
|
|
2013-02-28 16:43:43 -08:00
|
|
|
MOZ_ASSERT(mRenderingObserver || mHaveRestrictedRegion,
|
|
|
|
"Should have a rendering observer by now unless ExtractFrame created us");
|
|
|
|
if (mRenderingObserver) {
|
|
|
|
// Allow ourselves to fire FrameChanged and OnStopFrame again.
|
|
|
|
mRenderingObserver->ResumeListening();
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
return NS_OK;
|
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;
|
2013-02-13 18:04:08 -08:00
|
|
|
return rv;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
// Sending StartDecode will block page load until the document's ready. (We
|
|
|
|
// unblock it by sending StopDecode in OnSVGDocumentLoaded or
|
|
|
|
// OnSVGDocumentError.)
|
|
|
|
if (mStatusTracker) {
|
|
|
|
mStatusTracker->GetDecoderObserver()->OnStartDecode();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a listener to wait until the SVG document is fully loaded, which
|
|
|
|
// will signal that this image is ready to render. Certain error conditions
|
|
|
|
// will prevent us from ever getting this notification, so we also create a
|
|
|
|
// listener that waits for parsing to complete and cancels the
|
|
|
|
// SVGLoadEventListener if needed. The listeners are automatically attached
|
|
|
|
// to the document by their constructors.
|
|
|
|
nsIDocument* document = mSVGDocumentWrapper->GetDocument();
|
|
|
|
mLoadEventListener = new SVGLoadEventListener(document, this);
|
|
|
|
mParseCompleteListener = new SVGParseCompleteListener(document, this);
|
|
|
|
|
|
|
|
return NS_OK;
|
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;
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
return mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VectorImage::OnSVGDocumentParsed()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mParseCompleteListener, "Should have the parse complete listener");
|
|
|
|
NS_ABORT_IF_FALSE(mLoadEventListener, "Should have the load event listener");
|
|
|
|
|
|
|
|
if (!mSVGDocumentWrapper->GetRootSVGElem()) {
|
|
|
|
// This is an invalid SVG document. It may have failed to parse, or it may
|
|
|
|
// be missing the <svg> root element, or the <svg> root element may not
|
|
|
|
// declare the correct namespace. In any of these cases, we'll never be
|
|
|
|
// notified that the SVG finished loading, so we need to treat this as an error.
|
|
|
|
OnSVGDocumentError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VectorImage::CancelAllListeners()
|
|
|
|
{
|
|
|
|
if (mParseCompleteListener) {
|
|
|
|
mParseCompleteListener->Cancel();
|
|
|
|
mParseCompleteListener = nullptr;
|
|
|
|
}
|
|
|
|
if (mLoadEventListener) {
|
|
|
|
mLoadEventListener->Cancel();
|
|
|
|
mLoadEventListener = nullptr;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
2013-02-13 18:04:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VectorImage::OnSVGDocumentLoaded()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mSVGDocumentWrapper->GetRootSVGElem(), "Should have parsed successfully");
|
|
|
|
NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations,
|
|
|
|
"These flags shouldn't get set until OnSVGDocumentLoaded. "
|
|
|
|
"Duplicate calls to OnSVGDocumentLoaded?");
|
|
|
|
|
|
|
|
CancelAllListeners();
|
|
|
|
|
|
|
|
// XXX Flushing is wasteful if embedding frame hasn't had initial reflow.
|
|
|
|
mSVGDocumentWrapper->FlushLayout();
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mIsFullyLoaded = true;
|
2010-09-08 13:40:39 -07:00
|
|
|
mHaveAnimations = mSVGDocumentWrapper->IsAnimated();
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
// Start listening to our image for rendering updates.
|
2010-09-08 13:40:40 -07:00
|
|
|
mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this);
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
// Tell *our* observers that we're done loading.
|
2013-02-12 19:00:03 -08:00
|
|
|
if (mStatusTracker) {
|
|
|
|
imgDecoderObserver* observer = mStatusTracker->GetDecoderObserver();
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
observer->OnStartContainer(); // Signal that width/height are available.
|
2012-10-12 09:11:23 -07:00
|
|
|
observer->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
|
|
|
|
observer->OnStopFrame();
|
2013-02-13 18:41:10 -08:00
|
|
|
|
|
|
|
if (!mStopRequest.empty()) {
|
|
|
|
GetStatusTracker().OnStopRequest(mStopRequest.ref().lastPart,
|
|
|
|
mStopRequest.ref().status);
|
|
|
|
mStopRequest.destroy();
|
|
|
|
}
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
observer->OnStopDecode(NS_OK); // Unblock page load.
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
2013-02-13 18:04:08 -08:00
|
|
|
|
2010-12-19 16:45:29 -08:00
|
|
|
EvaluateAnimation();
|
2013-02-13 18:04:08 -08:00
|
|
|
}
|
2010-09-08 13:40:39 -07:00
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
void
|
|
|
|
VectorImage::OnSVGDocumentError()
|
|
|
|
{
|
|
|
|
CancelAllListeners();
|
|
|
|
|
|
|
|
// XXXdholbert Need to do something more for the parsing failed case -- right
|
|
|
|
// now, this just makes us draw the "object" icon, rather than the (jagged)
|
|
|
|
// "broken image" icon. See bug 594505.
|
|
|
|
mError = true;
|
|
|
|
|
|
|
|
if (mStatusTracker) {
|
2013-02-13 18:41:10 -08:00
|
|
|
if (!mStopRequest.empty()) {
|
|
|
|
nsresult status = NS_FAILED(mStopRequest.ref().status)
|
|
|
|
? mStopRequest.ref().status
|
|
|
|
: NS_ERROR_FAILURE;
|
|
|
|
GetStatusTracker().OnStopRequest(mStopRequest.ref().lastPart, status);
|
|
|
|
mStopRequest.destroy();
|
|
|
|
}
|
|
|
|
|
2013-02-13 18:04:08 -08:00
|
|
|
// Unblock page load.
|
|
|
|
mStatusTracker->GetDecoderObserver()->OnStopDecode(NS_ERROR_FAILURE);
|
|
|
|
}
|
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()
|
|
|
|
{
|
2013-02-12 19:00:03 -08:00
|
|
|
if (mStatusTracker) {
|
|
|
|
imgDecoderObserver* observer = mStatusTracker->GetDecoderObserver();
|
2012-12-18 08:37:15 -08:00
|
|
|
observer->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
|
|
|
|
observer->OnStopFrame();
|
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
|