1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/image/src/VectorImage.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1158 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "VectorImage.h" 1.10 + 1.11 +#include "gfx2DGlue.h" 1.12 +#include "gfxContext.h" 1.13 +#include "gfxDrawable.h" 1.14 +#include "gfxPlatform.h" 1.15 +#include "gfxUtils.h" 1.16 +#include "imgDecoderObserver.h" 1.17 +#include "mozilla/AutoRestore.h" 1.18 +#include "mozilla/MemoryReporting.h" 1.19 +#include "mozilla/dom/SVGSVGElement.h" 1.20 +#include "mozilla/gfx/2D.h" 1.21 +#include "mozilla/RefPtr.h" 1.22 +#include "nsIDOMEvent.h" 1.23 +#include "nsIPresShell.h" 1.24 +#include "nsIStreamListener.h" 1.25 +#include "nsMimeTypes.h" 1.26 +#include "nsPresContext.h" 1.27 +#include "nsRect.h" 1.28 +#include "nsStubDocumentObserver.h" 1.29 +#include "nsSVGEffects.h" // for nsSVGRenderingObserver 1.30 +#include "Orientation.h" 1.31 +#include "SVGDocumentWrapper.h" 1.32 +#include "nsIDOMEventListener.h" 1.33 +#include "SurfaceCache.h" 1.34 + 1.35 +// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK 1.36 +#undef GetCurrentTime 1.37 + 1.38 +namespace mozilla { 1.39 + 1.40 +using namespace dom; 1.41 +using namespace gfx; 1.42 +using namespace layers; 1.43 + 1.44 +namespace image { 1.45 + 1.46 +// Helper-class: SVGRootRenderingObserver 1.47 +class SVGRootRenderingObserver MOZ_FINAL : public nsSVGRenderingObserver { 1.48 +public: 1.49 + SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper, 1.50 + VectorImage* aVectorImage) 1.51 + : nsSVGRenderingObserver() 1.52 + , mDocWrapper(aDocWrapper) 1.53 + , mVectorImage(aVectorImage) 1.54 + , mHonoringInvalidations(true) 1.55 + { 1.56 + MOZ_ASSERT(mDocWrapper, "Need a non-null SVG document wrapper"); 1.57 + MOZ_ASSERT(mVectorImage, "Need a non-null VectorImage"); 1.58 + 1.59 + StartListening(); 1.60 + Element* elem = GetTarget(); 1.61 + MOZ_ASSERT(elem, "no root SVG node for us to observe"); 1.62 + 1.63 + nsSVGEffects::AddRenderingObserver(elem, this); 1.64 + mInObserverList = true; 1.65 + } 1.66 + 1.67 + virtual ~SVGRootRenderingObserver() 1.68 + { 1.69 + StopListening(); 1.70 + } 1.71 + 1.72 + void ResumeHonoringInvalidations() 1.73 + { 1.74 + mHonoringInvalidations = true; 1.75 + } 1.76 + 1.77 +protected: 1.78 + virtual Element* GetTarget() MOZ_OVERRIDE 1.79 + { 1.80 + return mDocWrapper->GetRootSVGElem(); 1.81 + } 1.82 + 1.83 + virtual void DoUpdate() MOZ_OVERRIDE 1.84 + { 1.85 + Element* elem = GetTarget(); 1.86 + MOZ_ASSERT(elem, "missing root SVG node"); 1.87 + 1.88 + if (mHonoringInvalidations && !mDocWrapper->ShouldIgnoreInvalidation()) { 1.89 + nsIFrame* frame = elem->GetPrimaryFrame(); 1.90 + if (!frame || frame->PresContext()->PresShell()->IsDestroying()) { 1.91 + // We're being destroyed. Bail out. 1.92 + return; 1.93 + } 1.94 + 1.95 + // Ignore further invalidations until we draw. 1.96 + mHonoringInvalidations = false; 1.97 + 1.98 + mVectorImage->InvalidateObserversOnNextRefreshDriverTick(); 1.99 + } 1.100 + 1.101 + // Our caller might've removed us from rendering-observer list. 1.102 + // Add ourselves back! 1.103 + if (!mInObserverList) { 1.104 + nsSVGEffects::AddRenderingObserver(elem, this); 1.105 + mInObserverList = true; 1.106 + } 1.107 + } 1.108 + 1.109 + // Private data 1.110 + const nsRefPtr<SVGDocumentWrapper> mDocWrapper; 1.111 + VectorImage* const mVectorImage; // Raw pointer because it owns me. 1.112 + bool mHonoringInvalidations; 1.113 +}; 1.114 + 1.115 +class SVGParseCompleteListener MOZ_FINAL : public nsStubDocumentObserver { 1.116 +public: 1.117 + NS_DECL_ISUPPORTS 1.118 + 1.119 + SVGParseCompleteListener(nsIDocument* aDocument, 1.120 + VectorImage* aImage) 1.121 + : mDocument(aDocument) 1.122 + , mImage(aImage) 1.123 + { 1.124 + MOZ_ASSERT(mDocument, "Need an SVG document"); 1.125 + MOZ_ASSERT(mImage, "Need an image"); 1.126 + 1.127 + mDocument->AddObserver(this); 1.128 + } 1.129 + 1.130 + ~SVGParseCompleteListener() 1.131 + { 1.132 + if (mDocument) { 1.133 + // The document must have been destroyed before we got our event. 1.134 + // Otherwise this can't happen, since documents hold strong references to 1.135 + // their observers. 1.136 + Cancel(); 1.137 + } 1.138 + } 1.139 + 1.140 + void EndLoad(nsIDocument* aDocument) MOZ_OVERRIDE 1.141 + { 1.142 + MOZ_ASSERT(aDocument == mDocument, "Got EndLoad for wrong document?"); 1.143 + 1.144 + // OnSVGDocumentParsed will release our owner's reference to us, so ensure 1.145 + // we stick around long enough to complete our work. 1.146 + nsRefPtr<SVGParseCompleteListener> kungFuDeathGroup(this); 1.147 + 1.148 + mImage->OnSVGDocumentParsed(); 1.149 + } 1.150 + 1.151 + void Cancel() 1.152 + { 1.153 + MOZ_ASSERT(mDocument, "Duplicate call to Cancel"); 1.154 + if (mDocument) { 1.155 + mDocument->RemoveObserver(this); 1.156 + mDocument = nullptr; 1.157 + } 1.158 + } 1.159 + 1.160 +private: 1.161 + nsCOMPtr<nsIDocument> mDocument; 1.162 + VectorImage* const mImage; // Raw pointer to owner. 1.163 +}; 1.164 + 1.165 +NS_IMPL_ISUPPORTS(SVGParseCompleteListener, nsIDocumentObserver) 1.166 + 1.167 +class SVGLoadEventListener MOZ_FINAL : public nsIDOMEventListener { 1.168 +public: 1.169 + NS_DECL_ISUPPORTS 1.170 + 1.171 + SVGLoadEventListener(nsIDocument* aDocument, 1.172 + VectorImage* aImage) 1.173 + : mDocument(aDocument) 1.174 + , mImage(aImage) 1.175 + { 1.176 + MOZ_ASSERT(mDocument, "Need an SVG document"); 1.177 + MOZ_ASSERT(mImage, "Need an image"); 1.178 + 1.179 + mDocument->AddEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true, false); 1.180 + mDocument->AddEventListener(NS_LITERAL_STRING("SVGAbort"), this, true, false); 1.181 + mDocument->AddEventListener(NS_LITERAL_STRING("SVGError"), this, true, false); 1.182 + } 1.183 + 1.184 + ~SVGLoadEventListener() 1.185 + { 1.186 + if (mDocument) { 1.187 + // The document must have been destroyed before we got our event. 1.188 + // Otherwise this can't happen, since documents hold strong references to 1.189 + // their observers. 1.190 + Cancel(); 1.191 + } 1.192 + } 1.193 + 1.194 + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE 1.195 + { 1.196 + MOZ_ASSERT(mDocument, "Need an SVG document. Received multiple events?"); 1.197 + 1.198 + // OnSVGDocumentLoaded/OnSVGDocumentError will release our owner's reference 1.199 + // to us, so ensure we stick around long enough to complete our work. 1.200 + nsRefPtr<SVGLoadEventListener> kungFuDeathGroup(this); 1.201 + 1.202 + nsAutoString eventType; 1.203 + aEvent->GetType(eventType); 1.204 + MOZ_ASSERT(eventType.EqualsLiteral("MozSVGAsImageDocumentLoad") || 1.205 + eventType.EqualsLiteral("SVGAbort") || 1.206 + eventType.EqualsLiteral("SVGError"), 1.207 + "Received unexpected event"); 1.208 + 1.209 + if (eventType.EqualsLiteral("MozSVGAsImageDocumentLoad")) { 1.210 + mImage->OnSVGDocumentLoaded(); 1.211 + } else { 1.212 + mImage->OnSVGDocumentError(); 1.213 + } 1.214 + 1.215 + return NS_OK; 1.216 + } 1.217 + 1.218 + void Cancel() 1.219 + { 1.220 + MOZ_ASSERT(mDocument, "Duplicate call to Cancel"); 1.221 + if (mDocument) { 1.222 + mDocument->RemoveEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true); 1.223 + mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGAbort"), this, true); 1.224 + mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGError"), this, true); 1.225 + mDocument = nullptr; 1.226 + } 1.227 + } 1.228 + 1.229 +private: 1.230 + nsCOMPtr<nsIDocument> mDocument; 1.231 + VectorImage* const mImage; // Raw pointer to owner. 1.232 +}; 1.233 + 1.234 +NS_IMPL_ISUPPORTS(SVGLoadEventListener, nsIDOMEventListener) 1.235 + 1.236 +// Helper-class: SVGDrawingCallback 1.237 +class SVGDrawingCallback : public gfxDrawingCallback { 1.238 +public: 1.239 + SVGDrawingCallback(SVGDocumentWrapper* aSVGDocumentWrapper, 1.240 + const nsIntRect& aViewport, 1.241 + const gfxSize& aScale, 1.242 + uint32_t aImageFlags) : 1.243 + mSVGDocumentWrapper(aSVGDocumentWrapper), 1.244 + mViewport(aViewport), 1.245 + mScale(aScale), 1.246 + mImageFlags(aImageFlags) 1.247 + {} 1.248 + virtual bool operator()(gfxContext* aContext, 1.249 + const gfxRect& aFillRect, 1.250 + const GraphicsFilter& aFilter, 1.251 + const gfxMatrix& aTransform); 1.252 +private: 1.253 + nsRefPtr<SVGDocumentWrapper> mSVGDocumentWrapper; 1.254 + const nsIntRect mViewport; 1.255 + const gfxSize mScale; 1.256 + uint32_t mImageFlags; 1.257 +}; 1.258 + 1.259 +// Based loosely on nsSVGIntegrationUtils' PaintFrameCallback::operator() 1.260 +bool 1.261 +SVGDrawingCallback::operator()(gfxContext* aContext, 1.262 + const gfxRect& aFillRect, 1.263 + const GraphicsFilter& aFilter, 1.264 + const gfxMatrix& aTransform) 1.265 +{ 1.266 + MOZ_ASSERT(mSVGDocumentWrapper, "need an SVGDocumentWrapper"); 1.267 + 1.268 + // Get (& sanity-check) the helper-doc's presShell 1.269 + nsCOMPtr<nsIPresShell> presShell; 1.270 + if (NS_FAILED(mSVGDocumentWrapper->GetPresShell(getter_AddRefs(presShell)))) { 1.271 + NS_WARNING("Unable to draw -- presShell lookup failed"); 1.272 + return false; 1.273 + } 1.274 + MOZ_ASSERT(presShell, "GetPresShell succeeded but returned null"); 1.275 + 1.276 + gfxContextAutoSaveRestore contextRestorer(aContext); 1.277 + 1.278 + // Clip to aFillRect so that we don't paint outside. 1.279 + aContext->NewPath(); 1.280 + aContext->Rectangle(aFillRect); 1.281 + aContext->Clip(); 1.282 + 1.283 + gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext); 1.284 + aContext->Multiply(gfxMatrix(aTransform).Invert()); 1.285 + aContext->Scale(1.0 / mScale.width, 1.0 / mScale.height); 1.286 + 1.287 + nsPresContext* presContext = presShell->GetPresContext(); 1.288 + MOZ_ASSERT(presContext, "pres shell w/out pres context"); 1.289 + 1.290 + nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x), 1.291 + presContext->DevPixelsToAppUnits(mViewport.y), 1.292 + presContext->DevPixelsToAppUnits(mViewport.width), 1.293 + presContext->DevPixelsToAppUnits(mViewport.height)); 1.294 + 1.295 + uint32_t renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING; 1.296 + if (!(mImageFlags & imgIContainer::FLAG_SYNC_DECODE)) { 1.297 + renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES; 1.298 + } 1.299 + 1.300 + presShell->RenderDocument(svgRect, renderDocFlags, 1.301 + NS_RGBA(0, 0, 0, 0), // transparent 1.302 + aContext); 1.303 + 1.304 + return true; 1.305 +} 1.306 + 1.307 +// Implement VectorImage's nsISupports-inherited methods 1.308 +NS_IMPL_ISUPPORTS(VectorImage, 1.309 + imgIContainer, 1.310 + nsIStreamListener, 1.311 + nsIRequestObserver) 1.312 + 1.313 +//------------------------------------------------------------------------------ 1.314 +// Constructor / Destructor 1.315 + 1.316 +VectorImage::VectorImage(imgStatusTracker* aStatusTracker, 1.317 + ImageURL* aURI /* = nullptr */) : 1.318 + ImageResource(aURI), // invoke superclass's constructor 1.319 + mIsInitialized(false), 1.320 + mIsFullyLoaded(false), 1.321 + mIsDrawing(false), 1.322 + mHaveAnimations(false), 1.323 + mHasPendingInvalidation(false) 1.324 +{ 1.325 + mStatusTrackerInit = new imgStatusTrackerInit(this, aStatusTracker); 1.326 +} 1.327 + 1.328 +VectorImage::~VectorImage() 1.329 +{ 1.330 + CancelAllListeners(); 1.331 + SurfaceCache::Discard(this); 1.332 +} 1.333 + 1.334 +//------------------------------------------------------------------------------ 1.335 +// Methods inherited from Image.h 1.336 + 1.337 +nsresult 1.338 +VectorImage::Init(const char* aMimeType, 1.339 + uint32_t aFlags) 1.340 +{ 1.341 + // We don't support re-initialization 1.342 + if (mIsInitialized) 1.343 + return NS_ERROR_ILLEGAL_VALUE; 1.344 + 1.345 + MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations && !mError, 1.346 + "Flags unexpectedly set before initialization"); 1.347 + MOZ_ASSERT(!strcmp(aMimeType, IMAGE_SVG_XML), "Unexpected mimetype"); 1.348 + 1.349 + mIsInitialized = true; 1.350 + return NS_OK; 1.351 +} 1.352 + 1.353 +nsIntRect 1.354 +VectorImage::FrameRect(uint32_t aWhichFrame) 1.355 +{ 1.356 + return nsIntRect::GetMaxSizedIntRect(); 1.357 +} 1.358 + 1.359 +size_t 1.360 +VectorImage::HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const 1.361 +{ 1.362 + // We're not storing the source data -- we just feed that directly to 1.363 + // our helper SVG document as we receive it, for it to parse. 1.364 + // So 0 is an appropriate return value here. 1.365 + return 0; 1.366 +} 1.367 + 1.368 +size_t 1.369 +VectorImage::HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const 1.370 +{ 1.371 + // XXXdholbert TODO: return num bytes used by helper SVG doc. (bug 590790) 1.372 + return 0; 1.373 +} 1.374 + 1.375 +size_t 1.376 +VectorImage::NonHeapSizeOfDecoded() const 1.377 +{ 1.378 + return 0; 1.379 +} 1.380 + 1.381 +size_t 1.382 +VectorImage::OutOfProcessSizeOfDecoded() const 1.383 +{ 1.384 + return 0; 1.385 +} 1.386 + 1.387 +nsresult 1.388 +VectorImage::OnImageDataComplete(nsIRequest* aRequest, 1.389 + nsISupports* aContext, 1.390 + nsresult aStatus, 1.391 + bool aLastPart) 1.392 +{ 1.393 + // Call our internal OnStopRequest method, which only talks to our embedded 1.394 + // SVG document. This won't have any effect on our imgStatusTracker. 1.395 + nsresult finalStatus = OnStopRequest(aRequest, aContext, aStatus); 1.396 + 1.397 + // Give precedence to Necko failure codes. 1.398 + if (NS_FAILED(aStatus)) 1.399 + finalStatus = aStatus; 1.400 + 1.401 + // Actually fire OnStopRequest. 1.402 + if (mStatusTracker) { 1.403 + // XXX(seth): Is this seriously the least insane way to do this? 1.404 + nsRefPtr<imgStatusTracker> clone = mStatusTracker->CloneForRecording(); 1.405 + imgDecoderObserver* observer = clone->GetDecoderObserver(); 1.406 + observer->OnStopRequest(aLastPart, finalStatus); 1.407 + ImageStatusDiff diff = mStatusTracker->Difference(clone); 1.408 + mStatusTracker->ApplyDifference(diff); 1.409 + mStatusTracker->SyncNotifyDifference(diff); 1.410 + } 1.411 + return finalStatus; 1.412 +} 1.413 + 1.414 +nsresult 1.415 +VectorImage::OnImageDataAvailable(nsIRequest* aRequest, 1.416 + nsISupports* aContext, 1.417 + nsIInputStream* aInStr, 1.418 + uint64_t aSourceOffset, 1.419 + uint32_t aCount) 1.420 +{ 1.421 + return OnDataAvailable(aRequest, aContext, aInStr, aSourceOffset, aCount); 1.422 +} 1.423 + 1.424 +nsresult 1.425 +VectorImage::OnNewSourceData() 1.426 +{ 1.427 + return NS_OK; 1.428 +} 1.429 + 1.430 +nsresult 1.431 +VectorImage::StartAnimation() 1.432 +{ 1.433 + if (mError) 1.434 + return NS_ERROR_FAILURE; 1.435 + 1.436 + MOZ_ASSERT(ShouldAnimate(), "Should not animate!"); 1.437 + 1.438 + mSVGDocumentWrapper->StartAnimation(); 1.439 + return NS_OK; 1.440 +} 1.441 + 1.442 +nsresult 1.443 +VectorImage::StopAnimation() 1.444 +{ 1.445 + nsresult rv = NS_OK; 1.446 + if (mError) { 1.447 + rv = NS_ERROR_FAILURE; 1.448 + } else { 1.449 + MOZ_ASSERT(mIsFullyLoaded && mHaveAnimations, 1.450 + "Should not have been animating!"); 1.451 + 1.452 + mSVGDocumentWrapper->StopAnimation(); 1.453 + } 1.454 + 1.455 + mAnimating = false; 1.456 + return rv; 1.457 +} 1.458 + 1.459 +bool 1.460 +VectorImage::ShouldAnimate() 1.461 +{ 1.462 + return ImageResource::ShouldAnimate() && mIsFullyLoaded && mHaveAnimations; 1.463 +} 1.464 + 1.465 +NS_IMETHODIMP_(void) 1.466 +VectorImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime) 1.467 +{ 1.468 + // We don't care about animation start time. 1.469 +} 1.470 + 1.471 +//------------------------------------------------------------------------------ 1.472 +// imgIContainer methods 1.473 + 1.474 +//****************************************************************************** 1.475 +/* readonly attribute int32_t width; */ 1.476 +NS_IMETHODIMP 1.477 +VectorImage::GetWidth(int32_t* aWidth) 1.478 +{ 1.479 + if (mError || !mIsFullyLoaded) { 1.480 + *aWidth = 0; 1.481 + return NS_ERROR_FAILURE; 1.482 + } 1.483 + 1.484 + if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth, 1.485 + *aWidth)) { 1.486 + *aWidth = 0; 1.487 + return NS_ERROR_FAILURE; 1.488 + } 1.489 + 1.490 + return NS_OK; 1.491 +} 1.492 + 1.493 +//****************************************************************************** 1.494 +/* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */ 1.495 +NS_IMETHODIMP_(void) 1.496 +VectorImage::RequestRefresh(const mozilla::TimeStamp& aTime) 1.497 +{ 1.498 + // TODO: Implement for b666446. 1.499 + EvaluateAnimation(); 1.500 + 1.501 + if (mHasPendingInvalidation) { 1.502 + SendInvalidationNotifications(); 1.503 + mHasPendingInvalidation = false; 1.504 + } 1.505 +} 1.506 + 1.507 +void 1.508 +VectorImage::SendInvalidationNotifications() 1.509 +{ 1.510 + // Animated images don't send out invalidation notifications as soon as 1.511 + // they're generated. Instead, InvalidateObserversOnNextRefreshDriverTick 1.512 + // records that there are pending invalidations and then returns immediately. 1.513 + // The notifications are actually sent from RequestRefresh(). We send these 1.514 + // notifications there to ensure that there is actually a document observing 1.515 + // us. Otherwise, the notifications are just wasted effort. 1.516 + // 1.517 + // Non-animated images call this method directly from 1.518 + // InvalidateObserversOnNextRefreshDriverTick, because RequestRefresh is never 1.519 + // called for them. Ordinarily this isn't needed, since we send out 1.520 + // invalidation notifications in OnSVGDocumentLoaded, but in rare cases the 1.521 + // SVG document may not be 100% ready to render at that time. In those cases 1.522 + // we would miss the subsequent invalidations if we didn't send out the 1.523 + // notifications directly in |InvalidateObservers...|. 1.524 + 1.525 + if (mStatusTracker) { 1.526 + SurfaceCache::Discard(this); 1.527 + mStatusTracker->FrameChanged(&nsIntRect::GetMaxSizedIntRect()); 1.528 + mStatusTracker->OnStopFrame(); 1.529 + } 1.530 +} 1.531 + 1.532 +//****************************************************************************** 1.533 +/* readonly attribute int32_t height; */ 1.534 +NS_IMETHODIMP 1.535 +VectorImage::GetHeight(int32_t* aHeight) 1.536 +{ 1.537 + if (mError || !mIsFullyLoaded) { 1.538 + *aHeight = 0; 1.539 + return NS_ERROR_FAILURE; 1.540 + } 1.541 + 1.542 + if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight, 1.543 + *aHeight)) { 1.544 + *aHeight = 0; 1.545 + return NS_ERROR_FAILURE; 1.546 + } 1.547 + 1.548 + return NS_OK; 1.549 +} 1.550 + 1.551 +//****************************************************************************** 1.552 +/* [noscript] readonly attribute nsSize intrinsicSize; */ 1.553 +NS_IMETHODIMP 1.554 +VectorImage::GetIntrinsicSize(nsSize* aSize) 1.555 +{ 1.556 + if (mError || !mIsFullyLoaded) 1.557 + return NS_ERROR_FAILURE; 1.558 + 1.559 + nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame(); 1.560 + if (!rootFrame) 1.561 + return NS_ERROR_FAILURE; 1.562 + 1.563 + *aSize = nsSize(-1, -1); 1.564 + IntrinsicSize rfSize = rootFrame->GetIntrinsicSize(); 1.565 + if (rfSize.width.GetUnit() == eStyleUnit_Coord) 1.566 + aSize->width = rfSize.width.GetCoordValue(); 1.567 + if (rfSize.height.GetUnit() == eStyleUnit_Coord) 1.568 + aSize->height = rfSize.height.GetCoordValue(); 1.569 + 1.570 + return NS_OK; 1.571 +} 1.572 + 1.573 +//****************************************************************************** 1.574 +/* [noscript] readonly attribute nsSize intrinsicRatio; */ 1.575 +NS_IMETHODIMP 1.576 +VectorImage::GetIntrinsicRatio(nsSize* aRatio) 1.577 +{ 1.578 + if (mError || !mIsFullyLoaded) 1.579 + return NS_ERROR_FAILURE; 1.580 + 1.581 + nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame(); 1.582 + if (!rootFrame) 1.583 + return NS_ERROR_FAILURE; 1.584 + 1.585 + *aRatio = rootFrame->GetIntrinsicRatio(); 1.586 + return NS_OK; 1.587 +} 1.588 + 1.589 +NS_IMETHODIMP_(Orientation) 1.590 +VectorImage::GetOrientation() 1.591 +{ 1.592 + return Orientation(); 1.593 +} 1.594 + 1.595 +//****************************************************************************** 1.596 +/* readonly attribute unsigned short type; */ 1.597 +NS_IMETHODIMP 1.598 +VectorImage::GetType(uint16_t* aType) 1.599 +{ 1.600 + NS_ENSURE_ARG_POINTER(aType); 1.601 + 1.602 + *aType = GetType(); 1.603 + return NS_OK; 1.604 +} 1.605 + 1.606 +//****************************************************************************** 1.607 +/* [noscript, notxpcom] uint16_t GetType(); */ 1.608 +NS_IMETHODIMP_(uint16_t) 1.609 +VectorImage::GetType() 1.610 +{ 1.611 + return imgIContainer::TYPE_VECTOR; 1.612 +} 1.613 + 1.614 +//****************************************************************************** 1.615 +/* readonly attribute boolean animated; */ 1.616 +NS_IMETHODIMP 1.617 +VectorImage::GetAnimated(bool* aAnimated) 1.618 +{ 1.619 + if (mError || !mIsFullyLoaded) 1.620 + return NS_ERROR_FAILURE; 1.621 + 1.622 + *aAnimated = mSVGDocumentWrapper->IsAnimated(); 1.623 + return NS_OK; 1.624 +} 1.625 + 1.626 +//****************************************************************************** 1.627 +/* [notxpcom] int32_t getFirstFrameDelay (); */ 1.628 +int32_t 1.629 +VectorImage::GetFirstFrameDelay() 1.630 +{ 1.631 + if (mError) 1.632 + return -1; 1.633 + 1.634 + if (!mSVGDocumentWrapper->IsAnimated()) 1.635 + return -1; 1.636 + 1.637 + // We don't really have a frame delay, so just pretend that we constantly 1.638 + // need updates. 1.639 + return 0; 1.640 +} 1.641 + 1.642 + 1.643 +//****************************************************************************** 1.644 +/* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */ 1.645 +NS_IMETHODIMP_(bool) 1.646 +VectorImage::FrameIsOpaque(uint32_t aWhichFrame) 1.647 +{ 1.648 + if (aWhichFrame > FRAME_MAX_VALUE) 1.649 + NS_WARNING("aWhichFrame outside valid range!"); 1.650 + 1.651 + return false; // In general, SVG content is not opaque. 1.652 +} 1.653 + 1.654 +//****************************************************************************** 1.655 +/* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame, 1.656 + * in uint32_t aFlags; */ 1.657 +NS_IMETHODIMP_(TemporaryRef<SourceSurface>) 1.658 +VectorImage::GetFrame(uint32_t aWhichFrame, 1.659 + uint32_t aFlags) 1.660 +{ 1.661 + MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE); 1.662 + 1.663 + if (aWhichFrame > FRAME_MAX_VALUE) 1.664 + return nullptr; 1.665 + 1.666 + if (mError) 1.667 + return nullptr; 1.668 + 1.669 + // Look up height & width 1.670 + // ---------------------- 1.671 + nsIntSize imageIntSize; 1.672 + if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth, 1.673 + imageIntSize.width) || 1.674 + !mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight, 1.675 + imageIntSize.height)) { 1.676 + // We'll get here if our SVG doc has a percent-valued width or height. 1.677 + return nullptr; 1.678 + } 1.679 + 1.680 + // Make our surface the size of what will ultimately be drawn to it. 1.681 + // (either the full image size, or the restricted region) 1.682 + RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()-> 1.683 + CreateOffscreenContentDrawTarget(IntSize(imageIntSize.width, 1.684 + imageIntSize.height), 1.685 + SurfaceFormat::B8G8R8A8); 1.686 + nsRefPtr<gfxContext> context = new gfxContext(dt); 1.687 + 1.688 + nsresult rv = Draw(context, GraphicsFilter::FILTER_NEAREST, gfxMatrix(), 1.689 + gfxRect(gfxPoint(0,0), gfxIntSize(imageIntSize.width, 1.690 + imageIntSize.height)), 1.691 + nsIntRect(nsIntPoint(0,0), imageIntSize), 1.692 + imageIntSize, nullptr, aWhichFrame, aFlags); 1.693 + 1.694 + NS_ENSURE_SUCCESS(rv, nullptr); 1.695 + return dt->Snapshot(); 1.696 +} 1.697 + 1.698 +//****************************************************************************** 1.699 +/* [noscript] ImageContainer getImageContainer(); */ 1.700 +NS_IMETHODIMP 1.701 +VectorImage::GetImageContainer(LayerManager* aManager, 1.702 + mozilla::layers::ImageContainer** _retval) 1.703 +{ 1.704 + *_retval = nullptr; 1.705 + return NS_OK; 1.706 +} 1.707 + 1.708 +struct SVGDrawingParameters 1.709 +{ 1.710 + SVGDrawingParameters(gfxContext* aContext, 1.711 + GraphicsFilter aFilter, 1.712 + const gfxMatrix& aUserSpaceToImageSpace, 1.713 + const gfxRect& aFill, 1.714 + const nsIntRect& aSubimage, 1.715 + const nsIntSize& aViewportSize, 1.716 + const SVGImageContext* aSVGContext, 1.717 + float aAnimationTime, 1.718 + uint32_t aFlags) 1.719 + : context(aContext) 1.720 + , filter(aFilter) 1.721 + , fill(aFill) 1.722 + , viewportSize(aViewportSize) 1.723 + , animationTime(aAnimationTime) 1.724 + , svgContext(aSVGContext) 1.725 + , flags(aFlags) 1.726 + { 1.727 + // gfxUtils::DrawPixelSnapped may rasterize this image to a temporary surface 1.728 + // if we hit the tiling path. Unfortunately, the temporary surface isn't 1.729 + // created at the size at which we'll ultimately draw, causing fuzzy output. 1.730 + // To fix this we pre-apply the transform's scaling to the drawing parameters 1.731 + // and remove the scaling from the transform, so the fact that temporary 1.732 + // surfaces won't take the scaling into account doesn't matter. (Bug 600207.) 1.733 + scale = aUserSpaceToImageSpace.ScaleFactors(true); 1.734 + gfxPoint translation(aUserSpaceToImageSpace.GetTranslation()); 1.735 + 1.736 + // Remove the scaling from the transform. 1.737 + gfxMatrix unscale; 1.738 + unscale.Translate(gfxPoint(translation.x / scale.width, 1.739 + translation.y / scale.height)); 1.740 + unscale.Scale(1.0 / scale.width, 1.0 / scale.height); 1.741 + unscale.Translate(-translation); 1.742 + userSpaceToImageSpace = aUserSpaceToImageSpace * unscale; 1.743 + 1.744 + // Rescale drawing parameters. 1.745 + IntSize drawableSize(aViewportSize.width / scale.width, 1.746 + aViewportSize.height / scale.height); 1.747 + sourceRect = userSpaceToImageSpace.Transform(aFill); 1.748 + imageRect = IntRect(IntPoint(0, 0), drawableSize); 1.749 + subimage = gfxRect(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); 1.750 + subimage.ScaleRoundOut(1.0 / scale.width, 1.0 / scale.height); 1.751 + } 1.752 + 1.753 + gfxContext* context; 1.754 + GraphicsFilter filter; 1.755 + gfxMatrix userSpaceToImageSpace; 1.756 + gfxRect fill; 1.757 + gfxRect subimage; 1.758 + gfxRect sourceRect; 1.759 + IntRect imageRect; 1.760 + nsIntSize viewportSize; 1.761 + gfxSize scale; 1.762 + float animationTime; 1.763 + const SVGImageContext* svgContext; 1.764 + uint32_t flags; 1.765 +}; 1.766 + 1.767 +//****************************************************************************** 1.768 +/* [noscript] void draw(in gfxContext aContext, 1.769 + * in gfxGraphicsFilter aFilter, 1.770 + * [const] in gfxMatrix aUserSpaceToImageSpace, 1.771 + * [const] in gfxRect aFill, 1.772 + * [const] in nsIntRect aSubimage, 1.773 + * [const] in nsIntSize aViewportSize, 1.774 + * [const] in SVGImageContext aSVGContext, 1.775 + * in uint32_t aWhichFrame, 1.776 + * in uint32_t aFlags); */ 1.777 +NS_IMETHODIMP 1.778 +VectorImage::Draw(gfxContext* aContext, 1.779 + GraphicsFilter aFilter, 1.780 + const gfxMatrix& aUserSpaceToImageSpace, 1.781 + const gfxRect& aFill, 1.782 + const nsIntRect& aSubimage, 1.783 + const nsIntSize& aViewportSize, 1.784 + const SVGImageContext* aSVGContext, 1.785 + uint32_t aWhichFrame, 1.786 + uint32_t aFlags) 1.787 +{ 1.788 + if (aWhichFrame > FRAME_MAX_VALUE) 1.789 + return NS_ERROR_INVALID_ARG; 1.790 + 1.791 + NS_ENSURE_ARG_POINTER(aContext); 1.792 + if (mError || !mIsFullyLoaded) 1.793 + return NS_ERROR_FAILURE; 1.794 + 1.795 + if (mIsDrawing) { 1.796 + NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw"); 1.797 + return NS_ERROR_FAILURE; 1.798 + } 1.799 + 1.800 + if (mAnimationConsumers == 0 && mStatusTracker) { 1.801 + mStatusTracker->OnUnlockedDraw(); 1.802 + } 1.803 + 1.804 + AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing); 1.805 + mIsDrawing = true; 1.806 + 1.807 + float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f 1.808 + : mSVGDocumentWrapper->GetCurrentTime(); 1.809 + AutoSVGRenderingState autoSVGState(aSVGContext, animTime, 1.810 + mSVGDocumentWrapper->GetRootSVGElem()); 1.811 + 1.812 + // Pack up the drawing parameters. 1.813 + SVGDrawingParameters params(aContext, aFilter, aUserSpaceToImageSpace, aFill, 1.814 + aSubimage, aViewportSize, aSVGContext, animTime, aFlags); 1.815 + 1.816 + // Check the cache. 1.817 + nsRefPtr<gfxDrawable> drawable = 1.818 + SurfaceCache::Lookup(ImageKey(this), 1.819 + SurfaceKey(params.imageRect.Size(), params.scale, 1.820 + aSVGContext, animTime, aFlags)); 1.821 + 1.822 + // Draw. 1.823 + if (drawable) { 1.824 + Show(drawable, params); 1.825 + } else { 1.826 + CreateDrawableAndShow(params); 1.827 + } 1.828 + 1.829 + return NS_OK; 1.830 +} 1.831 + 1.832 +void 1.833 +VectorImage::CreateDrawableAndShow(const SVGDrawingParameters& aParams) 1.834 +{ 1.835 + mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize); 1.836 + mSVGDocumentWrapper->FlushImageTransformInvalidation(); 1.837 + 1.838 + nsRefPtr<gfxDrawingCallback> cb = 1.839 + new SVGDrawingCallback(mSVGDocumentWrapper, 1.840 + nsIntRect(nsIntPoint(0, 0), aParams.viewportSize), 1.841 + aParams.scale, 1.842 + aParams.flags); 1.843 + 1.844 + nsRefPtr<gfxDrawable> svgDrawable = 1.845 + new gfxCallbackDrawable(cb, ThebesIntSize(aParams.imageRect.Size())); 1.846 + 1.847 + // Refuse to cache animated images. 1.848 + // XXX(seth): We may remove this restriction in bug 922893. 1.849 + if (mHaveAnimations) 1.850 + return Show(svgDrawable, aParams); 1.851 + 1.852 + // If the image is too big to fit in the cache, don't go any further. 1.853 + if (!SurfaceCache::CanHold(aParams.imageRect.Size())) 1.854 + return Show(svgDrawable, aParams); 1.855 + 1.856 + // Try to create an offscreen surface. 1.857 + mozilla::RefPtr<mozilla::gfx::DrawTarget> target = 1.858 + gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aParams.imageRect.Size(), gfx::SurfaceFormat::B8G8R8A8); 1.859 + 1.860 + // If we couldn't create the draw target, it was probably because it would end 1.861 + // up way too big. Generally it also wouldn't fit in the cache, but the prefs 1.862 + // could be set such that the cache isn't the limiting factor. 1.863 + if (!target) 1.864 + return Show(svgDrawable, aParams); 1.865 + 1.866 + nsRefPtr<gfxContext> ctx = new gfxContext(target); 1.867 + 1.868 + // Actually draw. (We use FILTER_NEAREST since we never scale here.) 1.869 + gfxUtils::DrawPixelSnapped(ctx, svgDrawable, gfxMatrix(), 1.870 + ThebesIntRect(aParams.imageRect), 1.871 + ThebesIntRect(aParams.imageRect), 1.872 + ThebesIntRect(aParams.imageRect), 1.873 + ThebesIntRect(aParams.imageRect), 1.874 + gfxImageFormat::ARGB32, 1.875 + GraphicsFilter::FILTER_NEAREST, aParams.flags); 1.876 + 1.877 + // Attempt to cache the resulting surface. 1.878 + SurfaceCache::Insert(target, 1.879 + ImageKey(this), 1.880 + SurfaceKey(aParams.imageRect.Size(), aParams.scale, 1.881 + aParams.svgContext, aParams.animationTime, 1.882 + aParams.flags)); 1.883 + 1.884 + // Draw. Note that if SurfaceCache::Insert failed for whatever reason, 1.885 + // then |target| is all that is keeping the pixel data alive, so we have 1.886 + // to draw before returning from this function. 1.887 + nsRefPtr<gfxDrawable> drawable = 1.888 + new gfxSurfaceDrawable(target, ThebesIntSize(aParams.imageRect.Size())); 1.889 + Show(drawable, aParams); 1.890 +} 1.891 + 1.892 + 1.893 +void 1.894 +VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams) 1.895 +{ 1.896 + MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now"); 1.897 + gfxUtils::DrawPixelSnapped(aParams.context, aDrawable, 1.898 + aParams.userSpaceToImageSpace, 1.899 + aParams.subimage, aParams.sourceRect, 1.900 + ThebesIntRect(aParams.imageRect), aParams.fill, 1.901 + gfxImageFormat::ARGB32, 1.902 + aParams.filter, aParams.flags); 1.903 + 1.904 + MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now"); 1.905 + mRenderingObserver->ResumeHonoringInvalidations(); 1.906 +} 1.907 + 1.908 +//****************************************************************************** 1.909 +/* void requestDecode() */ 1.910 +NS_IMETHODIMP 1.911 +VectorImage::RequestDecode() 1.912 +{ 1.913 + // Nothing to do for SVG images 1.914 + return NS_OK; 1.915 +} 1.916 + 1.917 +NS_IMETHODIMP 1.918 +VectorImage::StartDecoding() 1.919 +{ 1.920 + // Nothing to do for SVG images 1.921 + return NS_OK; 1.922 +} 1.923 + 1.924 +bool 1.925 +VectorImage::IsDecoded() 1.926 +{ 1.927 + return mIsFullyLoaded || mError; 1.928 +} 1.929 + 1.930 +//****************************************************************************** 1.931 +/* void lockImage() */ 1.932 +NS_IMETHODIMP 1.933 +VectorImage::LockImage() 1.934 +{ 1.935 + // This method is for image-discarding, which only applies to RasterImages. 1.936 + return NS_OK; 1.937 +} 1.938 + 1.939 +//****************************************************************************** 1.940 +/* void unlockImage() */ 1.941 +NS_IMETHODIMP 1.942 +VectorImage::UnlockImage() 1.943 +{ 1.944 + // This method is for image-discarding, which only applies to RasterImages. 1.945 + return NS_OK; 1.946 +} 1.947 + 1.948 +//****************************************************************************** 1.949 +/* void requestDiscard() */ 1.950 +NS_IMETHODIMP 1.951 +VectorImage::RequestDiscard() 1.952 +{ 1.953 + SurfaceCache::Discard(this); 1.954 + return NS_OK; 1.955 +} 1.956 + 1.957 +//****************************************************************************** 1.958 +/* void resetAnimation (); */ 1.959 +NS_IMETHODIMP 1.960 +VectorImage::ResetAnimation() 1.961 +{ 1.962 + if (mError) 1.963 + return NS_ERROR_FAILURE; 1.964 + 1.965 + if (!mIsFullyLoaded || !mHaveAnimations) { 1.966 + return NS_OK; // There are no animations to be reset. 1.967 + } 1.968 + 1.969 + mSVGDocumentWrapper->ResetAnimation(); 1.970 + 1.971 + return NS_OK; 1.972 +} 1.973 + 1.974 +NS_IMETHODIMP_(float) 1.975 +VectorImage::GetFrameIndex(uint32_t aWhichFrame) 1.976 +{ 1.977 + MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument"); 1.978 + return aWhichFrame == FRAME_FIRST 1.979 + ? 0.0f 1.980 + : mSVGDocumentWrapper->GetCurrentTime(); 1.981 +} 1.982 + 1.983 +//------------------------------------------------------------------------------ 1.984 +// nsIRequestObserver methods 1.985 + 1.986 +//****************************************************************************** 1.987 +/* void onStartRequest(in nsIRequest request, in nsISupports ctxt); */ 1.988 +NS_IMETHODIMP 1.989 +VectorImage::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt) 1.990 +{ 1.991 + MOZ_ASSERT(!mSVGDocumentWrapper, 1.992 + "Repeated call to OnStartRequest -- can this happen?"); 1.993 + 1.994 + mSVGDocumentWrapper = new SVGDocumentWrapper(); 1.995 + nsresult rv = mSVGDocumentWrapper->OnStartRequest(aRequest, aCtxt); 1.996 + if (NS_FAILED(rv)) { 1.997 + mSVGDocumentWrapper = nullptr; 1.998 + mError = true; 1.999 + return rv; 1.1000 + } 1.1001 + 1.1002 + // Sending StartDecode will block page load until the document's ready. (We 1.1003 + // unblock it by sending StopDecode in OnSVGDocumentLoaded or 1.1004 + // OnSVGDocumentError.) 1.1005 + if (mStatusTracker) { 1.1006 + nsRefPtr<imgStatusTracker> clone = mStatusTracker->CloneForRecording(); 1.1007 + imgDecoderObserver* observer = clone->GetDecoderObserver(); 1.1008 + observer->OnStartDecode(); 1.1009 + ImageStatusDiff diff = mStatusTracker->Difference(clone); 1.1010 + mStatusTracker->ApplyDifference(diff); 1.1011 + mStatusTracker->SyncNotifyDifference(diff); 1.1012 + } 1.1013 + 1.1014 + // Create a listener to wait until the SVG document is fully loaded, which 1.1015 + // will signal that this image is ready to render. Certain error conditions 1.1016 + // will prevent us from ever getting this notification, so we also create a 1.1017 + // listener that waits for parsing to complete and cancels the 1.1018 + // SVGLoadEventListener if needed. The listeners are automatically attached 1.1019 + // to the document by their constructors. 1.1020 + nsIDocument* document = mSVGDocumentWrapper->GetDocument(); 1.1021 + mLoadEventListener = new SVGLoadEventListener(document, this); 1.1022 + mParseCompleteListener = new SVGParseCompleteListener(document, this); 1.1023 + 1.1024 + return NS_OK; 1.1025 +} 1.1026 + 1.1027 +//****************************************************************************** 1.1028 +/* void onStopRequest(in nsIRequest request, in nsISupports ctxt, 1.1029 + in nsresult status); */ 1.1030 +NS_IMETHODIMP 1.1031 +VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, 1.1032 + nsresult aStatus) 1.1033 +{ 1.1034 + if (mError) 1.1035 + return NS_ERROR_FAILURE; 1.1036 + 1.1037 + return mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus); 1.1038 +} 1.1039 + 1.1040 +void 1.1041 +VectorImage::OnSVGDocumentParsed() 1.1042 +{ 1.1043 + MOZ_ASSERT(mParseCompleteListener, "Should have the parse complete listener"); 1.1044 + MOZ_ASSERT(mLoadEventListener, "Should have the load event listener"); 1.1045 + 1.1046 + if (!mSVGDocumentWrapper->GetRootSVGElem()) { 1.1047 + // This is an invalid SVG document. It may have failed to parse, or it may 1.1048 + // be missing the <svg> root element, or the <svg> root element may not 1.1049 + // declare the correct namespace. In any of these cases, we'll never be 1.1050 + // notified that the SVG finished loading, so we need to treat this as an error. 1.1051 + OnSVGDocumentError(); 1.1052 + } 1.1053 +} 1.1054 + 1.1055 +void 1.1056 +VectorImage::CancelAllListeners() 1.1057 +{ 1.1058 + if (mParseCompleteListener) { 1.1059 + mParseCompleteListener->Cancel(); 1.1060 + mParseCompleteListener = nullptr; 1.1061 + } 1.1062 + if (mLoadEventListener) { 1.1063 + mLoadEventListener->Cancel(); 1.1064 + mLoadEventListener = nullptr; 1.1065 + } 1.1066 +} 1.1067 + 1.1068 +void 1.1069 +VectorImage::OnSVGDocumentLoaded() 1.1070 +{ 1.1071 + MOZ_ASSERT(mSVGDocumentWrapper->GetRootSVGElem(), 1.1072 + "Should have parsed successfully"); 1.1073 + MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations, 1.1074 + "These flags shouldn't get set until OnSVGDocumentLoaded. " 1.1075 + "Duplicate calls to OnSVGDocumentLoaded?"); 1.1076 + 1.1077 + CancelAllListeners(); 1.1078 + 1.1079 + // XXX Flushing is wasteful if embedding frame hasn't had initial reflow. 1.1080 + mSVGDocumentWrapper->FlushLayout(); 1.1081 + 1.1082 + mIsFullyLoaded = true; 1.1083 + mHaveAnimations = mSVGDocumentWrapper->IsAnimated(); 1.1084 + 1.1085 + // Start listening to our image for rendering updates. 1.1086 + mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this); 1.1087 + 1.1088 + // Tell *our* observers that we're done loading. 1.1089 + if (mStatusTracker) { 1.1090 + nsRefPtr<imgStatusTracker> clone = mStatusTracker->CloneForRecording(); 1.1091 + imgDecoderObserver* observer = clone->GetDecoderObserver(); 1.1092 + 1.1093 + observer->OnStartContainer(); // Signal that width/height are available. 1.1094 + observer->FrameChanged(&nsIntRect::GetMaxSizedIntRect()); 1.1095 + observer->OnStopFrame(); 1.1096 + observer->OnStopDecode(NS_OK); // Unblock page load. 1.1097 + 1.1098 + ImageStatusDiff diff = mStatusTracker->Difference(clone); 1.1099 + mStatusTracker->ApplyDifference(diff); 1.1100 + mStatusTracker->SyncNotifyDifference(diff); 1.1101 + } 1.1102 + 1.1103 + EvaluateAnimation(); 1.1104 +} 1.1105 + 1.1106 +void 1.1107 +VectorImage::OnSVGDocumentError() 1.1108 +{ 1.1109 + CancelAllListeners(); 1.1110 + 1.1111 + // XXXdholbert Need to do something more for the parsing failed case -- right 1.1112 + // now, this just makes us draw the "object" icon, rather than the (jagged) 1.1113 + // "broken image" icon. See bug 594505. 1.1114 + mError = true; 1.1115 + 1.1116 + if (mStatusTracker) { 1.1117 + nsRefPtr<imgStatusTracker> clone = mStatusTracker->CloneForRecording(); 1.1118 + imgDecoderObserver* observer = clone->GetDecoderObserver(); 1.1119 + 1.1120 + // Unblock page load. 1.1121 + observer->OnStopDecode(NS_ERROR_FAILURE); 1.1122 + ImageStatusDiff diff = mStatusTracker->Difference(clone); 1.1123 + mStatusTracker->ApplyDifference(diff); 1.1124 + mStatusTracker->SyncNotifyDifference(diff); 1.1125 + } 1.1126 +} 1.1127 + 1.1128 +//------------------------------------------------------------------------------ 1.1129 +// nsIStreamListener method 1.1130 + 1.1131 +//****************************************************************************** 1.1132 +/* void onDataAvailable(in nsIRequest request, in nsISupports ctxt, 1.1133 + in nsIInputStream inStr, in unsigned long sourceOffset, 1.1134 + in unsigned long count); */ 1.1135 +NS_IMETHODIMP 1.1136 +VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt, 1.1137 + nsIInputStream* aInStr, uint64_t aSourceOffset, 1.1138 + uint32_t aCount) 1.1139 +{ 1.1140 + if (mError) 1.1141 + return NS_ERROR_FAILURE; 1.1142 + 1.1143 + return mSVGDocumentWrapper->OnDataAvailable(aRequest, aCtxt, aInStr, 1.1144 + aSourceOffset, aCount); 1.1145 +} 1.1146 + 1.1147 +// -------------------------- 1.1148 +// Invalidation helper method 1.1149 + 1.1150 +void 1.1151 +VectorImage::InvalidateObserversOnNextRefreshDriverTick() 1.1152 +{ 1.1153 + if (mHaveAnimations) { 1.1154 + mHasPendingInvalidation = true; 1.1155 + } else { 1.1156 + SendInvalidationNotifications(); 1.1157 + } 1.1158 +} 1.1159 + 1.1160 +} // namespace image 1.1161 +} // namespace mozilla