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