PageRenderTime 86ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/image/src/RasterImage.cpp

http://github.com/zpao/v8monkey
C++ | 3077 lines | 1933 code | 523 blank | 621 comment | 434 complexity | 9c3241205f36981702bbe7c9fb67afd9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. * ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is mozilla.org code.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Netscape Communications Corporation.
  19. * Portions created by the Initial Developer are Copyright (C) 2001
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. * Stuart Parmenter <pavlov@netscape.com>
  24. * Chris Saari <saari@netscape.com>
  25. * Asko Tontti <atontti@cc.hut.fi>
  26. * Arron Mogge <paper@animecity.nu>
  27. * Andrew Smith
  28. * Federico Mena-Quintero <federico@novell.com>
  29. * Bobby Holley <bobbyholley@gmail.com>
  30. *
  31. * Alternatively, the contents of this file may be used under the terms of
  32. * either the GNU General Public License Version 2 or later (the "GPL"), or
  33. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  34. * in which case the provisions of the GPL or the LGPL are applicable instead
  35. * of those above. If you wish to allow use of your version of this file only
  36. * under the terms of either the GPL or the LGPL, and not to allow others to
  37. * use your version of this file under the terms of the MPL, indicate your
  38. * decision by deleting the provisions above and replace them with the notice
  39. * and other provisions required by the GPL or the LGPL. If you do not delete
  40. * the provisions above, a recipient may use your version of this file under
  41. * the terms of any one of the MPL, the GPL or the LGPL.
  42. *
  43. * ***** END LICENSE BLOCK ***** */
  44. #include "base/histogram.h"
  45. #include "nsComponentManagerUtils.h"
  46. #include "imgIContainerObserver.h"
  47. #include "ImageErrors.h"
  48. #include "Decoder.h"
  49. #include "imgIDecoderObserver.h"
  50. #include "RasterImage.h"
  51. #include "nsIInterfaceRequestor.h"
  52. #include "nsIInterfaceRequestorUtils.h"
  53. #include "nsAutoPtr.h"
  54. #include "nsStringStream.h"
  55. #include "prmem.h"
  56. #include "prenv.h"
  57. #include "ImageLogging.h"
  58. #include "ImageLayers.h"
  59. #include "nsPNGDecoder.h"
  60. #include "nsGIFDecoder2.h"
  61. #include "nsJPEGDecoder.h"
  62. #include "nsBMPDecoder.h"
  63. #include "nsICODecoder.h"
  64. #include "nsIconDecoder.h"
  65. #include "gfxContext.h"
  66. #include "mozilla/Preferences.h"
  67. #include "mozilla/StdInt.h"
  68. #include "mozilla/Telemetry.h"
  69. #include "mozilla/TimeStamp.h"
  70. #include "mozilla/ClearOnShutdown.h"
  71. using namespace mozilla;
  72. using namespace mozilla::image;
  73. using namespace mozilla::layers;
  74. // a mask for flags that will affect the decoding
  75. #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
  76. #define DECODE_FLAGS_DEFAULT 0
  77. /* Accounting for compressed data */
  78. #if defined(PR_LOGGING)
  79. static PRLogModuleInfo *gCompressedImageAccountingLog = PR_NewLogModule ("CompressedImageAccounting");
  80. #else
  81. #define gCompressedImageAccountingLog
  82. #endif
  83. // Tweakable progressive decoding parameters. These are initialized to 0 here
  84. // because otherwise, we have to initialize them in a static initializer, which
  85. // makes us slower to start up.
  86. static bool gInitializedPrefCaches = false;
  87. static PRUint32 gDecodeBytesAtATime = 0;
  88. static PRUint32 gMaxMSBeforeYield = 0;
  89. static PRUint32 gMaxBytesForSyncDecode = 0;
  90. static void
  91. InitPrefCaches()
  92. {
  93. Preferences::AddUintVarCache(&gDecodeBytesAtATime,
  94. "image.mem.decode_bytes_at_a_time", 200000);
  95. Preferences::AddUintVarCache(&gMaxMSBeforeYield,
  96. "image.mem.max_ms_before_yield", 400);
  97. Preferences::AddUintVarCache(&gMaxBytesForSyncDecode,
  98. "image.mem.max_bytes_for_sync_decode", 150000);
  99. gInitializedPrefCaches = true;
  100. }
  101. /* We define our own error checking macros here for 2 reasons:
  102. *
  103. * 1) Most of the failures we encounter here will (hopefully) be
  104. * the result of decoding failures (ie, bad data) and not code
  105. * failures. As such, we don't want to clutter up debug consoles
  106. * with spurious messages about NS_ENSURE_SUCCESS failures.
  107. *
  108. * 2) We want to set the internal error flag, shutdown properly,
  109. * and end up in an error state.
  110. *
  111. * So this macro should be called when the desired failure behavior
  112. * is to put the container into an error state and return failure.
  113. * It goes without saying that macro won't compile outside of a
  114. * non-static RasterImage method.
  115. */
  116. #define LOG_CONTAINER_ERROR \
  117. PR_BEGIN_MACRO \
  118. PR_LOG (gImgLog, PR_LOG_ERROR, \
  119. ("RasterImage: [this=%p] Error " \
  120. "detected at line %u for image of " \
  121. "type %s\n", this, __LINE__, \
  122. mSourceDataMimeType.get())); \
  123. PR_END_MACRO
  124. #define CONTAINER_ENSURE_SUCCESS(status) \
  125. PR_BEGIN_MACRO \
  126. nsresult _status = status; /* eval once */ \
  127. if (_status) { \
  128. LOG_CONTAINER_ERROR; \
  129. DoError(); \
  130. return _status; \
  131. } \
  132. PR_END_MACRO
  133. #define CONTAINER_ENSURE_TRUE(arg, rv) \
  134. PR_BEGIN_MACRO \
  135. if (!(arg)) { \
  136. LOG_CONTAINER_ERROR; \
  137. DoError(); \
  138. return rv; \
  139. } \
  140. PR_END_MACRO
  141. static int num_containers;
  142. static int num_discardable_containers;
  143. static PRInt64 total_source_bytes;
  144. static PRInt64 discardable_source_bytes;
  145. /* Are we globally disabling image discarding? */
  146. static bool
  147. DiscardingEnabled()
  148. {
  149. static bool inited;
  150. static bool enabled;
  151. if (!inited) {
  152. inited = true;
  153. enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nsnull);
  154. }
  155. return enabled;
  156. }
  157. namespace mozilla {
  158. namespace image {
  159. /* static */ nsRefPtr<RasterImage::DecodeWorker> RasterImage::DecodeWorker::sSingleton;
  160. #ifndef DEBUG
  161. NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
  162. nsISupportsWeakReference)
  163. #else
  164. NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsIProperties,
  165. imgIContainerDebug, nsISupportsWeakReference)
  166. #endif
  167. //******************************************************************************
  168. RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
  169. Image(aStatusTracker), // invoke superclass's constructor
  170. mSize(0,0),
  171. mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
  172. mAnim(nsnull),
  173. mLoopCount(-1),
  174. mObserver(nsnull),
  175. mLockCount(0),
  176. mDecoder(nsnull),
  177. mDecodeRequest(this),
  178. mBytesDecoded(0),
  179. mDecodeCount(0),
  180. #ifdef DEBUG
  181. mFramesNotified(0),
  182. #endif
  183. mHasSize(false),
  184. mDecodeOnDraw(false),
  185. mMultipart(false),
  186. mDiscardable(false),
  187. mHasSourceData(false),
  188. mDecoded(false),
  189. mHasBeenDecoded(false),
  190. mInDecoder(false),
  191. mAnimationFinished(false)
  192. {
  193. // Set up the discard tracker node.
  194. mDiscardTrackerNode.curr = this;
  195. mDiscardTrackerNode.prev = mDiscardTrackerNode.next = nsnull;
  196. Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
  197. // Statistics
  198. num_containers++;
  199. // Register our pref observers if we haven't yet.
  200. if (NS_UNLIKELY(!gInitializedPrefCaches)) {
  201. InitPrefCaches();
  202. }
  203. }
  204. //******************************************************************************
  205. RasterImage::~RasterImage()
  206. {
  207. delete mAnim;
  208. for (unsigned int i = 0; i < mFrames.Length(); ++i)
  209. delete mFrames[i];
  210. // Discardable statistics
  211. if (mDiscardable) {
  212. num_discardable_containers--;
  213. discardable_source_bytes -= mSourceData.Length();
  214. PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
  215. ("CompressedImageAccounting: destroying RasterImage %p. "
  216. "Total Containers: %d, Discardable containers: %d, "
  217. "Total source bytes: %lld, Source bytes for discardable containers %lld",
  218. this,
  219. num_containers,
  220. num_discardable_containers,
  221. total_source_bytes,
  222. discardable_source_bytes));
  223. }
  224. DiscardTracker::Remove(&mDiscardTrackerNode);
  225. // If we have a decoder open, shut it down
  226. if (mDecoder) {
  227. nsresult rv = ShutdownDecoder(eShutdownIntent_Interrupted);
  228. if (NS_FAILED(rv))
  229. NS_WARNING("Failed to shut down decoder in destructor!");
  230. }
  231. // Total statistics
  232. num_containers--;
  233. total_source_bytes -= mSourceData.Length();
  234. }
  235. nsresult
  236. RasterImage::Init(imgIDecoderObserver *aObserver,
  237. const char* aMimeType,
  238. const char* aURIString,
  239. PRUint32 aFlags)
  240. {
  241. // We don't support re-initialization
  242. if (mInitialized)
  243. return NS_ERROR_ILLEGAL_VALUE;
  244. // Not sure an error can happen before init, but be safe
  245. if (mError)
  246. return NS_ERROR_FAILURE;
  247. NS_ENSURE_ARG_POINTER(aMimeType);
  248. // We must be non-discardable and non-decode-on-draw for
  249. // multipart channels
  250. NS_ABORT_IF_FALSE(!(aFlags & INIT_FLAG_MULTIPART) ||
  251. (!(aFlags & INIT_FLAG_DISCARDABLE) &&
  252. !(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
  253. "Can't be discardable or decode-on-draw for multipart");
  254. // Store initialization data
  255. mObserver = do_GetWeakReference(aObserver);
  256. mSourceDataMimeType.Assign(aMimeType);
  257. mURIString.Assign(aURIString);
  258. mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
  259. mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
  260. mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
  261. // Statistics
  262. if (mDiscardable) {
  263. num_discardable_containers++;
  264. discardable_source_bytes += mSourceData.Length();
  265. }
  266. // If we're being called from ExtractFrame (used by borderimage),
  267. // we don't actually do any decoding. Bail early.
  268. // XXX - This should be removed when we fix borderimage
  269. if (mSourceDataMimeType.Length() == 0) {
  270. mInitialized = true;
  271. return NS_OK;
  272. }
  273. // Instantiate the decoder
  274. //
  275. // If we're doing decode-on-draw, we want to do a quick first pass to get
  276. // the size but nothing else. We instantiate another decoder later to do
  277. // the full decoding.
  278. nsresult rv = InitDecoder(/* aDoSizeDecode = */ mDecodeOnDraw);
  279. CONTAINER_ENSURE_SUCCESS(rv);
  280. // Mark us as initialized
  281. mInitialized = true;
  282. return NS_OK;
  283. }
  284. bool
  285. RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
  286. {
  287. NS_ASSERTION(aTime <= TimeStamp::Now(),
  288. "Given time appears to be in the future");
  289. imgFrame* nextFrame = nsnull;
  290. PRUint32 currentFrameIndex = mAnim->currentAnimationFrameIndex;
  291. PRUint32 nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
  292. PRUint32 timeout = 0;
  293. mImageContainer = nsnull;
  294. // Figure out if we have the next full frame. This is more complicated than
  295. // just checking for mFrames.Length() because decoders append their frames
  296. // before they're filled in.
  297. NS_ABORT_IF_FALSE(mDecoder || nextFrameIndex <= mFrames.Length(),
  298. "How did we get 2 indices too far by incrementing?");
  299. // If we don't have a decoder, we know we've got everything we're going to
  300. // get. If we do, we only display fully-downloaded frames; everything else
  301. // gets delayed.
  302. bool haveFullNextFrame = !mDecoder ||
  303. nextFrameIndex < mDecoder->GetCompleteFrameCount();
  304. // If we're done decoding the next frame, go ahead and display it now and
  305. // reinit with the next frame's delay time.
  306. if (haveFullNextFrame) {
  307. if (mFrames.Length() == nextFrameIndex) {
  308. // End of Animation, unless we are looping forever
  309. // If animation mode is "loop once", it's time to stop animating
  310. if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) {
  311. mAnimationFinished = true;
  312. EvaluateAnimation();
  313. }
  314. // We may have used compositingFrame to build a frame, and then copied
  315. // it back into mFrames[..]. If so, delete composite to save memory
  316. if (mAnim->compositingFrame && mAnim->lastCompositedFrameIndex == -1) {
  317. mAnim->compositingFrame = nsnull;
  318. }
  319. nextFrameIndex = 0;
  320. if (mLoopCount > 0) {
  321. mLoopCount--;
  322. }
  323. if (!mAnimating) {
  324. // break out early if we are actually done animating
  325. return false;
  326. }
  327. }
  328. if (!(nextFrame = mFrames[nextFrameIndex])) {
  329. // something wrong with the next frame, skip it
  330. mAnim->currentAnimationFrameIndex = nextFrameIndex;
  331. return false;
  332. }
  333. timeout = nextFrame->GetTimeout();
  334. } else {
  335. // Uh oh, the frame we want to show is currently being decoded (partial)
  336. // Wait until the next refresh driver tick and try again
  337. return false;
  338. }
  339. if (!(timeout > 0)) {
  340. mAnimationFinished = true;
  341. EvaluateAnimation();
  342. }
  343. imgFrame *frameToUse = nsnull;
  344. if (nextFrameIndex == 0) {
  345. frameToUse = nextFrame;
  346. *aDirtyRect = mAnim->firstFrameRefreshArea;
  347. } else {
  348. imgFrame *curFrame = mFrames[currentFrameIndex];
  349. if (!curFrame) {
  350. return false;
  351. }
  352. // Change frame
  353. if (NS_FAILED(DoComposite(aDirtyRect, curFrame,
  354. nextFrame, nextFrameIndex))) {
  355. // something went wrong, move on to next
  356. NS_WARNING("RasterImage::AdvanceFrame(): Compositing of frame failed");
  357. nextFrame->SetCompositingFailed(true);
  358. mAnim->currentAnimationFrameIndex = nextFrameIndex;
  359. mAnim->currentAnimationFrameTime = aTime;
  360. return false;
  361. }
  362. nextFrame->SetCompositingFailed(false);
  363. }
  364. // Set currentAnimationFrameIndex at the last possible moment
  365. mAnim->currentAnimationFrameIndex = nextFrameIndex;
  366. mAnim->currentAnimationFrameTime = aTime;
  367. return true;
  368. }
  369. //******************************************************************************
  370. // [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
  371. NS_IMETHODIMP_(void)
  372. RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
  373. {
  374. if (!mAnimating || !ShouldAnimate()) {
  375. return;
  376. }
  377. EnsureAnimExists();
  378. // only advance the frame if the current time is greater than or
  379. // equal to the current frame's end time.
  380. TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime();
  381. bool frameAdvanced = false;
  382. // The dirtyRect variable will contain an accumulation of the sub-rectangles
  383. // that are dirty for each frame we advance in AdvanceFrame().
  384. nsIntRect dirtyRect;
  385. while (currentFrameEndTime <= aTime) {
  386. TimeStamp oldFrameEndTime = currentFrameEndTime;
  387. nsIntRect frameDirtyRect;
  388. bool didAdvance = AdvanceFrame(aTime, &frameDirtyRect);
  389. frameAdvanced = frameAdvanced || didAdvance;
  390. currentFrameEndTime = GetCurrentImgFrameEndTime();
  391. // Accumulate the dirty area.
  392. dirtyRect = dirtyRect.Union(frameDirtyRect);
  393. // if we didn't advance a frame, and our frame end time didn't change,
  394. // then we need to break out of this loop & wait for the frame(s)
  395. // to finish downloading
  396. if (!frameAdvanced && (currentFrameEndTime == oldFrameEndTime)) {
  397. break;
  398. }
  399. }
  400. if (frameAdvanced) {
  401. nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
  402. if (!observer) {
  403. NS_ERROR("Refreshing image after its imgRequest is gone");
  404. StopAnimation();
  405. return;
  406. }
  407. // Notify listeners that our frame has actually changed, but do this only
  408. // once for all frames that we've now passed (if AdvanceFrame() was called
  409. // more than once).
  410. #ifdef DEBUG
  411. mFramesNotified++;
  412. #endif
  413. observer->FrameChanged(nsnull, this, &dirtyRect);
  414. }
  415. }
  416. //******************************************************************************
  417. /* [noscript] imgIContainer extractFrame(PRUint32 aWhichFrame,
  418. * [const] in nsIntRect aRegion,
  419. * in PRUint32 aFlags); */
  420. NS_IMETHODIMP
  421. RasterImage::ExtractFrame(PRUint32 aWhichFrame,
  422. const nsIntRect &aRegion,
  423. PRUint32 aFlags,
  424. imgIContainer **_retval)
  425. {
  426. NS_ENSURE_ARG_POINTER(_retval);
  427. nsresult rv;
  428. if (aWhichFrame > FRAME_MAX_VALUE)
  429. return NS_ERROR_INVALID_ARG;
  430. if (mError)
  431. return NS_ERROR_FAILURE;
  432. // Disallowed in the API
  433. if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
  434. return NS_ERROR_FAILURE;
  435. // Make a new container. This should switch to another class with bug 505959.
  436. nsRefPtr<RasterImage> img(new RasterImage());
  437. // We don't actually have a mimetype in this case. The empty string tells the
  438. // init routine not to try to instantiate a decoder. This should be fixed in
  439. // bug 505959.
  440. img->Init(nsnull, "", "", INIT_FLAG_NONE);
  441. img->SetSize(aRegion.width, aRegion.height);
  442. img->mDecoded = true; // Also, we need to mark the image as decoded
  443. img->mHasBeenDecoded = true;
  444. img->mFrameDecodeFlags = aFlags & DECODE_FLAGS_MASK;
  445. if (img->mFrameDecodeFlags != mFrameDecodeFlags) {
  446. // if we can't discard, then we're screwed; we have no way
  447. // to re-decode. Similarly if we aren't allowed to do a sync
  448. // decode.
  449. if (!(aFlags & FLAG_SYNC_DECODE))
  450. return NS_ERROR_NOT_AVAILABLE;
  451. if (!CanForciblyDiscard() || mDecoder || mAnim)
  452. return NS_ERROR_NOT_AVAILABLE;
  453. ForceDiscard();
  454. mFrameDecodeFlags = img->mFrameDecodeFlags;
  455. }
  456. // If a synchronous decode was requested, do it
  457. if (aFlags & FLAG_SYNC_DECODE) {
  458. rv = SyncDecode();
  459. CONTAINER_ENSURE_SUCCESS(rv);
  460. }
  461. // Get the frame. If it's not there, it's probably the caller's fault for
  462. // not waiting for the data to be loaded from the network or not passing
  463. // FLAG_SYNC_DECODE
  464. PRUint32 frameIndex = (aWhichFrame == FRAME_FIRST) ?
  465. 0 : GetCurrentImgFrameIndex();
  466. imgFrame *frame = GetDrawableImgFrame(frameIndex);
  467. if (!frame) {
  468. *_retval = nsnull;
  469. return NS_ERROR_FAILURE;
  470. }
  471. // The frame can be smaller than the image. We want to extract only the part
  472. // of the frame that actually exists.
  473. nsIntRect framerect = frame->GetRect();
  474. framerect.IntersectRect(framerect, aRegion);
  475. if (framerect.IsEmpty())
  476. return NS_ERROR_NOT_AVAILABLE;
  477. nsAutoPtr<imgFrame> subframe;
  478. rv = frame->Extract(framerect, getter_Transfers(subframe));
  479. if (NS_FAILED(rv))
  480. return rv;
  481. img->mFrames.AppendElement(subframe.forget());
  482. img->mStatusTracker->RecordLoaded();
  483. img->mStatusTracker->RecordDecoded();
  484. *_retval = img.forget().get();
  485. return NS_OK;
  486. }
  487. //******************************************************************************
  488. /* readonly attribute PRInt32 width; */
  489. NS_IMETHODIMP
  490. RasterImage::GetWidth(PRInt32 *aWidth)
  491. {
  492. NS_ENSURE_ARG_POINTER(aWidth);
  493. if (mError) {
  494. *aWidth = 0;
  495. return NS_ERROR_FAILURE;
  496. }
  497. *aWidth = mSize.width;
  498. return NS_OK;
  499. }
  500. //******************************************************************************
  501. /* readonly attribute PRInt32 height; */
  502. NS_IMETHODIMP
  503. RasterImage::GetHeight(PRInt32 *aHeight)
  504. {
  505. NS_ENSURE_ARG_POINTER(aHeight);
  506. if (mError) {
  507. *aHeight = 0;
  508. return NS_ERROR_FAILURE;
  509. }
  510. *aHeight = mSize.height;
  511. return NS_OK;
  512. }
  513. //******************************************************************************
  514. /* unsigned short GetType(); */
  515. NS_IMETHODIMP
  516. RasterImage::GetType(PRUint16 *aType)
  517. {
  518. NS_ENSURE_ARG_POINTER(aType);
  519. *aType = GetType();
  520. return NS_OK;
  521. }
  522. //******************************************************************************
  523. /* [noscript, notxpcom] PRUint16 GetType(); */
  524. NS_IMETHODIMP_(PRUint16)
  525. RasterImage::GetType()
  526. {
  527. return imgIContainer::TYPE_RASTER;
  528. }
  529. imgFrame*
  530. RasterImage::GetImgFrameNoDecode(PRUint32 framenum)
  531. {
  532. if (!mAnim) {
  533. NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
  534. return mFrames.SafeElementAt(0, nsnull);
  535. }
  536. if (mAnim->lastCompositedFrameIndex == PRInt32(framenum))
  537. return mAnim->compositingFrame;
  538. return mFrames.SafeElementAt(framenum, nsnull);
  539. }
  540. imgFrame*
  541. RasterImage::GetImgFrame(PRUint32 framenum)
  542. {
  543. nsresult rv = WantDecodedFrames();
  544. CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nsnull);
  545. return GetImgFrameNoDecode(framenum);
  546. }
  547. imgFrame*
  548. RasterImage::GetDrawableImgFrame(PRUint32 framenum)
  549. {
  550. imgFrame *frame = GetImgFrame(framenum);
  551. // We will return a paletted frame if it's not marked as compositing failed
  552. // so we can catch crashes for reasons we haven't investigated.
  553. if (frame && frame->GetCompositingFailed())
  554. return nsnull;
  555. return frame;
  556. }
  557. PRUint32
  558. RasterImage::GetCurrentImgFrameIndex() const
  559. {
  560. if (mAnim)
  561. return mAnim->currentAnimationFrameIndex;
  562. return 0;
  563. }
  564. TimeStamp
  565. RasterImage::GetCurrentImgFrameEndTime() const
  566. {
  567. imgFrame* currentFrame = mFrames[mAnim->currentAnimationFrameIndex];
  568. TimeStamp currentFrameTime = mAnim->currentAnimationFrameTime;
  569. PRInt64 timeout = currentFrame->GetTimeout();
  570. if (timeout < 0) {
  571. // We need to return a sentinel value in this case, because our logic
  572. // doesn't work correctly if we have a negative timeout value. The reason
  573. // this positive infinity was chosen was because it works with the loop in
  574. // RequestRefresh() above.
  575. return TimeStamp() + TimeDuration::FromMilliseconds(UINT64_MAX);
  576. }
  577. TimeDuration durationOfTimeout = TimeDuration::FromMilliseconds(timeout);
  578. TimeStamp currentFrameEndTime = currentFrameTime + durationOfTimeout;
  579. return currentFrameEndTime;
  580. }
  581. imgFrame*
  582. RasterImage::GetCurrentImgFrame()
  583. {
  584. return GetImgFrame(GetCurrentImgFrameIndex());
  585. }
  586. imgFrame*
  587. RasterImage::GetCurrentDrawableImgFrame()
  588. {
  589. return GetDrawableImgFrame(GetCurrentImgFrameIndex());
  590. }
  591. //******************************************************************************
  592. /* readonly attribute boolean currentFrameIsOpaque; */
  593. NS_IMETHODIMP
  594. RasterImage::GetCurrentFrameIsOpaque(bool *aIsOpaque)
  595. {
  596. NS_ENSURE_ARG_POINTER(aIsOpaque);
  597. if (mError)
  598. return NS_ERROR_FAILURE;
  599. // See if we can get an image frame
  600. imgFrame *curframe = GetCurrentImgFrame();
  601. // If we don't get a frame, the safe answer is "not opaque"
  602. if (!curframe)
  603. *aIsOpaque = false;
  604. // Otherwise, we can make a more intelligent decision
  605. else {
  606. *aIsOpaque = !curframe->GetNeedsBackground();
  607. // We are also transparent if the current frame's size doesn't cover our
  608. // entire area.
  609. nsIntRect framerect = curframe->GetRect();
  610. *aIsOpaque = *aIsOpaque && framerect.IsEqualInterior(nsIntRect(0, 0, mSize.width, mSize.height));
  611. }
  612. return NS_OK;
  613. }
  614. void
  615. RasterImage::GetCurrentFrameRect(nsIntRect& aRect)
  616. {
  617. // Get the current frame
  618. imgFrame* curframe = GetCurrentImgFrame();
  619. // If we have the frame, use that rectangle
  620. if (curframe) {
  621. aRect = curframe->GetRect();
  622. } else {
  623. // If the frame doesn't exist, we pass the empty rectangle. It's not clear
  624. // whether this is appropriate in general, but at the moment the only
  625. // consumer of this method is imgStatusTracker (when it wants to figure out
  626. // dirty rectangles to send out batched observer updates). This should
  627. // probably be revisited when we fix bug 503973.
  628. aRect.MoveTo(0, 0);
  629. aRect.SizeTo(0, 0);
  630. }
  631. }
  632. PRUint32
  633. RasterImage::GetCurrentFrameIndex()
  634. {
  635. return GetCurrentImgFrameIndex();
  636. }
  637. PRUint32
  638. RasterImage::GetNumFrames()
  639. {
  640. return mFrames.Length();
  641. }
  642. //******************************************************************************
  643. /* readonly attribute boolean animated; */
  644. NS_IMETHODIMP
  645. RasterImage::GetAnimated(bool *aAnimated)
  646. {
  647. if (mError)
  648. return NS_ERROR_FAILURE;
  649. NS_ENSURE_ARG_POINTER(aAnimated);
  650. // If we have mAnim, we can know for sure
  651. if (mAnim) {
  652. *aAnimated = true;
  653. return NS_OK;
  654. }
  655. // Otherwise, we need to have been decoded to know for sure, since if we were
  656. // decoded at least once mAnim would have been created for animated images
  657. if (!mHasBeenDecoded)
  658. return NS_ERROR_NOT_AVAILABLE;
  659. // We know for sure
  660. *aAnimated = false;
  661. return NS_OK;
  662. }
  663. //******************************************************************************
  664. /* [noscript] gfxImageSurface copyFrame(in PRUint32 aWhichFrame,
  665. * in PRUint32 aFlags); */
  666. NS_IMETHODIMP
  667. RasterImage::CopyFrame(PRUint32 aWhichFrame,
  668. PRUint32 aFlags,
  669. gfxImageSurface **_retval)
  670. {
  671. if (aWhichFrame > FRAME_MAX_VALUE)
  672. return NS_ERROR_INVALID_ARG;
  673. if (mError)
  674. return NS_ERROR_FAILURE;
  675. // Disallowed in the API
  676. if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
  677. return NS_ERROR_FAILURE;
  678. nsresult rv;
  679. PRUint32 desiredDecodeFlags = aFlags & DECODE_FLAGS_MASK;
  680. if (desiredDecodeFlags != mFrameDecodeFlags) {
  681. // if we can't discard, then we're screwed; we have no way
  682. // to re-decode. Similarly if we aren't allowed to do a sync
  683. // decode.
  684. if (!(aFlags & FLAG_SYNC_DECODE))
  685. return NS_ERROR_NOT_AVAILABLE;
  686. if (!CanForciblyDiscard() || mDecoder || mAnim)
  687. return NS_ERROR_NOT_AVAILABLE;
  688. ForceDiscard();
  689. mFrameDecodeFlags = desiredDecodeFlags;
  690. }
  691. // If requested, synchronously flush any data we have lying around to the decoder
  692. if (aFlags & FLAG_SYNC_DECODE) {
  693. rv = SyncDecode();
  694. CONTAINER_ENSURE_SUCCESS(rv);
  695. }
  696. NS_ENSURE_ARG_POINTER(_retval);
  697. // Get the frame. If it's not there, it's probably the caller's fault for
  698. // not waiting for the data to be loaded from the network or not passing
  699. // FLAG_SYNC_DECODE
  700. PRUint32 frameIndex = (aWhichFrame == FRAME_FIRST) ?
  701. 0 : GetCurrentImgFrameIndex();
  702. imgFrame *frame = GetDrawableImgFrame(frameIndex);
  703. if (!frame) {
  704. *_retval = nsnull;
  705. return NS_ERROR_FAILURE;
  706. }
  707. nsRefPtr<gfxPattern> pattern;
  708. frame->GetPattern(getter_AddRefs(pattern));
  709. nsIntRect intframerect = frame->GetRect();
  710. gfxRect framerect(intframerect.x, intframerect.y, intframerect.width, intframerect.height);
  711. // Create a 32-bit image surface of our size, but draw using the frame's
  712. // rect, implicitly padding the frame out to the image's size.
  713. nsRefPtr<gfxImageSurface> imgsurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
  714. gfxASurface::ImageFormatARGB32);
  715. gfxContext ctx(imgsurface);
  716. ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
  717. ctx.SetPattern(pattern);
  718. ctx.Rectangle(framerect);
  719. ctx.Fill();
  720. *_retval = imgsurface.forget().get();
  721. return NS_OK;
  722. }
  723. //******************************************************************************
  724. /* [noscript] gfxASurface getFrame(in PRUint32 aWhichFrame,
  725. * in PRUint32 aFlags); */
  726. NS_IMETHODIMP
  727. RasterImage::GetFrame(PRUint32 aWhichFrame,
  728. PRUint32 aFlags,
  729. gfxASurface **_retval)
  730. {
  731. if (aWhichFrame > FRAME_MAX_VALUE)
  732. return NS_ERROR_INVALID_ARG;
  733. if (mError)
  734. return NS_ERROR_FAILURE;
  735. // Disallowed in the API
  736. if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
  737. return NS_ERROR_FAILURE;
  738. nsresult rv = NS_OK;
  739. if (mDecoded) {
  740. // If we have decoded data, and it is not a perfect match for what we are
  741. // looking for, we must discard to be able to generate the proper data.
  742. PRUint32 desiredDecodeFlags = aFlags & DECODE_FLAGS_MASK;
  743. if (desiredDecodeFlags != mFrameDecodeFlags) {
  744. // if we can't discard, then we're screwed; we have no way
  745. // to re-decode. Similarly if we aren't allowed to do a sync
  746. // decode.
  747. if (!(aFlags & FLAG_SYNC_DECODE))
  748. return NS_ERROR_NOT_AVAILABLE;
  749. if (!CanForciblyDiscard() || mDecoder || mAnim)
  750. return NS_ERROR_NOT_AVAILABLE;
  751. ForceDiscard();
  752. mFrameDecodeFlags = desiredDecodeFlags;
  753. }
  754. }
  755. // If the caller requested a synchronous decode, do it
  756. if (aFlags & FLAG_SYNC_DECODE) {
  757. rv = SyncDecode();
  758. CONTAINER_ENSURE_SUCCESS(rv);
  759. }
  760. // Get the frame. If it's not there, it's probably the caller's fault for
  761. // not waiting for the data to be loaded from the network or not passing
  762. // FLAG_SYNC_DECODE
  763. PRUint32 frameIndex = (aWhichFrame == FRAME_FIRST) ?
  764. 0 : GetCurrentImgFrameIndex();
  765. imgFrame *frame = GetDrawableImgFrame(frameIndex);
  766. if (!frame) {
  767. *_retval = nsnull;
  768. return NS_ERROR_FAILURE;
  769. }
  770. nsRefPtr<gfxASurface> framesurf;
  771. // If this frame covers the entire image, we can just reuse its existing
  772. // surface.
  773. nsIntRect framerect = frame->GetRect();
  774. if (framerect.x == 0 && framerect.y == 0 &&
  775. framerect.width == mSize.width &&
  776. framerect.height == mSize.height)
  777. rv = frame->GetSurface(getter_AddRefs(framesurf));
  778. // The image doesn't have a surface because it's been optimized away. Create
  779. // one.
  780. if (!framesurf) {
  781. nsRefPtr<gfxImageSurface> imgsurf;
  782. rv = CopyFrame(aWhichFrame, aFlags, getter_AddRefs(imgsurf));
  783. framesurf = imgsurf;
  784. }
  785. *_retval = framesurf.forget().get();
  786. return rv;
  787. }
  788. NS_IMETHODIMP
  789. RasterImage::GetImageContainer(ImageContainer **_retval)
  790. {
  791. if (mImageContainer) {
  792. *_retval = mImageContainer;
  793. NS_ADDREF(*_retval);
  794. return NS_OK;
  795. }
  796. CairoImage::Data cairoData;
  797. nsRefPtr<gfxASurface> imageSurface;
  798. nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface));
  799. NS_ENSURE_SUCCESS(rv, rv);
  800. cairoData.mSurface = imageSurface;
  801. GetWidth(&cairoData.mSize.width);
  802. GetHeight(&cairoData.mSize.height);
  803. mImageContainer = LayerManager::CreateImageContainer();
  804. // Now create a CairoImage to display the surface.
  805. layers::Image::Format cairoFormat = layers::Image::CAIRO_SURFACE;
  806. nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1);
  807. NS_ASSERTION(image, "Failed to create Image");
  808. NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format");
  809. static_cast<CairoImage*>(image.get())->SetData(cairoData);
  810. mImageContainer->SetCurrentImage(image);
  811. *_retval = mImageContainer;
  812. NS_ADDREF(*_retval);
  813. return NS_OK;
  814. }
  815. namespace {
  816. PRUint32
  817. GetDecodedSize(const nsTArray<imgFrame *> &aFrames,
  818. gfxASurface::MemoryLocation aLocation)
  819. {
  820. PRUint32 val = 0;
  821. for (PRUint32 i = 0; i < aFrames.Length(); ++i) {
  822. imgFrame *frame = aFrames.SafeElementAt(i, nsnull);
  823. NS_ABORT_IF_FALSE(frame, "Null frame in frame array!");
  824. val += frame->EstimateMemoryUsed(aLocation);
  825. }
  826. return val;
  827. }
  828. } // anonymous namespace
  829. PRUint32
  830. RasterImage::GetDecodedHeapSize()
  831. {
  832. return GetDecodedSize(mFrames, gfxASurface::MEMORY_IN_PROCESS_HEAP);
  833. }
  834. PRUint32
  835. RasterImage::GetDecodedNonheapSize()
  836. {
  837. return GetDecodedSize(mFrames, gfxASurface::MEMORY_IN_PROCESS_NONHEAP);
  838. }
  839. PRUint32
  840. RasterImage::GetDecodedOutOfProcessSize()
  841. {
  842. return GetDecodedSize(mFrames, gfxASurface::MEMORY_OUT_OF_PROCESS);
  843. }
  844. PRUint32
  845. RasterImage::GetSourceHeapSize()
  846. {
  847. PRUint32 sourceDataSize = mSourceData.Length();
  848. NS_ABORT_IF_FALSE(StoringSourceData() || (sourceDataSize == 0),
  849. "Non-zero source data size when we aren't storing it?");
  850. return sourceDataSize;
  851. }
  852. void
  853. RasterImage::DeleteImgFrame(PRUint32 framenum)
  854. {
  855. NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Deleting invalid frame!");
  856. delete mFrames[framenum];
  857. mFrames[framenum] = nsnull;
  858. }
  859. nsresult
  860. RasterImage::InternalAddFrameHelper(PRUint32 framenum, imgFrame *aFrame,
  861. PRUint8 **imageData, PRUint32 *imageLength,
  862. PRUint32 **paletteData, PRUint32 *paletteLength)
  863. {
  864. NS_ABORT_IF_FALSE(framenum <= mFrames.Length(), "Invalid frame index!");
  865. if (framenum > mFrames.Length())
  866. return NS_ERROR_INVALID_ARG;
  867. nsAutoPtr<imgFrame> frame(aFrame);
  868. if (paletteData && paletteLength)
  869. frame->GetPaletteData(paletteData, paletteLength);
  870. frame->GetImageData(imageData, imageLength);
  871. // We are in the middle of decoding. This will be unlocked when we finish the
  872. // decoder->Write() call.
  873. frame->LockImageData();
  874. mFrames.InsertElementAt(framenum, frame.forget());
  875. return NS_OK;
  876. }
  877. nsresult
  878. RasterImage::InternalAddFrame(PRUint32 framenum,
  879. PRInt32 aX, PRInt32 aY,
  880. PRInt32 aWidth, PRInt32 aHeight,
  881. gfxASurface::gfxImageFormat aFormat,
  882. PRUint8 aPaletteDepth,
  883. PRUint8 **imageData,
  884. PRUint32 *imageLength,
  885. PRUint32 **paletteData,
  886. PRUint32 *paletteLength)
  887. {
  888. // We assume that we're in the middle of decoding because we unlock the
  889. // previous frame when we create a new frame, and only when decoding do we
  890. // lock frames.
  891. NS_ABORT_IF_FALSE(mInDecoder, "Only decoders may add frames!");
  892. NS_ABORT_IF_FALSE(framenum <= mFrames.Length(), "Invalid frame index!");
  893. if (framenum > mFrames.Length())
  894. return NS_ERROR_INVALID_ARG;
  895. nsAutoPtr<imgFrame> frame(new imgFrame());
  896. nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
  897. NS_ENSURE_SUCCESS(rv, rv);
  898. // We know we are in a decoder. Therefore, we must unlock the previous frame
  899. // when we move on to decoding into the next frame.
  900. if (mFrames.Length() > 0) {
  901. imgFrame *prevframe = mFrames.ElementAt(mFrames.Length() - 1);
  902. prevframe->UnlockImageData();
  903. }
  904. if (mFrames.Length() == 0) {
  905. return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
  906. paletteData, paletteLength);
  907. }
  908. if (mFrames.Length() == 1) {
  909. // Since we're about to add our second frame, initialize animation stuff
  910. EnsureAnimExists();
  911. // If we dispose of the first frame by clearing it, then the
  912. // First Frame's refresh area is all of itself.
  913. // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR)
  914. PRInt32 frameDisposalMethod = mFrames[0]->GetFrameDisposalMethod();
  915. if (frameDisposalMethod == kDisposeClear ||
  916. frameDisposalMethod == kDisposeRestorePrevious)
  917. mAnim->firstFrameRefreshArea = mFrames[0]->GetRect();
  918. }
  919. // Calculate firstFrameRefreshArea
  920. // Some gifs are huge but only have a small area that they animate
  921. // We only need to refresh that small area when Frame 0 comes around again
  922. nsIntRect frameRect = frame->GetRect();
  923. mAnim->firstFrameRefreshArea.UnionRect(mAnim->firstFrameRefreshArea,
  924. frameRect);
  925. rv = InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
  926. paletteData, paletteLength);
  927. // We may be able to start animating, if we now have enough frames
  928. EvaluateAnimation();
  929. return rv;
  930. }
  931. nsresult
  932. RasterImage::SetSize(PRInt32 aWidth, PRInt32 aHeight)
  933. {
  934. if (mError)
  935. return NS_ERROR_FAILURE;
  936. // Ensure that we have positive values
  937. // XXX - Why isn't the size unsigned? Should this be changed?
  938. if ((aWidth < 0) || (aHeight < 0))
  939. return NS_ERROR_INVALID_ARG;
  940. // if we already have a size, check the new size against the old one
  941. if (mHasSize &&
  942. ((aWidth != mSize.width) || (aHeight != mSize.height))) {
  943. // Alter the warning depending on whether the channel is multipart
  944. if (!mMultipart)
  945. NS_WARNING("Image changed size on redecode! This should not happen!");
  946. else
  947. NS_WARNING("Multipart channel sent an image of a different size");
  948. // Make the decoder aware of the error so that it doesn't try to call
  949. // FinishInternal during ShutdownDecoder.
  950. if (mDecoder)
  951. mDecoder->PostResizeError();
  952. DoError();
  953. return NS_ERROR_UNEXPECTED;
  954. }
  955. // Set the size and flag that we have it
  956. mSize.SizeTo(aWidth, aHeight);
  957. mHasSize = true;
  958. return NS_OK;
  959. }
  960. nsresult
  961. RasterImage::EnsureFrame(PRUint32 aFrameNum, PRInt32 aX, PRInt32 aY,
  962. PRInt32 aWidth, PRInt32 aHeight,
  963. gfxASurface::gfxImageFormat aFormat,
  964. PRUint8 aPaletteDepth,
  965. PRUint8 **imageData, PRUint32 *imageLength,
  966. PRUint32 **paletteData, PRUint32 *paletteLength)
  967. {
  968. if (mError)
  969. return NS_ERROR_FAILURE;
  970. NS_ENSURE_ARG_POINTER(imageData);
  971. NS_ENSURE_ARG_POINTER(imageLength);
  972. NS_ABORT_IF_FALSE(aFrameNum <= mFrames.Length(), "Invalid frame index!");
  973. if (aPaletteDepth > 0) {
  974. NS_ENSURE_ARG_POINTER(paletteData);
  975. NS_ENSURE_ARG_POINTER(paletteLength);
  976. }
  977. if (aFrameNum > mFrames.Length())
  978. return NS_ERROR_INVALID_ARG;
  979. // Adding a frame that doesn't already exist.
  980. if (aFrameNum == mFrames.Length())
  981. return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
  982. aPaletteDepth, imageData, imageLength,
  983. paletteData, paletteLength);
  984. imgFrame *frame = GetImgFrame(aFrameNum);
  985. if (!frame)
  986. return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
  987. aPaletteDepth, imageData, imageLength,
  988. paletteData, paletteLength);
  989. // See if we can re-use the frame that already exists.
  990. nsIntRect rect = frame->GetRect();
  991. if (rect.x == aX && rect.y == aY && rect.width == aWidth &&
  992. rect.height == aHeight && frame->GetFormat() == aFormat &&
  993. frame->GetPaletteDepth() == aPaletteDepth) {
  994. frame->GetImageData(imageData, imageLength);
  995. if (paletteData) {
  996. frame->GetPaletteData(paletteData, paletteLength);
  997. }
  998. // We can re-use the frame if it has image data.
  999. if (*imageData && paletteData && *paletteData) {
  1000. return NS_OK;
  1001. }
  1002. if (*imageData && !paletteData) {
  1003. return NS_OK;
  1004. }
  1005. }
  1006. DeleteImgFrame(aFrameNum);
  1007. return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
  1008. aPaletteDepth, imageData, imageLength,
  1009. paletteData, paletteLength);
  1010. }
  1011. nsresult
  1012. RasterImage::EnsureFrame(PRUint32 aFramenum, PRInt32 aX, PRInt32 aY,
  1013. PRInt32 aWidth, PRInt32 aHeight,
  1014. gfxASurface::gfxImageFormat aFormat,
  1015. PRUint8** imageData, PRUint32* imageLength)
  1016. {
  1017. return EnsureFrame(aFramenum, aX, aY, aWidth, aHeight, aFormat,
  1018. /* aPaletteDepth = */ 0, imageData, imageLength,
  1019. /* aPaletteData = */ nsnull,
  1020. /* aPaletteLength = */ nsnull);
  1021. }
  1022. void
  1023. RasterImage::FrameUpdated(PRUint32 aFrameNum, nsIntRect &aUpdatedRect)
  1024. {
  1025. NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
  1026. imgFrame *frame = GetImgFrameNoDecode(aFrameNum);
  1027. NS_ABORT_IF_FALSE(frame, "Calling FrameUpdated on frame that doesn't exist!");
  1028. frame->ImageUpdated(aUpdatedRect);
  1029. // The image has changed, so we need to invalidate our cached ImageContainer.
  1030. mImageContainer = NULL;
  1031. }
  1032. nsresult
  1033. RasterImage::SetFrameDisposalMethod(PRUint32 aFrameNum,
  1034. PRInt32 aDisposalMethod)
  1035. {
  1036. if (mError)
  1037. return NS_ERROR_FAILURE;
  1038. NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
  1039. if (aFrameNum >= mFrames.Length())
  1040. return NS_ERROR_INVALID_ARG;
  1041. imgFrame *frame = GetImgFrame(aFrameNum);
  1042. NS_ABORT_IF_FALSE(frame,
  1043. "Calling SetFrameDisposalMethod on frame that doesn't exist!");
  1044. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  1045. frame->SetFrameDisposalMethod(aDisposalMethod);
  1046. return NS_OK;
  1047. }
  1048. nsresult
  1049. RasterImage::SetFrameTimeout(PRUint32 aFrameNum, PRInt32 aTimeout)
  1050. {
  1051. if (mError)
  1052. return NS_ERROR_FAILURE;
  1053. NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
  1054. if (aFrameNum >= mFrames.Length())
  1055. return NS_ERROR_INVALID_ARG;
  1056. imgFrame *frame = GetImgFrame(aFrameNum);
  1057. NS_ABORT_IF_FALSE(frame, "Calling SetFrameTimeout on frame that doesn't exist!");
  1058. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  1059. frame->SetTimeout(aTimeout);
  1060. return NS_OK;
  1061. }
  1062. nsresult
  1063. RasterImage::SetFrameBlendMethod(PRUint32 aFrameNum, PRInt32 aBlendMethod)
  1064. {
  1065. if (mError)
  1066. return NS_ERROR_FAILURE;
  1067. NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
  1068. if (aFrameNum >= mFrames.Length())
  1069. return NS_ERROR_INVALID_ARG;
  1070. imgFrame *frame = GetImgFrame(aFrameNum);
  1071. NS_ABORT_IF_FALSE(frame, "Calling SetFrameBlendMethod on frame that doesn't exist!");
  1072. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  1073. frame->SetBlendMethod(aBlendMethod);
  1074. return NS_OK;
  1075. }
  1076. nsresult
  1077. RasterImage::SetFrameHasNoAlpha(PRUint32 aFrameNum)
  1078. {
  1079. if (mError)
  1080. return NS_ERROR_FAILURE;
  1081. NS_ABORT_IF_FALSE(aFrameNum < mFrames.Length(), "Invalid frame index!");
  1082. if (aFrameNum >= mFrames.Length())
  1083. return NS_ERROR_INVALID_ARG;
  1084. imgFrame *frame = GetImgFrame(aFrameNum);
  1085. NS_ABORT_IF_FALSE(frame, "Calling SetFrameHasNoAlpha on frame that doesn't exist!");
  1086. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  1087. frame->SetHasNoAlpha();
  1088. return NS_OK;
  1089. }
  1090. nsresult
  1091. RasterImage::DecodingComplete()
  1092. {
  1093. if (mError)
  1094. return NS_ERROR_FAILURE;
  1095. // Flag that we're done decoding.
  1096. // XXX - these should probably be combined when we fix animated image
  1097. // discarding with bug 500402.
  1098. mDecoded = true;
  1099. mHasBeenDecoded = true;
  1100. nsresult rv;
  1101. // We now have one of the qualifications for discarding. Re-evaluate.
  1102. if (CanDiscard()) {
  1103. NS_ABORT_IF_FALSE(!DiscardingActive(),
  1104. "We shouldn't have been discardable before this");
  1105. rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  1106. CONTAINER_ENSURE_SUCCESS(rv);
  1107. }
  1108. // If there's only 1 frame, optimize it. Optimizing animated images
  1109. // is not supported.
  1110. //
  1111. // We don't optimize the frame for multipart images because we reuse
  1112. // the frame.
  1113. if ((mFrames.Length() == 1) && !mMultipart) {
  1114. rv = mFrames[0]->Optimize();
  1115. NS_ENSURE_SUCCESS(rv, rv);
  1116. }
  1117. return NS_OK;
  1118. }
  1119. //******************************************************************************
  1120. /* void StartAnimation () */
  1121. nsresult
  1122. RasterImage::StartAnimation()
  1123. {
  1124. if (mError)
  1125. return NS_ERROR_FAILURE;
  1126. NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
  1127. EnsureAnimExists();
  1128. imgFrame* currentFrame = GetCurrentImgFrame();
  1129. if (currentFrame) {
  1130. if (currentFrame->GetTimeout() < 0) { // -1 means display this frame forever
  1131. mAnimationFinished = true;
  1132. return NS_ERROR_ABORT;
  1133. }
  1134. // We need to set the time that this initial frame was first displayed, as
  1135. // this is used in AdvanceFrame().
  1136. mAnim->currentAnimationFrameTime = TimeStamp::Now();
  1137. }
  1138. return NS_OK;
  1139. }
  1140. //******************************************************************************
  1141. /* void stopAnimation (); */
  1142. nsresult
  1143. RasterImage::StopAnimation()
  1144. {
  1145. NS_ABORT_IF_FALSE(mAnimating, "Should be animating!");
  1146. if (mError)
  1147. return NS_ERROR_FAILURE;
  1148. return NS_OK;
  1149. }
  1150. //******************************************************************************
  1151. /* void resetAnimation (); */
  1152. NS_IMETHODIMP
  1153. RasterImage::ResetAnimation()
  1154. {
  1155. if (mError)
  1156. return NS_ERROR_FAILURE;
  1157. if (mAnimationMode == kDontAnimMode ||
  1158. !mAnim || mAnim->currentAnimationFrameIndex == 0)
  1159. return NS_OK;
  1160. mAnimationFinished = false;
  1161. if (mAnimating)
  1162. StopAnimation();
  1163. mAnim->lastCompositedFrameIndex = -1;
  1164. mAnim->currentAnimationFrameIndex = 0;
  1165. mImageContainer = nsnull;
  1166. // Note - We probably want to kick off a redecode somewhere around here when
  1167. // we fix bug 500402.
  1168. // Update display if we were animating before
  1169. nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
  1170. if (mAnimating && observer)
  1171. observer->FrameChanged(nsnull, this, &(mAnim->firstFrameRefreshArea));
  1172. if (ShouldAnimate()) {
  1173. StartAnimation();
  1174. // The animation may not have been running before, if mAnimationFinished
  1175. // was false (before we changed it to true in this function). So, mark the
  1176. // animation as running.
  1177. mAnimating = true;
  1178. }
  1179. return NS_OK;
  1180. }
  1181. void
  1182. RasterImage::SetLoopCount(PRInt32 aLoopCount)
  1183. {
  1184. if (mError)
  1185. return;
  1186. // -1 infinite
  1187. // 0 no looping, one iteration
  1188. // 1 one loop, two iterations
  1189. // ...
  1190. mLoopCount = aLoopCount;
  1191. }
  1192. nsresult
  1193. RasterImage::AddSourceData(const char *aBuffer, PRUint32 aCount)
  1194. {
  1195. if (mError)
  1196. return NS_ERROR_FAILURE;
  1197. NS_ENSURE_ARG_POINTER(aBuffer);
  1198. nsresult rv = NS_OK;
  1199. // We should not call this if we're not initialized
  1200. NS_ABORT_IF_FALSE(mInitialized, "Calling AddSourceData() on uninitialized "
  1201. "RasterImage!");
  1202. // We should not call this if we're already finished adding source data
  1203. NS_ABORT_IF_FALSE(!mHasSourceData, "Calling AddSourceData() after calling "
  1204. "sourceDataComplete()!");
  1205. // This call should come straight from necko - no reentrancy allowed
  1206. NS_ABORT_IF_FALSE(!mInDecoder, "Re-entrant call to AddSourceData!");
  1207. // If we're not storing source data, write it directly to the decoder
  1208. if (!StoringSourceData()) {
  1209. rv = WriteToDecoder(aBuffer, aCount);
  1210. CONTAINER_ENSURE_SUCCESS(rv);
  1211. // We're not storing source data, so this data is probably coming straight
  1212. // from the network. In this case, we want to display data as soon as we
  1213. // get it, so we want to flush invalidations after every write.
  1214. nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  1215. mInDecoder = true;
  1216. mDecoder->FlushInvalidations();
  1217. mInDecoder = false;
  1218. }
  1219. // Otherwise, we're storing data in the source buffer
  1220. else {
  1221. // Store the data
  1222. char *newElem = mSourceData.AppendElements(aBuffer, aCount);
  1223. if (!newElem)
  1224. return NS_ERROR_OUT_OF_MEMORY;
  1225. // If there's a decoder open, that means we want to do more decoding.
  1226. // Wake up the worker.
  1227. if (mDecoder) {
  1228. DecodeWorker::Singleton()->RequestDecode(this);
  1229. }
  1230. }
  1231. // Statistics
  1232. total_source_bytes += aCount;
  1233. if (mDiscardable)
  1234. discardable_source_bytes += aCount;
  1235. PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
  1236. ("CompressedImageAccounting: Added compressed data to RasterImage %p (%s). "
  1237. "Total Containers: %d, Discardable containers: %d, "
  1238. "Total source bytes: %lld, Source bytes for discardable containers %lld",
  1239. this,
  1240. mSourceDataMimeType.get(),
  1241. num_containers,
  1242. num_discardable_containers,
  1243. total_source_bytes,
  1244. discardable_source_bytes));
  1245. return NS_OK;
  1246. }
  1247. /* Note! buf must be declared as char buf[9]; */
  1248. // just used for logging and hashing the header
  1249. static void
  1250. get_header_str (char *buf, char *data, PRSize data_len)
  1251. {
  1252. int i;
  1253. int n;
  1254. static char hex[] = "0123456789abcdef";
  1255. n = data_len < 4 ? data_len : 4;
  1256. for (i = 0; i < n; i++) {
  1257. buf[i * 2] = hex[(data[i] >> 4) & 0x0f];
  1258. buf[i * 2 + 1] = hex[data[i] & 0x0f];
  1259. }
  1260. buf[i * 2] = 0;
  1261. }
  1262. nsresult
  1263. RasterImage::SourceDataComplete()
  1264. {
  1265. if (mError)
  1266. return NS_ERROR_FAILURE;
  1267. // If we've been called before, ignore. Otherwise, flag that we have everything
  1268. if (mHasSourceData)
  1269. return NS_OK;
  1270. mHasSourceData = true;
  1271. // This call should come straight from necko - no reentrancy allowed
  1272. NS_ABORT_IF_FALSE(!mInDecoder, "Re-entrant call to AddSourceData!");
  1273. // If we're not storing any source data, then all the data was written
  1274. // directly to the decoder in the AddSourceData() calls. This means we're
  1275. // done, so we can shut down the decoder.
  1276. if (!StoringSourceData()) {
  1277. nsresult rv = ShutdownDecoder(eShutdownIntent_Done);
  1278. CONTAINER_ENSURE_SUCCESS(rv);
  1279. }
  1280. // If there's a decoder open, synchronously decode the beginning of the image
  1281. // to check for errors and get the image's size. (If we already have the
  1282. // image's size, this does nothing.) Then kick off an async decode of the
  1283. // rest of the image.
  1284. if (mDecoder) {
  1285. nsresult rv = DecodeWorker::Singleton()->DecodeUntilSizeAvailable(this);
  1286. CONTAINER_ENSURE_SUCCESS(rv);
  1287. }
  1288. // If DecodeUntilSizeAvailable didn't finish the decode, let the decode worker
  1289. // finish decoding this image.
  1290. if (mDecoder) {
  1291. DecodeWorker::Singleton()->RequestDecode(this);
  1292. }
  1293. // Free up any extra space in the backing buffer
  1294. mSourceData.Compact();
  1295. // Log header information
  1296. if (PR_LOG_TEST(gCompressedImageAccountingLog, PR_LOG_DEBUG)) {
  1297. char buf[9];
  1298. get_header_str(buf, mSourceData.Elements(), mSourceData.Length());
  1299. PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
  1300. ("CompressedImageAccounting: RasterImage::SourceDataComplete() - data "
  1301. "is done for container %p (%s) - header %p is 0x%s (length %d)",
  1302. this,
  1303. mSourceDataMimeType.get(),
  1304. mSourceData.Elements(),
  1305. buf,
  1306. mSourceData.Length()));
  1307. }
  1308. // We now have one of the qualifications for discarding. Re-evaluate.
  1309. if (CanDiscard()) {
  1310. nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  1311. CONTAINER_ENSURE_SUCCESS(rv);
  1312. }
  1313. return NS_OK;
  1314. }
  1315. nsresult
  1316. RasterImage::NewSourceData()
  1317. {
  1318. nsresult rv;
  1319. if (mError)
  1320. return NS_ERROR_FAILURE;
  1321. // The source data should be complete before calling this
  1322. NS_ABORT_IF_FALSE(mHasSourceData,
  1323. "Calling NewSourceData before SourceDataComplete!");
  1324. if (!mHasSourceData)
  1325. return NS_ERROR_ILLEGAL_VALUE;
  1326. // Only supported for multipart channels. It wouldn't be too hard to change this,
  1327. // but it would involve making sure that things worked for decode-on-draw and
  1328. // discarding. Presently there's no need for this, so we don't.
  1329. NS_ABORT_IF_FALSE(mMultipart, "NewSourceData not supported for multipart");
  1330. if (!mMultipart)
  1331. return NS_ERROR_ILLEGAL_VALUE;
  1332. // We're multipart, so we shouldn't be storing source data
  1333. NS_ABORT_IF_FALSE(!StoringSourceData(),
  1334. "Shouldn't be storing source data for multipart");
  1335. // We're not storing the source data and we got SourceDataComplete. We should
  1336. // have shut down the previous decoder
  1337. NS_ABORT_IF_FALSE(!mDecoder, "Shouldn't have a decoder in NewSourceData");
  1338. // The decoder was shut down and we didn't flag an error, so we should be decoded
  1339. NS_ABORT_IF_FALSE(mDecoded, "Should be decoded in NewSourceData");
  1340. // Reset some flags
  1341. mDecoded = false;
  1342. mHasSourceData = false;
  1343. // We're decode-on-load here. Open up a new decoder just like what happens when
  1344. // we call Init() for decode-on-load images.
  1345. rv = InitDecoder(/* aDoSizeDecode = */ false);
  1346. CONTAINER_ENSURE_SUCCESS(rv);
  1347. return NS_OK;
  1348. }
  1349. nsresult
  1350. RasterImage::SetSourceSizeHint(PRUint32 sizeHint)
  1351. {
  1352. if (sizeHint && StoringSourceData())
  1353. return mSourceData.SetCapacity(sizeHint) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  1354. return NS_OK;
  1355. }
  1356. //******************************************************************************
  1357. // DoComposite gets called when the timer for animation get fired and we have to
  1358. // update the composited frame of the animation.
  1359. nsresult
  1360. RasterImage::DoComposite(nsIntRect* aDirtyRect,
  1361. imgFrame* aPrevFrame,
  1362. imgFrame* aNextFrame,
  1363. PRInt32 aNextFrameIndex)
  1364. {
  1365. NS_ENSURE_ARG_POINTER(aDirtyRect);
  1366. NS_ENSURE_ARG_POINTER(aPrevFrame);
  1367. NS_ENSURE_ARG_POINTER(aNextFrame);
  1368. PRInt32 prevFrameDisposalMethod = aPrevFrame->GetFrameDisposalMethod();
  1369. if (prevFrameDisposalMethod == kDisposeRestorePrevious &&
  1370. !mAnim->compositingPrevFrame)
  1371. prevFrameDisposalMethod = kDisposeClear;
  1372. nsIntRect prevFrameRect = aPrevFrame->GetRect();
  1373. bool isFullPrevFrame = (prevFrameRect.x == 0 && prevFrameRect.y == 0 &&
  1374. prevFrameRect.width == mSize.width &&
  1375. prevFrameRect.height == mSize.height);
  1376. // Optimization: DisposeClearAll if the previous frame is the same size as
  1377. // container and it's clearing itself
  1378. if (isFullPrevFrame &&
  1379. (prevFrameDisposalMethod == kDisposeClear))
  1380. prevFrameDisposalMethod = kDisposeClearAll;
  1381. PRInt32 nextFrameDisposalMethod = aNextFrame->GetFrameDisposalMethod();
  1382. nsIntRect nextFrameRect = aNextFrame->GetRect();
  1383. bool isFullNextFrame = (nextFrameRect.x == 0 && nextFrameRect.y == 0 &&
  1384. nextFrameRect.width == mSize.width &&
  1385. nextFrameRect.height == mSize.height);
  1386. if (!aNextFrame->GetIsPaletted()) {
  1387. // Optimization: Skip compositing if the previous frame wants to clear the
  1388. // whole image
  1389. if (prevFrameDisposalMethod == kDisposeClearAll) {
  1390. aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
  1391. return NS_OK;
  1392. }
  1393. // Optimization: Skip compositing if this frame is the same size as the
  1394. // container and it's fully drawing over prev frame (no alpha)
  1395. if (isFullNextFrame &&
  1396. (nextFrameDisposalMethod != kDisposeRestorePrevious) &&
  1397. !aNextFrame->GetHasAlpha()) {
  1398. aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
  1399. return NS_OK;
  1400. }
  1401. }
  1402. // Calculate area that needs updating
  1403. switch (prevFrameDisposalMethod) {
  1404. default:
  1405. case kDisposeNotSpecified:
  1406. case kDisposeKeep:
  1407. *aDirtyRect = nextFrameRect;
  1408. break;
  1409. case kDisposeClearAll:
  1410. // Whole image container is cleared
  1411. aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
  1412. break;
  1413. case kDisposeClear:
  1414. // Calc area that needs to be redrawn (the combination of previous and
  1415. // this frame)
  1416. // XXX - This could be done with multiple framechanged calls
  1417. // Having prevFrame way at the top of the image, and nextFrame
  1418. // way at the bottom, and both frames being small, we'd be
  1419. // telling framechanged to refresh the whole image when only two
  1420. // small areas are needed.
  1421. aDirtyRect->UnionRect(nextFrameRect, prevFrameRect);
  1422. break;
  1423. case kDisposeRestorePrevious:
  1424. aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
  1425. break;
  1426. }
  1427. // Optimization:
  1428. // Skip compositing if the last composited frame is this frame
  1429. // (Only one composited frame was made for this animation. Example:
  1430. // Only Frame 3 of a 10 frame image required us to build a composite frame
  1431. // On the second loop, we do not need to rebuild the frame
  1432. // since it's still sitting in compositingFrame)
  1433. if (mAnim->lastCompositedFrameIndex == aNextFrameIndex) {
  1434. return NS_OK;
  1435. }
  1436. bool needToBlankComposite = false;
  1437. // Create the Compositing Frame
  1438. if (!mAnim->compositingFrame) {
  1439. mAnim->compositingFrame = new imgFrame();
  1440. nsresult rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height,
  1441. gfxASurface::ImageFormatARGB32);
  1442. if (NS_FAILED(rv)) {
  1443. mAnim->compositingFrame = nsnull;
  1444. return rv;
  1445. }
  1446. needToBlankComposite = true;
  1447. } else if (aNextFrameIndex != mAnim->lastCompositedFrameIndex+1) {
  1448. // If we are not drawing on top of last composited frame,
  1449. // then we are building a new composite frame, so let's clear it first.
  1450. needToBlankComposite = true;
  1451. }
  1452. // More optimizations possible when next frame is not transparent
  1453. // But if the next frame has kDisposeRestorePrevious,
  1454. // this "no disposal" optimization is not possible,
  1455. // because the frame in "after disposal operation" state
  1456. // needs to be stored in compositingFrame, so it can be
  1457. // copied into compositingPrevFrame later.
  1458. bool doDisposal = true;
  1459. if (!aNextFrame->GetHasAlpha() &&
  1460. nextFrameDisposalMethod != kDisposeRestorePrevious) {
  1461. if (isFullNextFrame) {
  1462. // Optimization: No need to dispose prev.frame when
  1463. // next frame is full frame and not transparent.
  1464. doDisposal = false;
  1465. // No need to blank the composite frame
  1466. needToBlankComposite = false;
  1467. } else {
  1468. if ((prevFrameRect.x >= nextFrameRect.x) &&
  1469. (prevFrameRect.y >= nextFrameRect.y) &&
  1470. (prevFrameRect.x + prevFrameRect.width <= nextFrameRect.x + nextFrameRect.width) &&
  1471. (prevFrameRect.y + prevFrameRect.height <= nextFrameRect.y + nextFrameRect.height)) {
  1472. // Optimization: No need to dispose prev.frame when
  1473. // next frame fully overlaps previous frame.
  1474. doDisposal = false;
  1475. }
  1476. }
  1477. }
  1478. if (doDisposal) {
  1479. // Dispose of previous: clear, restore, or keep (copy)
  1480. switch (prevFrameDisposalMethod) {
  1481. case kDisposeClear:
  1482. if (needToBlankComposite) {
  1483. // If we just created the composite, it could have anything in it's
  1484. // buffer. Clear whole frame
  1485. ClearFrame(mAnim->compositingFrame);
  1486. } else {
  1487. // Only blank out previous frame area (both color & Mask/Alpha)
  1488. ClearFrame(mAnim->compositingFrame, prevFrameRect);
  1489. }
  1490. break;
  1491. case kDisposeClearAll:
  1492. ClearFrame(mAnim->compositingFrame);
  1493. break;
  1494. case kDisposeRestorePrevious:
  1495. // It would be better to copy only the area changed back to
  1496. // compositingFrame.
  1497. if (mAnim->compositingPrevFrame) {
  1498. CopyFrameImage(mAnim->compositingPrevFrame, mAnim->compositingFrame);
  1499. // destroy only if we don't need it for this frame's disposal
  1500. if (nextFrameDisposalMethod != kDisposeRestorePrevious)
  1501. mAnim->compositingPrevFrame = nsnull;
  1502. } else {
  1503. ClearFrame(mAnim->compositingFrame);
  1504. }
  1505. break;
  1506. default:
  1507. // Copy previous frame into compositingFrame before we put the new frame on top
  1508. // Assumes that the previous frame represents a full frame (it could be
  1509. // smaller in size than the container, as long as the frame before it erased
  1510. // itself)
  1511. // Note: Frame 1 never gets into DoComposite(), so (aNextFrameIndex - 1) will
  1512. // always be a valid frame number.
  1513. if (mAnim->lastCompositedFrameIndex != aNextFrameIndex - 1) {
  1514. if (isFullPrevFrame && !aPrevFrame->GetIsPaletted()) {
  1515. // Just copy the bits
  1516. CopyFrameImage(aPrevFrame, mAnim->compositingFrame);
  1517. } else {
  1518. if (needToBlankComposite) {
  1519. // Only blank composite when prev is transparent or not full.
  1520. if (aPrevFrame->GetHasAlpha() || !isFullPrevFrame) {
  1521. ClearFrame(mAnim->compositingFrame);
  1522. }
  1523. }
  1524. DrawFrameTo(aPrevFrame, mAnim->compositingFrame, prevFrameRect);
  1525. }
  1526. }
  1527. }
  1528. } else if (needToBlankComposite) {
  1529. // If we just created the composite, it could have anything in it's
  1530. // buffers. Clear them
  1531. ClearFrame(mAnim->compositingFrame);
  1532. }
  1533. // Check if the frame we are composing wants the previous image restored afer
  1534. // it is done. Don't store it (again) if last frame wanted its image restored
  1535. // too
  1536. if ((nextFrameDisposalMethod == kDisposeRestorePrevious) &&
  1537. (prevFrameDisposalMethod != kDisposeRestorePrevious)) {
  1538. // We are storing the whole image.
  1539. // It would be better if we just stored the area that nextFrame is going to
  1540. // overwrite.
  1541. if (!mAnim->compositingPrevFrame) {
  1542. mAnim->compositingPrevFrame = new imgFrame();
  1543. nsresult rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height,
  1544. gfxASurface::ImageFormatARGB32);
  1545. if (NS_FAILED(rv)) {
  1546. mAnim->compositingPrevFrame = nsnull;
  1547. return rv;
  1548. }
  1549. }
  1550. CopyFrameImage(mAnim->compositingFrame, mAnim->compositingPrevFrame);
  1551. }
  1552. // blit next frame into it's correct spot
  1553. DrawFrameTo(aNextFrame, mAnim->compositingFrame, nextFrameRect);
  1554. // Set timeout of CompositeFrame to timeout of frame we just composed
  1555. // Bug 177948
  1556. PRInt32 timeout = aNextFrame->GetTimeout();
  1557. mAnim->compositingFrame->SetTimeout(timeout);
  1558. // Tell the image that it is fully 'downloaded'.
  1559. nsresult rv = mAnim->compositingFrame->ImageUpdated(mAnim->compositingFrame->GetRect());
  1560. if (NS_FAILED(rv)) {
  1561. return rv;
  1562. }
  1563. // We don't want to keep composite images for 8bit frames.
  1564. // Also this optimization won't work if the next frame has
  1565. // kDisposeRestorePrevious, because it would need to be restored
  1566. // into "after prev disposal but before next blend" state,
  1567. // not into empty frame.
  1568. if (isFullNextFrame && mAnimationMode == kNormalAnimMode && mLoopCount != 0 &&
  1569. nextFrameDisposalMethod != kDisposeRestorePrevious &&
  1570. !aNextFrame->GetIsPaletted()) {
  1571. // We have a composited full frame
  1572. // Store the composited frame into the mFrames[..] so we don't have to
  1573. // continuously re-build it
  1574. // Then set the previous frame's disposal to CLEAR_ALL so we just draw the
  1575. // frame next time around
  1576. if (CopyFrameImage(mAnim->compositingFrame, aNextFrame)) {
  1577. aPrevFrame->SetFrameDisposalMethod(kDisposeClearAll);
  1578. mAnim->lastCompositedFrameIndex = -1;
  1579. return NS_OK;
  1580. }
  1581. }
  1582. mAnim->lastCompositedFrameIndex = aNextFrameIndex;
  1583. return NS_OK;
  1584. }
  1585. //******************************************************************************
  1586. // Fill aFrame with black. Does also clears the mask.
  1587. void
  1588. RasterImage::ClearFrame(imgFrame *aFrame)
  1589. {
  1590. if (!aFrame)
  1591. return;
  1592. nsresult rv = aFrame->LockImageData();
  1593. if (NS_FAILED(rv))
  1594. return;
  1595. nsRefPtr<gfxASurface> surf;
  1596. aFrame->GetSurface(getter_AddRefs(surf));
  1597. // Erase the surface to transparent
  1598. gfxContext ctx(surf);
  1599. ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
  1600. ctx.Paint();
  1601. aFrame->UnlockImageData();
  1602. }
  1603. //******************************************************************************
  1604. void
  1605. RasterImage::ClearFrame(imgFrame *aFrame, nsIntRect &aRect)
  1606. {
  1607. if (!aFrame || aRect.width <= 0 || aRect.height <= 0)
  1608. return;
  1609. nsresult rv = aFrame->LockImageData();
  1610. if (NS_FAILED(rv))
  1611. return;
  1612. nsRefPtr<gfxASurface> surf;
  1613. aFrame->GetSurface(getter_AddRefs(surf));
  1614. // Erase the destination rectangle to transparent
  1615. gfxContext ctx(surf);
  1616. ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
  1617. ctx.Rectangle(gfxRect(aRect.x, aRect.y, aRect.width, aRect.height));
  1618. ctx.Fill();
  1619. aFrame->UnlockImageData();
  1620. }
  1621. //******************************************************************************
  1622. // Whether we succeed or fail will not cause a crash, and there's not much
  1623. // we can do about a failure, so there we don't return a nsresult
  1624. bool
  1625. RasterImage::CopyFrameImage(imgFrame *aSrcFrame,
  1626. imgFrame *aDstFrame)
  1627. {
  1628. PRUint8* aDataSrc;
  1629. PRUint8* aDataDest;
  1630. PRUint32 aDataLengthSrc;
  1631. PRUint32 aDataLengthDest;
  1632. if (!aSrcFrame || !aDstFrame)
  1633. return false;
  1634. if (NS_FAILED(aDstFrame->LockImageData()))
  1635. return false;
  1636. // Copy Image Over
  1637. aSrcFrame->GetImageData(&aDataSrc, &aDataLengthSrc);
  1638. aDstFrame->GetImageData(&aDataDest, &aDataLengthDest);
  1639. if (!aDataDest || !aDataSrc || aDataLengthDest != aDataLengthSrc) {
  1640. aDstFrame->UnlockImageData();
  1641. return false;
  1642. }
  1643. memcpy(aDataDest, aDataSrc, aDataLengthSrc);
  1644. aDstFrame->UnlockImageData();
  1645. return true;
  1646. }
  1647. //******************************************************************************
  1648. /*
  1649. * aSrc is the current frame being drawn,
  1650. * aDst is the composition frame where the current frame is drawn into.
  1651. * aSrcRect is the size of the current frame, and the position of that frame
  1652. * in the composition frame.
  1653. */
  1654. nsresult
  1655. RasterImage::DrawFrameTo(imgFrame *aSrc,
  1656. imgFrame *aDst,
  1657. nsIntRect& aSrcRect)
  1658. {
  1659. NS_ENSURE_ARG_POINTER(aSrc);
  1660. NS_ENSURE_ARG_POINTER(aDst);
  1661. nsIntRect dstRect = aDst->GetRect();
  1662. // According to both AGIF and APNG specs, offsets are unsigned
  1663. if (aSrcRect.x < 0 || aSrcRect.y < 0) {
  1664. NS_WARNING("RasterImage::DrawFrameTo: negative offsets not allowed");
  1665. return NS_ERROR_FAILURE;
  1666. }
  1667. // Outside the destination frame, skip it
  1668. if ((aSrcRect.x > dstRect.width) || (aSrcRect.y > dstRect.height)) {
  1669. return NS_OK;
  1670. }
  1671. if (aSrc->GetIsPaletted()) {
  1672. // Larger than the destination frame, clip it
  1673. PRInt32 width = NS_MIN(aSrcRect.width, dstRect.width - aSrcRect.x);
  1674. PRInt32 height = NS_MIN(aSrcRect.height, dstRect.height - aSrcRect.y);
  1675. // The clipped image must now fully fit within destination image frame
  1676. NS_ASSERTION((aSrcRect.x >= 0) && (aSrcRect.y >= 0) &&
  1677. (aSrcRect.x + width <= dstRect.width) &&
  1678. (aSrcRect.y + height <= dstRect.height),
  1679. "RasterImage::DrawFrameTo: Invalid aSrcRect");
  1680. // clipped image size may be smaller than source, but not larger
  1681. NS_ASSERTION((width <= aSrcRect.width) && (height <= aSrcRect.height),
  1682. "RasterImage::DrawFrameTo: source must be smaller than dest");
  1683. if (NS_FAILED(aDst->LockImageData()))
  1684. return NS_ERROR_FAILURE;
  1685. // Get pointers to image data
  1686. PRUint32 size;
  1687. PRUint8 *srcPixels;
  1688. PRUint32 *colormap;
  1689. PRUint32 *dstPixels;
  1690. aSrc->GetImageData(&srcPixels, &size);
  1691. aSrc->GetPaletteData(&colormap, &size);
  1692. aDst->GetImageData((PRUint8 **)&dstPixels, &size);
  1693. if (!srcPixels || !dstPixels || !colormap) {
  1694. aDst->UnlockImageData();
  1695. return NS_ERROR_FAILURE;
  1696. }
  1697. // Skip to the right offset
  1698. dstPixels += aSrcRect.x + (aSrcRect.y * dstRect.width);
  1699. if (!aSrc->GetHasAlpha()) {
  1700. for (PRInt32 r = height; r > 0; --r) {
  1701. for (PRInt32 c = 0; c < width; c++) {
  1702. dstPixels[c] = colormap[srcPixels[c]];
  1703. }
  1704. // Go to the next row in the source resp. destination image
  1705. srcPixels += aSrcRect.width;
  1706. dstPixels += dstRect.width;
  1707. }
  1708. } else {
  1709. for (PRInt32 r = height; r > 0; --r) {
  1710. for (PRInt32 c = 0; c < width; c++) {
  1711. const PRUint32 color = colormap[srcPixels[c]];
  1712. if (color)
  1713. dstPixels[c] = color;
  1714. }
  1715. // Go to the next row in the source resp. destination image
  1716. srcPixels += aSrcRect.width;
  1717. dstPixels += dstRect.width;
  1718. }
  1719. }
  1720. aDst->UnlockImageData();
  1721. return NS_OK;
  1722. }
  1723. nsRefPtr<gfxPattern> srcPatt;
  1724. aSrc->GetPattern(getter_AddRefs(srcPatt));
  1725. aDst->LockImageData();
  1726. nsRefPtr<gfxASurface> dstSurf;
  1727. aDst->GetSurface(getter_AddRefs(dstSurf));
  1728. gfxContext dst(dstSurf);
  1729. dst.Translate(gfxPoint(aSrcRect.x, aSrcRect.y));
  1730. dst.Rectangle(gfxRect(0, 0, aSrcRect.width, aSrcRect.height), true);
  1731. // first clear the surface if the blend flag says so
  1732. PRInt32 blendMethod = aSrc->GetBlendMethod();
  1733. if (blendMethod == kBlendSource) {
  1734. gfxContext::GraphicsOperator defaultOperator = dst.CurrentOperator();
  1735. dst.SetOperator(gfxContext::OPERATOR_CLEAR);
  1736. dst.Fill();
  1737. dst.SetOperator(defaultOperator);
  1738. }
  1739. dst.SetPattern(srcPatt);
  1740. dst.Paint();
  1741. aDst->UnlockImageData();
  1742. return NS_OK;
  1743. }
  1744. /********* Methods to implement lazy allocation of nsIProperties object *************/
  1745. NS_IMETHODIMP
  1746. RasterImage::Get(const char *prop, const nsIID & iid, void * *result)
  1747. {
  1748. if (!mProperties)
  1749. return NS_ERROR_FAILURE;
  1750. return mProperties->Get(prop, iid, result);
  1751. }
  1752. NS_IMETHODIMP
  1753. RasterImage::Set(const char *prop, nsISupports *value)
  1754. {
  1755. if (!mProperties)
  1756. mProperties = do_CreateInstance("@mozilla.org/properties;1");
  1757. if (!mProperties)
  1758. return NS_ERROR_OUT_OF_MEMORY;
  1759. return mProperties->Set(prop, value);
  1760. }
  1761. NS_IMETHODIMP
  1762. RasterImage::Has(const char *prop, bool *_retval)
  1763. {
  1764. NS_ENSURE_ARG_POINTER(_retval);
  1765. if (!mProperties) {
  1766. *_retval = false;
  1767. return NS_OK;
  1768. }
  1769. return mProperties->Has(prop, _retval);
  1770. }
  1771. NS_IMETHODIMP
  1772. RasterImage::Undefine(const char *prop)
  1773. {
  1774. if (!mProperties)
  1775. return NS_ERROR_FAILURE;
  1776. return mProperties->Undefine(prop);
  1777. }
  1778. NS_IMETHODIMP
  1779. RasterImage::GetKeys(PRUint32 *count, char ***keys)
  1780. {
  1781. if (!mProperties) {
  1782. *count = 0;
  1783. *keys = nsnull;
  1784. return NS_OK;
  1785. }
  1786. return mProperties->GetKeys(count, keys);
  1787. }
  1788. void
  1789. RasterImage::Discard(bool force)
  1790. {
  1791. // We should be ok for discard
  1792. NS_ABORT_IF_FALSE(force ? CanForciblyDiscard() : CanDiscard(), "Asked to discard but can't!");
  1793. // We should never discard when we have an active decoder
  1794. NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
  1795. // As soon as an image becomes animated, it becomes non-discardable and any
  1796. // timers are cancelled.
  1797. NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
  1798. // For post-operation logging
  1799. int old_frame_count = mFrames.Length();
  1800. // Delete all the decoded frames, then clear the array.
  1801. for (int i = 0; i < old_frame_count; ++i)
  1802. delete mFrames[i];
  1803. mFrames.Clear();
  1804. // Flag that we no longer have decoded frames for this image
  1805. mDecoded = false;
  1806. // Notify that we discarded
  1807. nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(mObserver));
  1808. if (observer)
  1809. observer->OnDiscard(nsnull);
  1810. if (force)
  1811. DiscardTracker::Remove(&mDiscardTrackerNode);
  1812. // Log
  1813. PR_LOG(gCompressedImageAccountingLog, PR_LOG_DEBUG,
  1814. ("CompressedImageAccounting: discarded uncompressed image "
  1815. "data from RasterImage %p (%s) - %d frames (cached count: %d); "
  1816. "Total Containers: %d, Discardable containers: %d, "
  1817. "Total source bytes: %lld, Source bytes for discardable containers %lld",
  1818. this,
  1819. mSourceDataMimeType.get(),
  1820. old_frame_count,
  1821. mFrames.Length(),
  1822. num_containers,
  1823. num_discardable_containers,
  1824. total_source_bytes,
  1825. discardable_source_bytes));
  1826. }
  1827. // Helper method to determine if we can discard an image
  1828. bool
  1829. RasterImage::CanDiscard() {
  1830. return (DiscardingEnabled() && // Globally enabled...
  1831. mDiscardable && // ...Enabled at creation time...
  1832. (mLockCount == 0) && // ...not temporarily disabled...
  1833. mHasSourceData && // ...have the source data...
  1834. mDecoded); // ...and have something to discard.
  1835. }
  1836. bool
  1837. RasterImage::CanForciblyDiscard() {
  1838. return mDiscardable && // ...Enabled at creation time...
  1839. mHasSourceData; // ...have the source data...
  1840. }
  1841. // Helper method to tell us whether the clock is currently running for
  1842. // discarding this image. Mainly for assertions.
  1843. bool
  1844. RasterImage::DiscardingActive() {
  1845. return !!(mDiscardTrackerNode.prev || mDiscardTrackerNode.next);
  1846. }
  1847. // Helper method to determine if we're storing the source data in a buffer
  1848. // or just writing it directly to the decoder
  1849. bool
  1850. RasterImage::StoringSourceData() {
  1851. return (mDecodeOnDraw || mDiscardable);
  1852. }
  1853. // Sets up a decoder for this image. It is an error to call this function
  1854. // when decoding is already in process (ie - when mDecoder is non-null).
  1855. nsresult
  1856. RasterImage::InitDecoder(bool aDoSizeDecode)
  1857. {
  1858. // Ensure that the decoder is not already initialized
  1859. NS_ABORT_IF_FALSE(!mDecoder, "Calling InitDecoder() while already decoding!");
  1860. // We shouldn't be firing up a decoder if we already have the frames decoded
  1861. NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
  1862. // Since we're not decoded, we should not have a discard timer active
  1863. NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
  1864. // Figure out which decoder we want
  1865. eDecoderType type = GetDecoderType(mSourceDataMimeType.get());
  1866. CONTAINER_ENSURE_TRUE(type != eDecoderType_unknown, NS_IMAGELIB_ERROR_NO_DECODER);
  1867. nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(mObserver));
  1868. // Instantiate the appropriate decoder
  1869. switch (type) {
  1870. case eDecoderType_png:
  1871. mDecoder = new nsPNGDecoder(*this, observer);
  1872. break;
  1873. case eDecoderType_gif:
  1874. mDecoder = new nsGIFDecoder2(*this, observer);
  1875. break;
  1876. case eDecoderType_jpeg:
  1877. mDecoder = new nsJPEGDecoder(*this, observer);
  1878. break;
  1879. case eDecoderType_bmp:
  1880. mDecoder = new nsBMPDecoder(*this, observer);
  1881. break;
  1882. case eDecoderType_ico:
  1883. mDecoder = new nsICODecoder(*this, observer);
  1884. break;
  1885. case eDecoderType_icon:
  1886. mDecoder = new nsIconDecoder(*this, observer);
  1887. break;
  1888. default:
  1889. NS_ABORT_IF_FALSE(0, "Shouldn't get here!");
  1890. }
  1891. // Initialize the decoder
  1892. mDecoder->SetSizeDecode(aDoSizeDecode);
  1893. mDecoder->SetDecodeFlags(mFrameDecodeFlags);
  1894. mDecoder->Init();
  1895. CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
  1896. if (!aDoSizeDecode) {
  1897. Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
  1898. mDecodeCount++;
  1899. Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
  1900. }
  1901. return NS_OK;
  1902. }
  1903. // Flushes, closes, and nulls-out a decoder. Cleans up any related decoding
  1904. // state. It is an error to call this function when there is no initialized
  1905. // decoder.
  1906. //
  1907. // aIntent specifies the intent of the shutdown. If aIntent is
  1908. // eShutdownIntent_Done, an error is flagged if we didn't get what we should
  1909. // have out of the decode. If aIntent is eShutdownIntent_Interrupted, we don't
  1910. // check this. If aIntent is eShutdownIntent_Error, we shut down in error mode.
  1911. nsresult
  1912. RasterImage::ShutdownDecoder(eShutdownIntent aIntent)
  1913. {
  1914. // Ensure that our intent is valid
  1915. NS_ABORT_IF_FALSE((aIntent >= 0) || (aIntent < eShutdownIntent_AllCount),
  1916. "Invalid shutdown intent");
  1917. // Ensure that the decoder is initialized
  1918. NS_ABORT_IF_FALSE(mDecoder, "Calling ShutdownDecoder() with no active decoder!");
  1919. // Figure out what kind of decode we were doing before we get rid of our decoder
  1920. bool wasSizeDecode = mDecoder->IsSizeDecode();
  1921. // Finalize the decoder
  1922. // null out mDecoder, _then_ check for errors on the close (otherwise the
  1923. // error routine might re-invoke ShutdownDecoder)
  1924. nsRefPtr<Decoder> decoder = mDecoder;
  1925. mDecoder = nsnull;
  1926. mInDecoder = true;
  1927. decoder->Finish();
  1928. mInDecoder = false;
  1929. // Kill off our decode request, if it's pending. (If not, this call is
  1930. // harmless.)
  1931. DecodeWorker::Singleton()->StopDecoding(this);
  1932. nsresult decoderStatus = decoder->GetDecoderError();
  1933. if (NS_FAILED(decoderStatus)) {
  1934. DoError();
  1935. return decoderStatus;
  1936. }
  1937. // We just shut down the decoder. If we didn't get what we want, but expected
  1938. // to, flag an error
  1939. bool failed = false;
  1940. if (wasSizeDecode && !mHasSize)
  1941. failed = true;
  1942. if (!wasSizeDecode && !mDecoded)
  1943. failed = true;
  1944. if ((aIntent == eShutdownIntent_Done) && failed) {
  1945. DoError();
  1946. return NS_ERROR_FAILURE;
  1947. }
  1948. // Reset number of decoded bytes
  1949. mBytesDecoded = 0;
  1950. return NS_OK;
  1951. }
  1952. // Writes the data to the decoder, updating the total number of bytes written.
  1953. nsresult
  1954. RasterImage::WriteToDecoder(const char *aBuffer, PRUint32 aCount)
  1955. {
  1956. // We should have a decoder
  1957. NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
  1958. // The decoder will start decoding into the current frame (if we have one).
  1959. // When it needs to add another frame, we will unlock this frame and lock the
  1960. // new frame.
  1961. // Our invariant is that, while in the decoder, the last frame is always
  1962. // locked, and all others are unlocked.
  1963. if (mFrames.Length() > 0) {
  1964. imgFrame *curframe = mFrames.ElementAt(mFrames.Length() - 1);
  1965. curframe->LockImageData();
  1966. }
  1967. // Write
  1968. nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  1969. mInDecoder = true;
  1970. mDecoder->Write(aBuffer, aCount);
  1971. mInDecoder = false;
  1972. // We unlock the current frame, even if that frame is different from the
  1973. // frame we entered the decoder with. (See above.)
  1974. if (mFrames.Length() > 0) {
  1975. imgFrame *curframe = mFrames.ElementAt(mFrames.Length() - 1);
  1976. curframe->UnlockImageData();
  1977. }
  1978. if (!mDecoder)
  1979. return NS_ERROR_FAILURE;
  1980. CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
  1981. // Keep track of the total number of bytes written over the lifetime of the
  1982. // decoder
  1983. mBytesDecoded += aCount;
  1984. return NS_OK;
  1985. }
  1986. // This function is called in situations where it's clear that we want the
  1987. // frames in decoded form (Draw, GetFrame, CopyFrame, ExtractFrame, etc).
  1988. // If we're completely decoded, this method resets the discard timer (if
  1989. // we're discardable), since wanting the frames now is a good indicator of
  1990. // wanting them again soon. If we're not decoded, this method kicks off
  1991. // asynchronous decoding to generate the frames.
  1992. nsresult
  1993. RasterImage::WantDecodedFrames()
  1994. {
  1995. nsresult rv;
  1996. // If we can discard, the clock should be running. Reset it.
  1997. if (CanDiscard()) {
  1998. NS_ABORT_IF_FALSE(DiscardingActive(),
  1999. "Decoded and discardable but discarding not activated!");
  2000. rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  2001. CONTAINER_ENSURE_SUCCESS(rv);
  2002. }
  2003. // Request a decode (no-op if we're decoded)
  2004. return RequestDecode();
  2005. }
  2006. //******************************************************************************
  2007. /* void requestDecode() */
  2008. NS_IMETHODIMP
  2009. RasterImage::RequestDecode()
  2010. {
  2011. nsresult rv;
  2012. if (mError)
  2013. return NS_ERROR_FAILURE;
  2014. // If we're fully decoded, we have nothing to do
  2015. if (mDecoded)
  2016. return NS_OK;
  2017. // If we're not storing source data, we have nothing to do
  2018. if (!StoringSourceData())
  2019. return NS_OK;
  2020. // If we've already got a full decoder running, we have nothing to do
  2021. if (mDecoder && !mDecoder->IsSizeDecode())
  2022. return NS_OK;
  2023. // If our callstack goes through a size decoder, we have a problem.
  2024. // We need to shutdown the size decode and replace it with a full
  2025. // decoder, but can't do that from within the decoder itself. Thus, we post
  2026. // an asynchronous event to the event loop to do it later. Since
  2027. // RequestDecode() is an asynchronous function this works fine (though it's
  2028. // a little slower).
  2029. if (mInDecoder) {
  2030. nsRefPtr<imgDecodeRequestor> requestor = new imgDecodeRequestor(this);
  2031. return NS_DispatchToCurrentThread(requestor);
  2032. }
  2033. // If we have a size decode open, interrupt it and shut it down; or if
  2034. // the decoder has different flags than what we need
  2035. if (mDecoder &&
  2036. (mDecoder->IsSizeDecode() || mDecoder->GetDecodeFlags() != mFrameDecodeFlags))
  2037. {
  2038. rv = ShutdownDecoder(eShutdownIntent_Interrupted);
  2039. CONTAINER_ENSURE_SUCCESS(rv);
  2040. }
  2041. // If we don't have a decoder, create one
  2042. if (!mDecoder) {
  2043. NS_ABORT_IF_FALSE(mFrames.IsEmpty(), "Trying to decode to non-empty frame-array");
  2044. rv = InitDecoder(/* aDoSizeDecode = */ false);
  2045. CONTAINER_ENSURE_SUCCESS(rv);
  2046. }
  2047. // If we've read all the data we have, we're done
  2048. if (mBytesDecoded == mSourceData.Length())
  2049. return NS_OK;
  2050. // If it's a smallish image, it's not worth it to do things async
  2051. if (!mDecoded && !mInDecoder && mHasSourceData && (mSourceData.Length() < gMaxBytesForSyncDecode))
  2052. return SyncDecode();
  2053. // If we get this far, dispatch the worker. We do this instead of starting
  2054. // any immediate decoding to guarantee that all our decode notifications are
  2055. // dispatched asynchronously, and to ensure we stay responsive.
  2056. DecodeWorker::Singleton()->RequestDecode(this);
  2057. return NS_OK;
  2058. }
  2059. // Synchronously decodes as much data as possible
  2060. nsresult
  2061. RasterImage::SyncDecode()
  2062. {
  2063. nsresult rv;
  2064. // If we're decoded already, no worries
  2065. if (mDecoded)
  2066. return NS_OK;
  2067. // If we're not storing source data, there isn't much to do here
  2068. if (!StoringSourceData())
  2069. return NS_OK;
  2070. // We really have no good way of forcing a synchronous decode if we're being
  2071. // called in a re-entrant manner (ie, from an event listener fired by a
  2072. // decoder), because the decoding machinery is already tied up. We thus explicitly
  2073. // disallow this type of call in the API, and check for it in API methods.
  2074. NS_ABORT_IF_FALSE(!mInDecoder, "Yikes, forcing sync in reentrant call!");
  2075. // If we have a size decoder open, or one with different flags than
  2076. // what we need, shut it down
  2077. if (mDecoder &&
  2078. (mDecoder->IsSizeDecode() || mDecoder->GetDecodeFlags() != mFrameDecodeFlags))
  2079. {
  2080. rv = ShutdownDecoder(eShutdownIntent_Interrupted);
  2081. CONTAINER_ENSURE_SUCCESS(rv);
  2082. }
  2083. // If we don't have a decoder, create one
  2084. if (!mDecoder) {
  2085. NS_ABORT_IF_FALSE(mFrames.IsEmpty(), "Trying to decode to non-empty frame-array");
  2086. rv = InitDecoder(/* aDoSizeDecode = */ false);
  2087. CONTAINER_ENSURE_SUCCESS(rv);
  2088. }
  2089. // Write everything we have
  2090. rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
  2091. mSourceData.Length() - mBytesDecoded);
  2092. CONTAINER_ENSURE_SUCCESS(rv);
  2093. // When we're doing a sync decode, we want to get as much information from the
  2094. // image as possible. We've send the decoder all of our data, so now's a good
  2095. // time to flush any invalidations (in case we don't have all the data and what
  2096. // we got left us mid-frame).
  2097. nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  2098. mInDecoder = true;
  2099. mDecoder->FlushInvalidations();
  2100. mInDecoder = false;
  2101. // If we finished the decode, shutdown the decoder
  2102. if (mDecoder && IsDecodeFinished()) {
  2103. rv = ShutdownDecoder(eShutdownIntent_Done);
  2104. CONTAINER_ENSURE_SUCCESS(rv);
  2105. }
  2106. // All good if no errors!
  2107. return mError ? NS_ERROR_FAILURE : NS_OK;
  2108. }
  2109. //******************************************************************************
  2110. /* [noscript] void draw(in gfxContext aContext,
  2111. * in gfxGraphicsFilter aFilter,
  2112. * [const] in gfxMatrix aUserSpaceToImageSpace,
  2113. * [const] in gfxRect aFill,
  2114. * [const] in nsIntRect aSubimage,
  2115. * [const] in nsIntSize aViewportSize,
  2116. * in PRUint32 aFlags); */
  2117. NS_IMETHODIMP
  2118. RasterImage::Draw(gfxContext *aContext,
  2119. gfxPattern::GraphicsFilter aFilter,
  2120. const gfxMatrix &aUserSpaceToImageSpace,
  2121. const gfxRect &aFill,
  2122. const nsIntRect &aSubimage,
  2123. const nsIntSize& /*aViewportSize - ignored*/,
  2124. PRUint32 aFlags)
  2125. {
  2126. if (mError)
  2127. return NS_ERROR_FAILURE;
  2128. // Disallowed in the API
  2129. if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
  2130. return NS_ERROR_FAILURE;
  2131. // Illegal -- you can't draw with non-default decode flags.
  2132. // (Disabling colorspace conversion might make sense to allow, but
  2133. // we don't currently.)
  2134. if ((aFlags & DECODE_FLAGS_MASK) != DECODE_FLAGS_DEFAULT)
  2135. return NS_ERROR_FAILURE;
  2136. NS_ENSURE_ARG_POINTER(aContext);
  2137. // We can only draw with the default decode flags
  2138. if (mFrameDecodeFlags != DECODE_FLAGS_DEFAULT) {
  2139. if (!CanForciblyDiscard())
  2140. return NS_ERROR_NOT_AVAILABLE;
  2141. ForceDiscard();
  2142. mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
  2143. }
  2144. // We use !mDecoded && mHasSourceData to mean discarded.
  2145. if (!mDecoded && mHasSourceData) {
  2146. mDrawStartTime = TimeStamp::Now();
  2147. // We're drawing this image, so indicate that we should decode it as soon
  2148. // as possible.
  2149. DecodeWorker::Singleton()->MarkAsASAP(this);
  2150. }
  2151. // If a synchronous draw is requested, flush anything that might be sitting around
  2152. if (aFlags & FLAG_SYNC_DECODE) {
  2153. nsresult rv = SyncDecode();
  2154. NS_ENSURE_SUCCESS(rv, rv);
  2155. }
  2156. imgFrame *frame = GetCurrentDrawableImgFrame();
  2157. if (!frame) {
  2158. return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
  2159. }
  2160. nsIntRect framerect = frame->GetRect();
  2161. nsIntMargin padding(framerect.x, framerect.y,
  2162. mSize.width - framerect.XMost(),
  2163. mSize.height - framerect.YMost());
  2164. frame->Draw(aContext, aFilter, aUserSpaceToImageSpace, aFill, padding, aSubimage);
  2165. if (mDecoded && !mDrawStartTime.IsNull()) {
  2166. TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
  2167. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, PRInt32(drawLatency.ToMicroseconds()));
  2168. // clear the value of mDrawStartTime
  2169. mDrawStartTime = TimeStamp();
  2170. }
  2171. return NS_OK;
  2172. }
  2173. //******************************************************************************
  2174. /* [notxpcom] nsIFrame GetRootLayoutFrame() */
  2175. nsIFrame*
  2176. RasterImage::GetRootLayoutFrame()
  2177. {
  2178. return nsnull;
  2179. }
  2180. //******************************************************************************
  2181. /* void lockImage() */
  2182. NS_IMETHODIMP
  2183. RasterImage::LockImage()
  2184. {
  2185. if (mError)
  2186. return NS_ERROR_FAILURE;
  2187. // Cancel the discard timer if it's there
  2188. DiscardTracker::Remove(&mDiscardTrackerNode);
  2189. // Increment the lock count
  2190. mLockCount++;
  2191. return NS_OK;
  2192. }
  2193. //******************************************************************************
  2194. /* void unlockImage() */
  2195. NS_IMETHODIMP
  2196. RasterImage::UnlockImage()
  2197. {
  2198. if (mError)
  2199. return NS_ERROR_FAILURE;
  2200. // It's an error to call this function if the lock count is 0
  2201. NS_ABORT_IF_FALSE(mLockCount > 0,
  2202. "Calling UnlockImage with mLockCount == 0!");
  2203. if (mLockCount == 0)
  2204. return NS_ERROR_ABORT;
  2205. // We're locked, so discarding should not be active
  2206. NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
  2207. // Decrement our lock count
  2208. mLockCount--;
  2209. // If we've decoded this image once before, we're currently decoding again,
  2210. // and our lock count is now zero (so nothing is forcing us to keep the
  2211. // decoded data around), try to cancel the decode and throw away whatever
  2212. // we've decoded.
  2213. if (mHasBeenDecoded && mDecoder &&
  2214. mLockCount == 0 && CanForciblyDiscard()) {
  2215. PR_LOG(gCompressedImageAccountingLog, PR_LOG_DEBUG,
  2216. ("RasterImage[0x%p] canceling decode because image "
  2217. "is now unlocked.", this));
  2218. ShutdownDecoder(eShutdownIntent_Interrupted);
  2219. ForceDiscard();
  2220. return NS_OK;
  2221. }
  2222. // Otherwise, we might still be a candidate for discarding in the future. If
  2223. // we are, add ourselves to the discard tracker.
  2224. if (CanDiscard()) {
  2225. nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  2226. CONTAINER_ENSURE_SUCCESS(rv);
  2227. }
  2228. return NS_OK;
  2229. }
  2230. // Flushes up to aMaxBytes to the decoder.
  2231. nsresult
  2232. RasterImage::DecodeSomeData(PRUint32 aMaxBytes)
  2233. {
  2234. // We should have a decoder if we get here
  2235. NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
  2236. // If we have nothing to decode, return
  2237. if (mBytesDecoded == mSourceData.Length())
  2238. return NS_OK;
  2239. // write the proper amount of data
  2240. PRUint32 bytesToDecode = NS_MIN(aMaxBytes,
  2241. mSourceData.Length() - mBytesDecoded);
  2242. nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
  2243. bytesToDecode);
  2244. return rv;
  2245. }
  2246. // There are various indicators that tell us we're finished with the decode
  2247. // task at hand and can shut down the decoder.
  2248. //
  2249. // This method may not be called if there is no decoder.
  2250. bool
  2251. RasterImage::IsDecodeFinished()
  2252. {
  2253. // Precondition
  2254. NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!");
  2255. // Assume it's not finished
  2256. bool decodeFinished = false;
  2257. // There shouldn't be any reason to call this if we're not storing
  2258. // source data
  2259. NS_ABORT_IF_FALSE(StoringSourceData(),
  2260. "just shut down on SourceDataComplete!");
  2261. // The decode is complete if we got what we wanted...
  2262. if (mDecoder->IsSizeDecode()) {
  2263. if (mHasSize)
  2264. decodeFinished = true;
  2265. }
  2266. else {
  2267. if (mDecoded)
  2268. decodeFinished = true;
  2269. }
  2270. // ...or if we have all the source data and wrote all the source data.
  2271. //
  2272. // (NB - This can be distinct from the above case even for non-erroneous
  2273. // images because the decoder might not call DecodingComplete() until we
  2274. // call Close() in ShutdownDecoder())
  2275. if (mHasSourceData && (mBytesDecoded == mSourceData.Length()))
  2276. decodeFinished = true;
  2277. return decodeFinished;
  2278. }
  2279. // Indempotent error flagging routine. If a decoder is open, shuts it down.
  2280. void
  2281. RasterImage::DoError()
  2282. {
  2283. // If we've flagged an error before, we have nothing to do
  2284. if (mError)
  2285. return;
  2286. // If we're mid-decode, shut down the decoder.
  2287. if (mDecoder)
  2288. ShutdownDecoder(eShutdownIntent_Error);
  2289. // Put the container in an error state
  2290. mError = true;
  2291. // Log our error
  2292. LOG_CONTAINER_ERROR;
  2293. }
  2294. // nsIInputStream callback to copy the incoming image data directly to the
  2295. // RasterImage without processing. The RasterImage is passed as the closure.
  2296. // Always reads everything it gets, even if the data is erroneous.
  2297. NS_METHOD
  2298. RasterImage::WriteToRasterImage(nsIInputStream* /* unused */,
  2299. void* aClosure,
  2300. const char* aFromRawSegment,
  2301. PRUint32 /* unused */,
  2302. PRUint32 aCount,
  2303. PRUint32* aWriteCount)
  2304. {
  2305. // Retrieve the RasterImage
  2306. RasterImage* image = static_cast<RasterImage*>(aClosure);
  2307. // Copy the source data. Unless we hit OOM, we squelch the return value
  2308. // here, because returning an error means that ReadSegments stops
  2309. // reading data, violating our invariant that we read everything we get.
  2310. // If we hit OOM then we fail and the load is aborted.
  2311. nsresult rv = image->AddSourceData(aFromRawSegment, aCount);
  2312. if (rv == NS_ERROR_OUT_OF_MEMORY) {
  2313. image->DoError();
  2314. return rv;
  2315. }
  2316. // We wrote everything we got
  2317. *aWriteCount = aCount;
  2318. return NS_OK;
  2319. }
  2320. bool
  2321. RasterImage::ShouldAnimate()
  2322. {
  2323. return Image::ShouldAnimate() && mFrames.Length() >= 2 &&
  2324. !mAnimationFinished;
  2325. }
  2326. /* readonly attribute PRUint32 framesNotified; */
  2327. #ifdef DEBUG
  2328. NS_IMETHODIMP
  2329. RasterImage::GetFramesNotified(PRUint32 *aFramesNotified)
  2330. {
  2331. NS_ENSURE_ARG_POINTER(aFramesNotified);
  2332. *aFramesNotified = mFramesNotified;
  2333. return NS_OK;
  2334. }
  2335. #endif
  2336. /* static */ RasterImage::DecodeWorker*
  2337. RasterImage::DecodeWorker::Singleton()
  2338. {
  2339. if (!sSingleton) {
  2340. sSingleton = new DecodeWorker();
  2341. ClearOnShutdown(&sSingleton);
  2342. }
  2343. return sSingleton;
  2344. }
  2345. void
  2346. RasterImage::DecodeWorker::MarkAsASAP(RasterImage* aImg)
  2347. {
  2348. DecodeRequest* request = &aImg->mDecodeRequest;
  2349. // If we're already an ASAP request, there's nothing to do here.
  2350. if (request->mIsASAP) {
  2351. return;
  2352. }
  2353. request->mIsASAP = true;
  2354. if (request->isInList()) {
  2355. // If the decode request is in a list, it must be in the normal decode
  2356. // requests list -- if it had been in the ASAP list, then mIsASAP would
  2357. // have been true above. Move the request to the ASAP list.
  2358. request->remove();
  2359. mASAPDecodeRequests.insertBack(request);
  2360. // Since request is in a list, one of the decode worker's lists is
  2361. // non-empty, so the worker should be pending in the event loop.
  2362. //
  2363. // (Note that this invariant only holds while we are not in Run(), because
  2364. // DecodeSomeOfImage adds requests to the decode worker using
  2365. // AddDecodeRequest, not RequestDecode, and AddDecodeRequest does not call
  2366. // EnsurePendingInEventLoop. Therefore, it is an error to call MarkAsASAP
  2367. // from within DecodeWorker::Run.)
  2368. MOZ_ASSERT(mPendingInEventLoop);
  2369. }
  2370. }
  2371. void
  2372. RasterImage::DecodeWorker::AddDecodeRequest(DecodeRequest* aRequest)
  2373. {
  2374. if (aRequest->isInList()) {
  2375. // The image is already in our list of images to decode, so we don't have
  2376. // to do anything here.
  2377. return;
  2378. }
  2379. if (aRequest->mIsASAP) {
  2380. mASAPDecodeRequests.insertBack(aRequest);
  2381. } else {
  2382. mNormalDecodeRequests.insertBack(aRequest);
  2383. }
  2384. }
  2385. void
  2386. RasterImage::DecodeWorker::RequestDecode(RasterImage* aImg)
  2387. {
  2388. AddDecodeRequest(&aImg->mDecodeRequest);
  2389. EnsurePendingInEventLoop();
  2390. }
  2391. void
  2392. RasterImage::DecodeWorker::EnsurePendingInEventLoop()
  2393. {
  2394. if (!mPendingInEventLoop) {
  2395. mPendingInEventLoop = true;
  2396. NS_DispatchToCurrentThread(this);
  2397. }
  2398. }
  2399. void
  2400. RasterImage::DecodeWorker::StopDecoding(RasterImage* aImg)
  2401. {
  2402. DecodeRequest* request = &aImg->mDecodeRequest;
  2403. if (request->isInList()) {
  2404. request->remove();
  2405. }
  2406. request->mDecodeTime = TimeDuration(0);
  2407. request->mIsASAP = false;
  2408. }
  2409. NS_IMETHODIMP
  2410. RasterImage::DecodeWorker::Run()
  2411. {
  2412. // We just got called back by the event loop; therefore, we're no longer
  2413. // pending.
  2414. mPendingInEventLoop = false;
  2415. TimeStamp eventStart = TimeStamp::Now();
  2416. // Now decode until we either run out of time or run out of images.
  2417. do {
  2418. // Try to get an ASAP request to handle. If there isn't one, try to get a
  2419. // normal request. If no normal request is pending either, then we're done
  2420. // here.
  2421. DecodeRequest* request = mASAPDecodeRequests.popFirst();
  2422. if (!request)
  2423. request = mNormalDecodeRequests.popFirst();
  2424. if (!request)
  2425. break;
  2426. // This has to be a strong pointer, because DecodeSomeOfImage may destroy
  2427. // image->mDecoder, which may be holding the only other reference to image.
  2428. nsRefPtr<RasterImage> image = request->mImage;
  2429. DecodeSomeOfImage(image);
  2430. // If we aren't yet finished decoding and we have more data in hand, add
  2431. // this request to the back of the list.
  2432. if (image->mDecoder &&
  2433. !image->mError &&
  2434. !image->IsDecodeFinished() &&
  2435. image->mSourceData.Length() > image->mBytesDecoded) {
  2436. AddDecodeRequest(request);
  2437. }
  2438. } while ((TimeStamp::Now() - eventStart).ToMilliseconds() <= gMaxMSBeforeYield);
  2439. // If decode requests are pending, re-post ourself to the event loop.
  2440. if (!mASAPDecodeRequests.isEmpty() || !mNormalDecodeRequests.isEmpty()) {
  2441. EnsurePendingInEventLoop();
  2442. }
  2443. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_LATENCY,
  2444. PRUint32((TimeStamp::Now() - eventStart).ToMilliseconds()));
  2445. return NS_OK;
  2446. }
  2447. nsresult
  2448. RasterImage::DecodeWorker::DecodeUntilSizeAvailable(RasterImage* aImg)
  2449. {
  2450. return DecodeSomeOfImage(aImg, DECODE_TYPE_UNTIL_SIZE);
  2451. }
  2452. nsresult
  2453. RasterImage::DecodeWorker::DecodeSomeOfImage(
  2454. RasterImage* aImg,
  2455. DecodeType aDecodeType /* = DECODE_TYPE_NORMAL */)
  2456. {
  2457. NS_ABORT_IF_FALSE(aImg->mInitialized,
  2458. "Worker active for uninitialized container!");
  2459. if (aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize)
  2460. return NS_OK;
  2461. // If an error is flagged, it probably happened while we were waiting
  2462. // in the event queue.
  2463. if (aImg->mError)
  2464. return NS_OK;
  2465. // If mDecoded or we don't have a decoder, we must have finished already (for
  2466. // example, a synchronous decode request came while the worker was pending).
  2467. if (!aImg->mDecoder || aImg->mDecoded)
  2468. return NS_OK;
  2469. nsRefPtr<Decoder> decoderKungFuDeathGrip = aImg->mDecoder;
  2470. PRUint32 maxBytes;
  2471. if (aImg->mDecoder->IsSizeDecode()) {
  2472. // Decode all available data if we're a size decode; they're cheap, and we
  2473. // want them to be more or less synchronous.
  2474. maxBytes = aImg->mSourceData.Length();
  2475. } else {
  2476. // We're only guaranteed to decode this many bytes, so in particular,
  2477. // gDecodeBytesAtATime should be set high enough for us to read the size
  2478. // from most images.
  2479. maxBytes = gDecodeBytesAtATime;
  2480. }
  2481. PRInt32 chunkCount = 0;
  2482. TimeStamp start = TimeStamp::Now();
  2483. TimeStamp deadline = start + TimeDuration::FromMilliseconds(gMaxMSBeforeYield);
  2484. // Decode some chunks of data.
  2485. do {
  2486. chunkCount++;
  2487. nsresult rv = aImg->DecodeSomeData(maxBytes);
  2488. if (NS_FAILED(rv)) {
  2489. aImg->DoError();
  2490. return rv;
  2491. }
  2492. // We keep decoding chunks until either:
  2493. // * we're an UNTIL_SIZE decode and we get the size,
  2494. // * we don't have any data left to decode,
  2495. // * the decode completes, or
  2496. // * we run out of time.
  2497. if (aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize)
  2498. break;
  2499. } while (aImg->mSourceData.Length() > aImg->mBytesDecoded &&
  2500. !aImg->IsDecodeFinished() &&
  2501. TimeStamp::Now() < deadline);
  2502. aImg->mDecodeRequest.mDecodeTime += (TimeStamp::Now() - start);
  2503. if (chunkCount && !aImg->mDecoder->IsSizeDecode()) {
  2504. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, chunkCount);
  2505. }
  2506. // Flush invalidations (and therefore paint) now that we've decoded all the
  2507. // chunks we're going to.
  2508. //
  2509. // However, don't paint if:
  2510. //
  2511. // * This was an until-size decode. Until-size decodes are always followed
  2512. // by normal decodes, so don't bother painting.
  2513. //
  2514. // * The decoder flagged an error. The decoder may have written garbage
  2515. // into the output buffer; don't paint it to the screen.
  2516. //
  2517. // * We have all the source data. This disables progressive display of
  2518. // previously-decoded images, thus letting us finish decoding faster,
  2519. // since we don't waste time painting while we decode.
  2520. // Decoder::PostFrameStop() will flush invalidations once the decode is
  2521. // done.
  2522. if (aDecodeType != DECODE_TYPE_UNTIL_SIZE &&
  2523. !aImg->mDecoder->HasError() &&
  2524. !aImg->mHasSourceData) {
  2525. aImg->mInDecoder = true;
  2526. aImg->mDecoder->FlushInvalidations();
  2527. aImg->mInDecoder = false;
  2528. }
  2529. // If the decode finished, shut down the decoder.
  2530. if (aImg->mDecoder && aImg->IsDecodeFinished()) {
  2531. // Do some telemetry if this isn't a size decode.
  2532. DecodeRequest* request = &aImg->mDecodeRequest;
  2533. if (!aImg->mDecoder->IsSizeDecode()) {
  2534. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
  2535. PRInt32(request->mDecodeTime.ToMicroseconds()));
  2536. // We record the speed for only some decoders. The rest have
  2537. // SpeedHistogram return HistogramCount.
  2538. Telemetry::ID id = aImg->mDecoder->SpeedHistogram();
  2539. if (id < Telemetry::HistogramCount) {
  2540. PRInt32 KBps = PRInt32(request->mImage->mBytesDecoded /
  2541. (1024 * request->mDecodeTime.ToSeconds()));
  2542. Telemetry::Accumulate(id, KBps);
  2543. }
  2544. }
  2545. nsresult rv = aImg->ShutdownDecoder(RasterImage::eShutdownIntent_Done);
  2546. if (NS_FAILED(rv)) {
  2547. aImg->DoError();
  2548. return rv;
  2549. }
  2550. }
  2551. return NS_OK;
  2552. }
  2553. } // namespace image
  2554. } // namespace mozilla