/image/src/RasterImage.cpp

http://github.com/zpao/v8monkey · C++ · 3077 lines · 1933 code · 523 blank · 621 comment · 434 complexity · 9c3241205f36981702bbe7c9fb67afd9 MD5 · raw file

Large files are truncated click here to view the full file

  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(!Storin