VectorImage.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "VectorImage.h"
  6. #include "gfx2DGlue.h"
  7. #include "gfxContext.h"
  8. #include "gfxDrawable.h"
  9. #include "gfxPlatform.h"
  10. #include "gfxPrefs.h" // for surface cache size
  11. #include "gfxUtils.h"
  12. #include "imgFrame.h"
  13. #include "mozilla/AutoRestore.h"
  14. #include "mozilla/MemoryReporting.h"
  15. #include "mozilla/dom/SVGSVGElement.h"
  16. #include "mozilla/gfx/2D.h"
  17. #include "mozilla/RefPtr.h"
  18. #include "nsIDOMEvent.h"
  19. #include "nsIPresShell.h"
  20. #include "nsIStreamListener.h"
  21. #include "nsMimeTypes.h"
  22. #include "nsPresContext.h"
  23. #include "nsRect.h"
  24. #include "nsString.h"
  25. #include "nsStubDocumentObserver.h"
  26. #include "nsSVGEffects.h" // for nsSVGRenderingObserver
  27. #include "nsWindowMemoryReporter.h"
  28. #include "ImageRegion.h"
  29. #include "ISurfaceProvider.h"
  30. #include "LookupResult.h"
  31. #include "Orientation.h"
  32. #include "SVGDocumentWrapper.h"
  33. #include "nsIDOMEventListener.h"
  34. #include "SurfaceCache.h"
  35. #include "nsDocument.h"
  36. // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
  37. #undef GetCurrentTime
  38. namespace mozilla {
  39. using namespace dom;
  40. using namespace gfx;
  41. using namespace layers;
  42. namespace image {
  43. // Helper-class: SVGRootRenderingObserver
  44. class SVGRootRenderingObserver final : public nsSVGRenderingObserver {
  45. public:
  46. NS_DECL_ISUPPORTS
  47. SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
  48. VectorImage* aVectorImage)
  49. : nsSVGRenderingObserver()
  50. , mDocWrapper(aDocWrapper)
  51. , mVectorImage(aVectorImage)
  52. , mHonoringInvalidations(true)
  53. {
  54. MOZ_ASSERT(mDocWrapper, "Need a non-null SVG document wrapper");
  55. MOZ_ASSERT(mVectorImage, "Need a non-null VectorImage");
  56. StartListening();
  57. Element* elem = GetTarget();
  58. MOZ_ASSERT(elem, "no root SVG node for us to observe");
  59. nsSVGEffects::AddRenderingObserver(elem, this);
  60. mInObserverList = true;
  61. }
  62. void ResumeHonoringInvalidations()
  63. {
  64. mHonoringInvalidations = true;
  65. }
  66. protected:
  67. virtual ~SVGRootRenderingObserver()
  68. {
  69. StopListening();
  70. }
  71. virtual Element* GetTarget() override
  72. {
  73. return mDocWrapper->GetRootSVGElem();
  74. }
  75. virtual void DoUpdate() override
  76. {
  77. Element* elem = GetTarget();
  78. MOZ_ASSERT(elem, "missing root SVG node");
  79. if (mHonoringInvalidations && !mDocWrapper->ShouldIgnoreInvalidation()) {
  80. nsIFrame* frame = elem->GetPrimaryFrame();
  81. if (!frame || frame->PresContext()->PresShell()->IsDestroying()) {
  82. // We're being destroyed. Bail out.
  83. return;
  84. }
  85. // Ignore further invalidations until we draw.
  86. mHonoringInvalidations = false;
  87. mVectorImage->InvalidateObserversOnNextRefreshDriverTick();
  88. }
  89. // Our caller might've removed us from rendering-observer list.
  90. // Add ourselves back!
  91. if (!mInObserverList) {
  92. nsSVGEffects::AddRenderingObserver(elem, this);
  93. mInObserverList = true;
  94. }
  95. }
  96. // Private data
  97. const RefPtr<SVGDocumentWrapper> mDocWrapper;
  98. VectorImage* const mVectorImage; // Raw pointer because it owns me.
  99. bool mHonoringInvalidations;
  100. };
  101. NS_IMPL_ISUPPORTS(SVGRootRenderingObserver, nsIMutationObserver)
  102. class SVGParseCompleteListener final : public nsStubDocumentObserver {
  103. public:
  104. NS_DECL_ISUPPORTS
  105. SVGParseCompleteListener(nsIDocument* aDocument,
  106. VectorImage* aImage)
  107. : mDocument(aDocument)
  108. , mImage(aImage)
  109. {
  110. MOZ_ASSERT(mDocument, "Need an SVG document");
  111. MOZ_ASSERT(mImage, "Need an image");
  112. mDocument->AddObserver(this);
  113. }
  114. private:
  115. ~SVGParseCompleteListener()
  116. {
  117. if (mDocument) {
  118. // The document must have been destroyed before we got our event.
  119. // Otherwise this can't happen, since documents hold strong references to
  120. // their observers.
  121. Cancel();
  122. }
  123. }
  124. public:
  125. void EndLoad(nsIDocument* aDocument) override
  126. {
  127. MOZ_ASSERT(aDocument == mDocument, "Got EndLoad for wrong document?");
  128. // OnSVGDocumentParsed will release our owner's reference to us, so ensure
  129. // we stick around long enough to complete our work.
  130. RefPtr<SVGParseCompleteListener> kungFuDeathGrip(this);
  131. mImage->OnSVGDocumentParsed();
  132. }
  133. void Cancel()
  134. {
  135. MOZ_ASSERT(mDocument, "Duplicate call to Cancel");
  136. if (mDocument) {
  137. mDocument->RemoveObserver(this);
  138. mDocument = nullptr;
  139. }
  140. }
  141. private:
  142. nsCOMPtr<nsIDocument> mDocument;
  143. VectorImage* const mImage; // Raw pointer to owner.
  144. };
  145. NS_IMPL_ISUPPORTS(SVGParseCompleteListener, nsIDocumentObserver)
  146. class SVGLoadEventListener final : public nsIDOMEventListener {
  147. public:
  148. NS_DECL_ISUPPORTS
  149. SVGLoadEventListener(nsIDocument* aDocument,
  150. VectorImage* aImage)
  151. : mDocument(aDocument)
  152. , mImage(aImage)
  153. {
  154. MOZ_ASSERT(mDocument, "Need an SVG document");
  155. MOZ_ASSERT(mImage, "Need an image");
  156. mDocument->AddEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
  157. this, true, false);
  158. mDocument->AddEventListener(NS_LITERAL_STRING("SVGAbort"), this, true,
  159. false);
  160. mDocument->AddEventListener(NS_LITERAL_STRING("SVGError"), this, true,
  161. false);
  162. }
  163. private:
  164. ~SVGLoadEventListener()
  165. {
  166. if (mDocument) {
  167. // The document must have been destroyed before we got our event.
  168. // Otherwise this can't happen, since documents hold strong references to
  169. // their observers.
  170. Cancel();
  171. }
  172. }
  173. public:
  174. NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
  175. {
  176. MOZ_ASSERT(mDocument, "Need an SVG document. Received multiple events?");
  177. // OnSVGDocumentLoaded/OnSVGDocumentError will release our owner's reference
  178. // to us, so ensure we stick around long enough to complete our work.
  179. RefPtr<SVGLoadEventListener> kungFuDeathGrip(this);
  180. nsAutoString eventType;
  181. aEvent->GetType(eventType);
  182. MOZ_ASSERT(eventType.EqualsLiteral("MozSVGAsImageDocumentLoad") ||
  183. eventType.EqualsLiteral("SVGAbort") ||
  184. eventType.EqualsLiteral("SVGError"),
  185. "Received unexpected event");
  186. if (eventType.EqualsLiteral("MozSVGAsImageDocumentLoad")) {
  187. mImage->OnSVGDocumentLoaded();
  188. } else {
  189. mImage->OnSVGDocumentError();
  190. }
  191. return NS_OK;
  192. }
  193. void Cancel()
  194. {
  195. MOZ_ASSERT(mDocument, "Duplicate call to Cancel");
  196. if (mDocument) {
  197. mDocument
  198. ->RemoveEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
  199. this, true);
  200. mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGAbort"), this, true);
  201. mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGError"), this, true);
  202. mDocument = nullptr;
  203. }
  204. }
  205. private:
  206. nsCOMPtr<nsIDocument> mDocument;
  207. VectorImage* const mImage; // Raw pointer to owner.
  208. };
  209. NS_IMPL_ISUPPORTS(SVGLoadEventListener, nsIDOMEventListener)
  210. // Helper-class: SVGDrawingCallback
  211. class SVGDrawingCallback : public gfxDrawingCallback {
  212. public:
  213. SVGDrawingCallback(SVGDocumentWrapper* aSVGDocumentWrapper,
  214. const IntRect& aViewport,
  215. const IntSize& aSize,
  216. uint32_t aImageFlags)
  217. : mSVGDocumentWrapper(aSVGDocumentWrapper)
  218. , mViewport(aViewport)
  219. , mSize(aSize)
  220. , mImageFlags(aImageFlags)
  221. { }
  222. virtual bool operator()(gfxContext* aContext,
  223. const gfxRect& aFillRect,
  224. const SamplingFilter aSamplingFilter,
  225. const gfxMatrix& aTransform);
  226. private:
  227. RefPtr<SVGDocumentWrapper> mSVGDocumentWrapper;
  228. const IntRect mViewport;
  229. const IntSize mSize;
  230. uint32_t mImageFlags;
  231. };
  232. // Based loosely on nsSVGIntegrationUtils' PaintFrameCallback::operator()
  233. bool
  234. SVGDrawingCallback::operator()(gfxContext* aContext,
  235. const gfxRect& aFillRect,
  236. const SamplingFilter aSamplingFilter,
  237. const gfxMatrix& aTransform)
  238. {
  239. MOZ_ASSERT(mSVGDocumentWrapper, "need an SVGDocumentWrapper");
  240. // Get (& sanity-check) the helper-doc's presShell
  241. nsCOMPtr<nsIPresShell> presShell;
  242. if (NS_FAILED(mSVGDocumentWrapper->GetPresShell(getter_AddRefs(presShell)))) {
  243. NS_WARNING("Unable to draw -- presShell lookup failed");
  244. return false;
  245. }
  246. MOZ_ASSERT(presShell, "GetPresShell succeeded but returned null");
  247. gfxContextAutoSaveRestore contextRestorer(aContext);
  248. // Clip to aFillRect so that we don't paint outside.
  249. aContext->NewPath();
  250. aContext->Rectangle(aFillRect);
  251. aContext->Clip();
  252. gfxMatrix matrix = aTransform;
  253. if (!matrix.Invert()) {
  254. return false;
  255. }
  256. aContext->SetMatrix(
  257. aContext->CurrentMatrix().PreMultiply(matrix).
  258. Scale(double(mSize.width) / mViewport.width,
  259. double(mSize.height) / mViewport.height));
  260. nsPresContext* presContext = presShell->GetPresContext();
  261. MOZ_ASSERT(presContext, "pres shell w/out pres context");
  262. nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
  263. presContext->DevPixelsToAppUnits(mViewport.y),
  264. presContext->DevPixelsToAppUnits(mViewport.width),
  265. presContext->DevPixelsToAppUnits(mViewport.height));
  266. uint32_t renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
  267. if (!(mImageFlags & imgIContainer::FLAG_SYNC_DECODE)) {
  268. renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES;
  269. }
  270. presShell->RenderDocument(svgRect, renderDocFlags,
  271. NS_RGBA(0, 0, 0, 0), // transparent
  272. aContext);
  273. return true;
  274. }
  275. // Implement VectorImage's nsISupports-inherited methods
  276. NS_IMPL_ISUPPORTS(VectorImage,
  277. imgIContainer,
  278. nsIStreamListener,
  279. nsIRequestObserver)
  280. //------------------------------------------------------------------------------
  281. // Constructor / Destructor
  282. VectorImage::VectorImage(ImageURL* aURI /* = nullptr */) :
  283. ImageResource(aURI), // invoke superclass's constructor
  284. mLockCount(0),
  285. mIsInitialized(false),
  286. mIsFullyLoaded(false),
  287. mIsDrawing(false),
  288. mHaveAnimations(false),
  289. mHasPendingInvalidation(false)
  290. { }
  291. VectorImage::~VectorImage()
  292. {
  293. CancelAllListeners();
  294. SurfaceCache::RemoveImage(ImageKey(this));
  295. }
  296. //------------------------------------------------------------------------------
  297. // Methods inherited from Image.h
  298. nsresult
  299. VectorImage::Init(const char* aMimeType,
  300. uint32_t aFlags)
  301. {
  302. // We don't support re-initialization
  303. if (mIsInitialized) {
  304. return NS_ERROR_ILLEGAL_VALUE;
  305. }
  306. MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations && !mError,
  307. "Flags unexpectedly set before initialization");
  308. MOZ_ASSERT(!strcmp(aMimeType, IMAGE_SVG_XML), "Unexpected mimetype");
  309. mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
  310. // Lock this image's surfaces in the SurfaceCache if we're not discardable.
  311. if (!mDiscardable) {
  312. mLockCount++;
  313. SurfaceCache::LockImage(ImageKey(this));
  314. }
  315. mIsInitialized = true;
  316. return NS_OK;
  317. }
  318. size_t
  319. VectorImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
  320. {
  321. if (!mSVGDocumentWrapper) {
  322. return 0; // No document, so no memory used for the document.
  323. }
  324. nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
  325. if (!doc) {
  326. return 0; // No document, so no memory used for the document.
  327. }
  328. nsWindowSizes windowSizes(aMallocSizeOf);
  329. doc->DocAddSizeOfIncludingThis(&windowSizes);
  330. if (windowSizes.getTotalSize() == 0) {
  331. // MallocSizeOf fails on this platform. Because we also use this method for
  332. // determining the size of cache entries, we need to return something
  333. // reasonable here. Unfortunately, there's no way to estimate the document's
  334. // size accurately, so we just use a constant value of 100KB, which will
  335. // generally underestimate the true size.
  336. return 100 * 1024;
  337. }
  338. return windowSizes.getTotalSize();
  339. }
  340. void
  341. VectorImage::CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
  342. MallocSizeOf aMallocSizeOf) const
  343. {
  344. SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
  345. }
  346. nsresult
  347. VectorImage::OnImageDataComplete(nsIRequest* aRequest,
  348. nsISupports* aContext,
  349. nsresult aStatus,
  350. bool aLastPart)
  351. {
  352. // Call our internal OnStopRequest method, which only talks to our embedded
  353. // SVG document. This won't have any effect on our ProgressTracker.
  354. nsresult finalStatus = OnStopRequest(aRequest, aContext, aStatus);
  355. // Give precedence to Necko failure codes.
  356. if (NS_FAILED(aStatus)) {
  357. finalStatus = aStatus;
  358. }
  359. Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus);
  360. if (mIsFullyLoaded || mError) {
  361. // Our document is loaded, so we're ready to notify now.
  362. mProgressTracker->SyncNotifyProgress(loadProgress);
  363. } else {
  364. // Record our progress so far; we'll actually send the notifications in
  365. // OnSVGDocumentLoaded or OnSVGDocumentError.
  366. mLoadProgress = Some(loadProgress);
  367. }
  368. return finalStatus;
  369. }
  370. nsresult
  371. VectorImage::OnImageDataAvailable(nsIRequest* aRequest,
  372. nsISupports* aContext,
  373. nsIInputStream* aInStr,
  374. uint64_t aSourceOffset,
  375. uint32_t aCount)
  376. {
  377. return OnDataAvailable(aRequest, aContext, aInStr, aSourceOffset, aCount);
  378. }
  379. nsresult
  380. VectorImage::StartAnimation()
  381. {
  382. if (mError) {
  383. return NS_ERROR_FAILURE;
  384. }
  385. MOZ_ASSERT(ShouldAnimate(), "Should not animate!");
  386. mSVGDocumentWrapper->StartAnimation();
  387. return NS_OK;
  388. }
  389. nsresult
  390. VectorImage::StopAnimation()
  391. {
  392. nsresult rv = NS_OK;
  393. if (mError) {
  394. rv = NS_ERROR_FAILURE;
  395. } else {
  396. MOZ_ASSERT(mIsFullyLoaded && mHaveAnimations,
  397. "Should not have been animating!");
  398. mSVGDocumentWrapper->StopAnimation();
  399. }
  400. mAnimating = false;
  401. return rv;
  402. }
  403. bool
  404. VectorImage::ShouldAnimate()
  405. {
  406. return ImageResource::ShouldAnimate() && mIsFullyLoaded && mHaveAnimations;
  407. }
  408. NS_IMETHODIMP_(void)
  409. VectorImage::SetAnimationStartTime(const TimeStamp& aTime)
  410. {
  411. // We don't care about animation start time.
  412. }
  413. //------------------------------------------------------------------------------
  414. // imgIContainer methods
  415. //******************************************************************************
  416. NS_IMETHODIMP
  417. VectorImage::GetWidth(int32_t* aWidth)
  418. {
  419. if (mError || !mIsFullyLoaded) {
  420. // XXXdholbert Technically we should leave outparam untouched when we
  421. // fail. But since many callers don't check for failure, we set it to 0 on
  422. // failure, for sane/predictable results.
  423. *aWidth = 0;
  424. return NS_ERROR_FAILURE;
  425. }
  426. SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
  427. MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
  428. "loading without errors");
  429. int32_t rootElemWidth = rootElem->GetIntrinsicWidth();
  430. if (rootElemWidth < 0) {
  431. *aWidth = 0;
  432. return NS_ERROR_FAILURE;
  433. }
  434. *aWidth = rootElemWidth;
  435. return NS_OK;
  436. }
  437. //******************************************************************************
  438. NS_IMETHODIMP_(void)
  439. VectorImage::RequestRefresh(const TimeStamp& aTime)
  440. {
  441. if (HadRecentRefresh(aTime)) {
  442. return;
  443. }
  444. PendingAnimationTracker* tracker =
  445. mSVGDocumentWrapper->GetDocument()->GetPendingAnimationTracker();
  446. if (tracker && ShouldAnimate()) {
  447. tracker->TriggerPendingAnimationsOnNextTick(aTime);
  448. }
  449. EvaluateAnimation();
  450. mSVGDocumentWrapper->TickRefreshDriver();
  451. if (mHasPendingInvalidation) {
  452. mHasPendingInvalidation = false;
  453. SendInvalidationNotifications();
  454. }
  455. }
  456. void
  457. VectorImage::SendInvalidationNotifications()
  458. {
  459. // Animated images don't send out invalidation notifications as soon as
  460. // they're generated. Instead, InvalidateObserversOnNextRefreshDriverTick
  461. // records that there are pending invalidations and then returns immediately.
  462. // The notifications are actually sent from RequestRefresh(). We send these
  463. // notifications there to ensure that there is actually a document observing
  464. // us. Otherwise, the notifications are just wasted effort.
  465. //
  466. // Non-animated images call this method directly from
  467. // InvalidateObserversOnNextRefreshDriverTick, because RequestRefresh is never
  468. // called for them. Ordinarily this isn't needed, since we send out
  469. // invalidation notifications in OnSVGDocumentLoaded, but in rare cases the
  470. // SVG document may not be 100% ready to render at that time. In those cases
  471. // we would miss the subsequent invalidations if we didn't send out the
  472. // notifications directly in |InvalidateObservers...|.
  473. if (mProgressTracker) {
  474. SurfaceCache::RemoveImage(ImageKey(this));
  475. mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE,
  476. GetMaxSizedIntRect());
  477. }
  478. }
  479. NS_IMETHODIMP_(IntRect)
  480. VectorImage::GetImageSpaceInvalidationRect(const IntRect& aRect)
  481. {
  482. return aRect;
  483. }
  484. //******************************************************************************
  485. NS_IMETHODIMP
  486. VectorImage::GetHeight(int32_t* aHeight)
  487. {
  488. if (mError || !mIsFullyLoaded) {
  489. // XXXdholbert Technically we should leave outparam untouched when we
  490. // fail. But since many callers don't check for failure, we set it to 0 on
  491. // failure, for sane/predictable results.
  492. *aHeight = 0;
  493. return NS_ERROR_FAILURE;
  494. }
  495. SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
  496. MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
  497. "loading without errors");
  498. int32_t rootElemHeight = rootElem->GetIntrinsicHeight();
  499. if (rootElemHeight < 0) {
  500. *aHeight = 0;
  501. return NS_ERROR_FAILURE;
  502. }
  503. *aHeight = rootElemHeight;
  504. return NS_OK;
  505. }
  506. //******************************************************************************
  507. NS_IMETHODIMP
  508. VectorImage::GetIntrinsicSize(nsSize* aSize)
  509. {
  510. if (mError || !mIsFullyLoaded) {
  511. return NS_ERROR_FAILURE;
  512. }
  513. nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame();
  514. if (!rootFrame) {
  515. return NS_ERROR_FAILURE;
  516. }
  517. *aSize = nsSize(-1, -1);
  518. IntrinsicSize rfSize = rootFrame->GetIntrinsicSize();
  519. if (rfSize.width.GetUnit() == eStyleUnit_Coord) {
  520. aSize->width = rfSize.width.GetCoordValue();
  521. }
  522. if (rfSize.height.GetUnit() == eStyleUnit_Coord) {
  523. aSize->height = rfSize.height.GetCoordValue();
  524. }
  525. return NS_OK;
  526. }
  527. //******************************************************************************
  528. NS_IMETHODIMP
  529. VectorImage::GetIntrinsicRatio(AspectRatio* aRatio)
  530. {
  531. if (mError || !mIsFullyLoaded) {
  532. return NS_ERROR_FAILURE;
  533. }
  534. nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame();
  535. if (!rootFrame) {
  536. return NS_ERROR_FAILURE;
  537. }
  538. *aRatio = rootFrame->GetIntrinsicRatio();
  539. return NS_OK;
  540. }
  541. NS_IMETHODIMP_(Orientation)
  542. VectorImage::GetOrientation()
  543. {
  544. return Orientation();
  545. }
  546. //******************************************************************************
  547. NS_IMETHODIMP
  548. VectorImage::GetType(uint16_t* aType)
  549. {
  550. NS_ENSURE_ARG_POINTER(aType);
  551. *aType = imgIContainer::TYPE_VECTOR;
  552. return NS_OK;
  553. }
  554. //******************************************************************************
  555. NS_IMETHODIMP
  556. VectorImage::GetAnimated(bool* aAnimated)
  557. {
  558. if (mError || !mIsFullyLoaded) {
  559. return NS_ERROR_FAILURE;
  560. }
  561. *aAnimated = mSVGDocumentWrapper->IsAnimated();
  562. return NS_OK;
  563. }
  564. //******************************************************************************
  565. int32_t
  566. VectorImage::GetFirstFrameDelay()
  567. {
  568. if (mError) {
  569. return -1;
  570. }
  571. if (!mSVGDocumentWrapper->IsAnimated()) {
  572. return -1;
  573. }
  574. // We don't really have a frame delay, so just pretend that we constantly
  575. // need updates.
  576. return 0;
  577. }
  578. NS_IMETHODIMP_(bool)
  579. VectorImage::WillDrawOpaqueNow()
  580. {
  581. return false; // In general, SVG content is not opaque.
  582. }
  583. //******************************************************************************
  584. NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
  585. VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags)
  586. {
  587. if (mError) {
  588. return nullptr;
  589. }
  590. // Look up height & width
  591. // ----------------------
  592. SVGSVGElement* svgElem = mSVGDocumentWrapper->GetRootSVGElem();
  593. MOZ_ASSERT(svgElem, "Should have a root SVG elem, since we finished "
  594. "loading without errors");
  595. nsIntSize imageIntSize(svgElem->GetIntrinsicWidth(),
  596. svgElem->GetIntrinsicHeight());
  597. if (imageIntSize.IsEmpty()) {
  598. // We'll get here if our SVG doc has a percent-valued or negative width or
  599. // height.
  600. return nullptr;
  601. }
  602. return GetFrameAtSize(imageIntSize, aWhichFrame, aFlags);
  603. }
  604. NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
  605. VectorImage::GetFrameAtSize(const IntSize& aSize,
  606. uint32_t aWhichFrame,
  607. uint32_t aFlags)
  608. {
  609. MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
  610. if (aSize.IsEmpty()) {
  611. return nullptr;
  612. }
  613. if (aWhichFrame > FRAME_MAX_VALUE) {
  614. return nullptr;
  615. }
  616. if (mError || !mIsFullyLoaded) {
  617. return nullptr;
  618. }
  619. // Make our surface the size of what will ultimately be drawn to it.
  620. // (either the full image size, or the restricted region)
  621. RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
  622. CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
  623. if (!dt || !dt->IsValid()) {
  624. NS_ERROR("Could not create a DrawTarget");
  625. return nullptr;
  626. }
  627. RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
  628. MOZ_ASSERT(context); // already checked the draw target above
  629. auto result = Draw(context, aSize, ImageRegion::Create(aSize),
  630. aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags);
  631. return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
  632. }
  633. NS_IMETHODIMP_(bool)
  634. VectorImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
  635. {
  636. return false;
  637. }
  638. //******************************************************************************
  639. NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
  640. VectorImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
  641. {
  642. return nullptr;
  643. }
  644. struct SVGDrawingParameters
  645. {
  646. SVGDrawingParameters(gfxContext* aContext,
  647. const nsIntSize& aSize,
  648. const ImageRegion& aRegion,
  649. SamplingFilter aSamplingFilter,
  650. const Maybe<SVGImageContext>& aSVGContext,
  651. float aAnimationTime,
  652. uint32_t aFlags)
  653. : context(aContext)
  654. , size(aSize.width, aSize.height)
  655. , region(aRegion)
  656. , samplingFilter(aSamplingFilter)
  657. , svgContext(aSVGContext)
  658. , viewportSize(aSize)
  659. , animationTime(aAnimationTime)
  660. , flags(aFlags)
  661. , opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0)
  662. {
  663. if (aSVGContext) {
  664. CSSIntSize sz = aSVGContext->GetViewportSize();
  665. viewportSize = nsIntSize(sz.width, sz.height); // XXX losing unit
  666. }
  667. }
  668. gfxContext* context;
  669. IntSize size;
  670. ImageRegion region;
  671. SamplingFilter samplingFilter;
  672. const Maybe<SVGImageContext>& svgContext;
  673. nsIntSize viewportSize;
  674. float animationTime;
  675. uint32_t flags;
  676. gfxFloat opacity;
  677. };
  678. //******************************************************************************
  679. NS_IMETHODIMP_(DrawResult)
  680. VectorImage::Draw(gfxContext* aContext,
  681. const nsIntSize& aSize,
  682. const ImageRegion& aRegion,
  683. uint32_t aWhichFrame,
  684. SamplingFilter aSamplingFilter,
  685. const Maybe<SVGImageContext>& aSVGContext,
  686. uint32_t aFlags)
  687. {
  688. if (aWhichFrame > FRAME_MAX_VALUE) {
  689. return DrawResult::BAD_ARGS;
  690. }
  691. if (!aContext) {
  692. return DrawResult::BAD_ARGS;
  693. }
  694. if (mError) {
  695. return DrawResult::BAD_IMAGE;
  696. }
  697. if (!mIsFullyLoaded) {
  698. return DrawResult::NOT_READY;
  699. }
  700. if (mIsDrawing) {
  701. NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
  702. return DrawResult::TEMPORARY_ERROR;
  703. }
  704. if (mAnimationConsumers == 0 && mProgressTracker) {
  705. mProgressTracker->OnUnlockedDraw();
  706. }
  707. AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);
  708. mIsDrawing = true;
  709. Maybe<SVGImageContext> svgContext;
  710. // If FLAG_FORCE_PRESERVEASPECTRATIO_NONE bit is set, that mean we should
  711. // overwrite SVG preserveAspectRatio attibute of this image with none, and
  712. // always stretch this image to viewport non-uniformly.
  713. // And we can do this only if the caller pass in the the SVG viewport, via
  714. // aSVGContext.
  715. if ((aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext.isSome()) {
  716. Maybe<SVGPreserveAspectRatio> aspectRatio =
  717. Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE,
  718. SVG_MEETORSLICE_UNKNOWN));
  719. svgContext =
  720. Some(SVGImageContext(aSVGContext->GetViewportSize(),
  721. aspectRatio));
  722. } else {
  723. svgContext = aSVGContext;
  724. }
  725. float animTime =
  726. (aWhichFrame == FRAME_FIRST) ? 0.0f
  727. : mSVGDocumentWrapper->GetCurrentTime();
  728. AutoSVGRenderingState autoSVGState(svgContext, animTime,
  729. mSVGDocumentWrapper->GetRootSVGElem());
  730. SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter,
  731. svgContext, animTime, aFlags);
  732. // If we have an prerasterized version of this image that matches the
  733. // drawing parameters, use that.
  734. RefPtr<gfxDrawable> svgDrawable = LookupCachedSurface(params);
  735. if (svgDrawable) {
  736. Show(svgDrawable, params);
  737. return DrawResult::SUCCESS;
  738. }
  739. // We didn't get a hit in the surface cache, so we'll need to rerasterize.
  740. CreateSurfaceAndShow(params, aContext->GetDrawTarget()->GetBackendType());
  741. return DrawResult::SUCCESS;
  742. }
  743. already_AddRefed<gfxDrawable>
  744. VectorImage::LookupCachedSurface(const SVGDrawingParameters& aParams)
  745. {
  746. // If we're not allowed to use a cached surface, don't attempt a lookup.
  747. if (aParams.flags & FLAG_BYPASS_SURFACE_CACHE) {
  748. return nullptr;
  749. }
  750. // We don't do any caching if we have animation, so don't bother with a lookup
  751. // in this case either.
  752. if (mHaveAnimations) {
  753. return nullptr;
  754. }
  755. LookupResult result =
  756. SurfaceCache::Lookup(ImageKey(this),
  757. VectorSurfaceKey(aParams.size, aParams.svgContext));
  758. if (!result) {
  759. return nullptr; // No matching surface, or the OS freed the volatile buffer.
  760. }
  761. RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSourceSurface();
  762. if (!sourceSurface) {
  763. // Something went wrong. (Probably a GPU driver crash or device reset.)
  764. // Attempt to recover.
  765. RecoverFromLossOfSurfaces();
  766. return nullptr;
  767. }
  768. RefPtr<gfxDrawable> svgDrawable =
  769. new gfxSurfaceDrawable(sourceSurface, result.Surface()->GetSize());
  770. return svgDrawable.forget();
  771. }
  772. void
  773. VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams, BackendType aBackend)
  774. {
  775. mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize);
  776. mSVGDocumentWrapper->FlushImageTransformInvalidation();
  777. RefPtr<gfxDrawingCallback> cb =
  778. new SVGDrawingCallback(mSVGDocumentWrapper,
  779. IntRect(IntPoint(0, 0), aParams.viewportSize),
  780. aParams.size,
  781. aParams.flags);
  782. RefPtr<gfxDrawable> svgDrawable =
  783. new gfxCallbackDrawable(cb, aParams.size);
  784. // We take an early exit without using the surface cache if too large,
  785. // because for vector images this can cause bad perf issues if large sizes
  786. // are scaled repeatedly (a rather common scenario) that can quickly exhaust
  787. // the cache.
  788. // Similar to max image size calculations, this has a max cap and size check.
  789. // max cap = 8000 (pixels); size check = 5% of cache
  790. int32_t maxDimension = 8000;
  791. int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 20;
  792. bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) ||
  793. // Refuse to cache animated images:
  794. // XXX(seth): We may remove this restriction in bug 922893.
  795. mHaveAnimations ||
  796. // The image is too big to fit in the cache:
  797. !SurfaceCache::CanHold(aParams.size) ||
  798. // Image x or y is larger than our cache cap:
  799. aParams.size.width > maxDimension ||
  800. aParams.size.height > maxDimension;
  801. if (!bypassCache) {
  802. // This is separated out to make sure width and height are sane at this point
  803. // and the result can't overflow. Note: keep maxDimension low enough so that
  804. // (maxDimension)^2 x 4 < INT32_MAX.
  805. // Assuming surface size for any rendered vector image is RGBA, so 4Bpp.
  806. bypassCache = (aParams.size.width * aParams.size.height * 4) > maxCacheElemSize;
  807. }
  808. if (bypassCache) {
  809. return Show(svgDrawable, aParams);
  810. }
  811. // We're about to rerasterize, which may mean that some of the previous
  812. // surfaces we've rasterized aren't useful anymore. We can allow them to
  813. // expire from the cache by unlocking them here, and then sending out an
  814. // invalidation. If this image is locked, any surfaces that are still useful
  815. // will become locked again when Draw touches them, and the remainder will
  816. // eventually expire.
  817. SurfaceCache::UnlockEntries(ImageKey(this));
  818. // Try to create an imgFrame, initializing the surface it contains by drawing
  819. // our gfxDrawable into it. (We use FILTER_NEAREST since we never scale here.)
  820. NotNull<RefPtr<imgFrame>> frame = WrapNotNull(new imgFrame);
  821. nsresult rv =
  822. frame->InitWithDrawable(svgDrawable, aParams.size,
  823. SurfaceFormat::B8G8R8A8,
  824. SamplingFilter::POINT, aParams.flags,
  825. aBackend);
  826. // If we couldn't create the frame, it was probably because it would end
  827. // up way too big. Generally it also wouldn't fit in the cache, but the prefs
  828. // could be set such that the cache isn't the limiting factor.
  829. if (NS_FAILED(rv)) {
  830. return Show(svgDrawable, aParams);
  831. }
  832. // Take a strong reference to the frame's surface and make sure it hasn't
  833. // already been purged by the operating system.
  834. RefPtr<SourceSurface> surface = frame->GetSourceSurface();
  835. if (!surface) {
  836. return Show(svgDrawable, aParams);
  837. }
  838. // Attempt to cache the frame.
  839. SurfaceKey surfaceKey = VectorSurfaceKey(aParams.size, aParams.svgContext);
  840. NotNull<RefPtr<ISurfaceProvider>> provider =
  841. WrapNotNull(new SimpleSurfaceProvider(ImageKey(this), surfaceKey, frame));
  842. SurfaceCache::Insert(provider);
  843. // Draw.
  844. RefPtr<gfxDrawable> drawable =
  845. new gfxSurfaceDrawable(surface, aParams.size);
  846. Show(drawable, aParams);
  847. // Send out an invalidation so that surfaces that are still in use get
  848. // re-locked. See the discussion of the UnlockSurfaces call above.
  849. mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE,
  850. GetMaxSizedIntRect());
  851. }
  852. void
  853. VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
  854. {
  855. MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now");
  856. gfxUtils::DrawPixelSnapped(aParams.context, aDrawable,
  857. aParams.size,
  858. aParams.region,
  859. SurfaceFormat::B8G8R8A8,
  860. aParams.samplingFilter,
  861. aParams.flags, aParams.opacity);
  862. MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
  863. mRenderingObserver->ResumeHonoringInvalidations();
  864. }
  865. void
  866. VectorImage::RecoverFromLossOfSurfaces()
  867. {
  868. NS_WARNING("An imgFrame became invalid. Attempting to recover...");
  869. // Discard all existing frames, since they're probably all now invalid.
  870. SurfaceCache::RemoveImage(ImageKey(this));
  871. }
  872. NS_IMETHODIMP
  873. VectorImage::StartDecoding()
  874. {
  875. // Nothing to do for SVG images
  876. return NS_OK;
  877. }
  878. NS_IMETHODIMP
  879. VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
  880. {
  881. // Nothing to do for SVG images, though in theory we could rasterize to the
  882. // provided size ahead of time if we supported off-main-thread SVG
  883. // rasterization...
  884. return NS_OK;
  885. }
  886. //******************************************************************************
  887. NS_IMETHODIMP
  888. VectorImage::LockImage()
  889. {
  890. MOZ_ASSERT(NS_IsMainThread());
  891. if (mError) {
  892. return NS_ERROR_FAILURE;
  893. }
  894. mLockCount++;
  895. if (mLockCount == 1) {
  896. // Lock this image's surfaces in the SurfaceCache.
  897. SurfaceCache::LockImage(ImageKey(this));
  898. }
  899. return NS_OK;
  900. }
  901. //******************************************************************************
  902. NS_IMETHODIMP
  903. VectorImage::UnlockImage()
  904. {
  905. MOZ_ASSERT(NS_IsMainThread());
  906. if (mError) {
  907. return NS_ERROR_FAILURE;
  908. }
  909. if (mLockCount == 0) {
  910. MOZ_ASSERT_UNREACHABLE("Calling UnlockImage with a zero lock count");
  911. return NS_ERROR_ABORT;
  912. }
  913. mLockCount--;
  914. if (mLockCount == 0) {
  915. // Unlock this image's surfaces in the SurfaceCache.
  916. SurfaceCache::UnlockImage(ImageKey(this));
  917. }
  918. return NS_OK;
  919. }
  920. //******************************************************************************
  921. NS_IMETHODIMP
  922. VectorImage::RequestDiscard()
  923. {
  924. MOZ_ASSERT(NS_IsMainThread());
  925. if (mDiscardable && mLockCount == 0) {
  926. SurfaceCache::RemoveImage(ImageKey(this));
  927. mProgressTracker->OnDiscard();
  928. }
  929. return NS_OK;
  930. }
  931. void
  932. VectorImage::OnSurfaceDiscarded()
  933. {
  934. MOZ_ASSERT(mProgressTracker);
  935. NS_DispatchToMainThread(NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard));
  936. }
  937. //******************************************************************************
  938. NS_IMETHODIMP
  939. VectorImage::ResetAnimation()
  940. {
  941. if (mError) {
  942. return NS_ERROR_FAILURE;
  943. }
  944. if (!mIsFullyLoaded || !mHaveAnimations) {
  945. return NS_OK; // There are no animations to be reset.
  946. }
  947. mSVGDocumentWrapper->ResetAnimation();
  948. return NS_OK;
  949. }
  950. NS_IMETHODIMP_(float)
  951. VectorImage::GetFrameIndex(uint32_t aWhichFrame)
  952. {
  953. MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
  954. return aWhichFrame == FRAME_FIRST
  955. ? 0.0f
  956. : mSVGDocumentWrapper->GetCurrentTime();
  957. }
  958. //------------------------------------------------------------------------------
  959. // nsIRequestObserver methods
  960. //******************************************************************************
  961. NS_IMETHODIMP
  962. VectorImage::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
  963. {
  964. MOZ_ASSERT(!mSVGDocumentWrapper,
  965. "Repeated call to OnStartRequest -- can this happen?");
  966. mSVGDocumentWrapper = new SVGDocumentWrapper();
  967. nsresult rv = mSVGDocumentWrapper->OnStartRequest(aRequest, aCtxt);
  968. if (NS_FAILED(rv)) {
  969. mSVGDocumentWrapper = nullptr;
  970. mError = true;
  971. return rv;
  972. }
  973. // ProgressTracker::SyncNotifyProgress may release us, so ensure we
  974. // stick around long enough to complete our work.
  975. RefPtr<VectorImage> kungFuDeathGrip(this);
  976. // Block page load until the document's ready. (We unblock it in
  977. // OnSVGDocumentLoaded or OnSVGDocumentError.)
  978. if (mProgressTracker) {
  979. mProgressTracker->SyncNotifyProgress(FLAG_ONLOAD_BLOCKED);
  980. }
  981. // Create a listener to wait until the SVG document is fully loaded, which
  982. // will signal that this image is ready to render. Certain error conditions
  983. // will prevent us from ever getting this notification, so we also create a
  984. // listener that waits for parsing to complete and cancels the
  985. // SVGLoadEventListener if needed. The listeners are automatically attached
  986. // to the document by their constructors.
  987. nsIDocument* document = mSVGDocumentWrapper->GetDocument();
  988. mLoadEventListener = new SVGLoadEventListener(document, this);
  989. mParseCompleteListener = new SVGParseCompleteListener(document, this);
  990. return NS_OK;
  991. }
  992. //******************************************************************************
  993. NS_IMETHODIMP
  994. VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
  995. nsresult aStatus)
  996. {
  997. if (mError) {
  998. return NS_ERROR_FAILURE;
  999. }
  1000. return mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus);
  1001. }
  1002. void
  1003. VectorImage::OnSVGDocumentParsed()
  1004. {
  1005. MOZ_ASSERT(mParseCompleteListener, "Should have the parse complete listener");
  1006. MOZ_ASSERT(mLoadEventListener, "Should have the load event listener");
  1007. if (!mSVGDocumentWrapper->GetRootSVGElem()) {
  1008. // This is an invalid SVG document. It may have failed to parse, or it may
  1009. // be missing the <svg> root element, or the <svg> root element may not
  1010. // declare the correct namespace. In any of these cases, we'll never be
  1011. // notified that the SVG finished loading, so we need to treat this as an
  1012. // error.
  1013. OnSVGDocumentError();
  1014. }
  1015. }
  1016. void
  1017. VectorImage::CancelAllListeners()
  1018. {
  1019. if (mParseCompleteListener) {
  1020. mParseCompleteListener->Cancel();
  1021. mParseCompleteListener = nullptr;
  1022. }
  1023. if (mLoadEventListener) {
  1024. mLoadEventListener->Cancel();
  1025. mLoadEventListener = nullptr;
  1026. }
  1027. }
  1028. void
  1029. VectorImage::OnSVGDocumentLoaded()
  1030. {
  1031. MOZ_ASSERT(mSVGDocumentWrapper->GetRootSVGElem(),
  1032. "Should have parsed successfully");
  1033. MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations,
  1034. "These flags shouldn't get set until OnSVGDocumentLoaded. "
  1035. "Duplicate calls to OnSVGDocumentLoaded?");
  1036. CancelAllListeners();
  1037. // XXX Flushing is wasteful if embedding frame hasn't had initial reflow.
  1038. mSVGDocumentWrapper->FlushLayout();
  1039. mIsFullyLoaded = true;
  1040. mHaveAnimations = mSVGDocumentWrapper->IsAnimated();
  1041. // Start listening to our image for rendering updates.
  1042. mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this);
  1043. // ProgressTracker::SyncNotifyProgress may release us, so ensure we
  1044. // stick around long enough to complete our work.
  1045. RefPtr<VectorImage> kungFuDeathGrip(this);
  1046. // Tell *our* observers that we're done loading.
  1047. if (mProgressTracker) {
  1048. Progress progress = FLAG_SIZE_AVAILABLE |
  1049. FLAG_HAS_TRANSPARENCY |
  1050. FLAG_FRAME_COMPLETE |
  1051. FLAG_DECODE_COMPLETE |
  1052. FLAG_ONLOAD_UNBLOCKED;
  1053. if (mHaveAnimations) {
  1054. progress |= FLAG_IS_ANIMATED;
  1055. }
  1056. // Merge in any saved progress from OnImageDataComplete.
  1057. if (mLoadProgress) {
  1058. progress |= *mLoadProgress;
  1059. mLoadProgress = Nothing();
  1060. }
  1061. mProgressTracker->SyncNotifyProgress(progress, GetMaxSizedIntRect());
  1062. }
  1063. EvaluateAnimation();
  1064. }
  1065. void
  1066. VectorImage::OnSVGDocumentError()
  1067. {
  1068. CancelAllListeners();
  1069. mError = true;
  1070. if (mProgressTracker) {
  1071. // Notify observers about the error and unblock page load.
  1072. Progress progress = FLAG_ONLOAD_UNBLOCKED | FLAG_HAS_ERROR;
  1073. // Merge in any saved progress from OnImageDataComplete.
  1074. if (mLoadProgress) {
  1075. progress |= *mLoadProgress;
  1076. mLoadProgress = Nothing();
  1077. }
  1078. mProgressTracker->SyncNotifyProgress(progress);
  1079. }
  1080. }
  1081. //------------------------------------------------------------------------------
  1082. // nsIStreamListener method
  1083. //******************************************************************************
  1084. NS_IMETHODIMP
  1085. VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt,
  1086. nsIInputStream* aInStr, uint64_t aSourceOffset,
  1087. uint32_t aCount)
  1088. {
  1089. if (mError) {
  1090. return NS_ERROR_FAILURE;
  1091. }
  1092. return mSVGDocumentWrapper->OnDataAvailable(aRequest, aCtxt, aInStr,
  1093. aSourceOffset, aCount);
  1094. }
  1095. // --------------------------
  1096. // Invalidation helper method
  1097. void
  1098. VectorImage::InvalidateObserversOnNextRefreshDriverTick()
  1099. {
  1100. if (mHaveAnimations) {
  1101. mHasPendingInvalidation = true;
  1102. } else {
  1103. SendInvalidationNotifications();
  1104. }
  1105. }
  1106. void
  1107. VectorImage::PropagateUseCounters(nsIDocument* aParentDocument)
  1108. {
  1109. nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
  1110. if (doc) {
  1111. doc->PropagateUseCounters(aParentDocument);
  1112. }
  1113. }
  1114. nsIntSize
  1115. VectorImage::OptimalImageSizeForDest(const gfxSize& aDest,
  1116. uint32_t aWhichFrame,
  1117. SamplingFilter aSamplingFilter,
  1118. uint32_t aFlags)
  1119. {
  1120. MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX ||
  1121. aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX,
  1122. "Unexpected destination size");
  1123. // We can rescale SVGs freely, so just return the provided destination size.
  1124. return nsIntSize::Ceil(aDest.width, aDest.height);
  1125. }
  1126. already_AddRefed<imgIContainer>
  1127. VectorImage::Unwrap()
  1128. {
  1129. nsCOMPtr<imgIContainer> self(this);
  1130. return self.forget();
  1131. }
  1132. } // namespace image
  1133. } // namespace mozilla