Exemple #1
0
void
Decoder::CompleteDecode()
{
  // Implementation-specific finalization
  BeforeFinishInternal();
  if (!HasError()) {
    FinishInternal();
  } else {
    FinishWithErrorInternal();
  }

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError()) {
    PostFrameStop();
  }

  // If PostDecodeDone() has not been called, and this decoder wasn't aborted
  // early because of low-memory conditions or losing a race with another
  // decoder, we need to send teardown notifications (and report an error to the
  // console later).
  if (!IsMetadataDecode() && !mDecodeDone && !WasAborted()) {
    mShouldReportError = true;

    // If we only have a data error, we're usable if we have at least one
    // complete frame.
    if (!HasDecoderError() && GetCompleteFrameCount() > 0) {
      // We're usable, so do exactly what we should have when the decoder
      // completed.

      // Not writing to the entire frame may have left us transparent.
      PostHasTransparency();

      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      // We're not usable. Record some final progress indicating the error.
      if (!IsMetadataDecode()) {
        mProgress |= FLAG_DECODE_COMPLETE;
      }
      mProgress |= FLAG_HAS_ERROR;
    }
  }

  if (mDecodeDone && !IsMetadataDecode()) {
    MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");

    // If this image wasn't animated and isn't a transient image, mark its frame
    // as optimizable. We don't support optimizing animated images and
    // optimizing transient images isn't worth it.
    if (!HasAnimation() &&
        !(mDecoderFlags & DecoderFlags::IMAGE_IS_TRANSIENT) &&
        mCurrentFrame) {
      mCurrentFrame->SetOptimizable();
    }
  }
}
Exemple #2
0
// set timeout and frame disposal method for the current frame
void
nsPNGDecoder::EndImageFrame()
{
  if (mFrameIsHidden) {
    return;
  }

  mNumFrames++;

  Opacity opacity = Opacity::SOME_TRANSPARENCY;
  if (format == gfx::SurfaceFormat::B8G8R8X8) {
    opacity = Opacity::OPAQUE;
  }

#ifdef PNG_APNG_SUPPORTED
  uint32_t numFrames = GetFrameCount();

  // We can't use mPNG->num_frames_read as it may be one ahead.
  if (numFrames > 1) {
    PostInvalidation(mFrameRect);
  }
#endif

  PostFrameStop(opacity, mAnimInfo.mDispose, mAnimInfo.mTimeout,
                mAnimInfo.mBlend);
}
LexerTransition<nsIconDecoder::State>
nsIconDecoder::Finish()
{
  PostFrameStop();
  PostDecodeDone();

  return Transition::TerminateSuccess();
}
Exemple #4
0
//******************************************************************************
void nsGIFDecoder2::EndImageFrame()
{
    // First flush all pending image data
    if (!mGIFStruct.images_decoded) {
        // Only need to flush first frame
        FlushImageData();

        // If the first frame is smaller in height than the entire image, send an
        // invalidation for the area it does not have data for.
        // This will clear the remaining bits of the placeholder. (Bug 37589)
        const PRUint32 realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
        if (realFrameHeight < mGIFStruct.screen_height) {
            nsIntRect r(0, realFrameHeight,
                        mGIFStruct.screen_width,
                        mGIFStruct.screen_height - realFrameHeight);
            PostInvalidation(r);
        }
        // This transparency check is only valid for first frame
        if (mGIFStruct.is_transparent && !mSawTransparency) {
            mImage->SetFrameHasNoAlpha(mGIFStruct.images_decoded);
        }
    }
    mCurrentRow = mLastFlushedRow = -1;
    mCurrentPass = mLastFlushedPass = 0;

    // Only add frame if we have any rows at all
    if (mGIFStruct.rows_remaining != mGIFStruct.height) {
        if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
            // Clear the remaining rows (only needed for the animation frames)
            PRUint8 *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
            memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
        }

        // We actually have the timeout information before we get the lzw encoded
        // image data, at least according to the spec, but we delay in setting the
        // timeout for the image until here to help ensure that we have the whole
        // image frame decoded before we go off and try to display another frame.
        mImage->SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time);
    }

    // Unconditionally increment images_decoded, because we unconditionally
    // append frames in BeginImageFrame(). This ensures that images_decoded
    // always refers to the frame in mImage we're currently decoding,
    // even if some of them weren't decoded properly and thus are blank.
    mGIFStruct.images_decoded++;

    // Tell the superclass we finished a frame
    PostFrameStop();

    // Reset the transparent pixel
    if (mOldColor) {
        mColormap[mGIFStruct.tpixel] = mOldColor;
        mOldColor = 0;
    }

    mCurrentFrame = -1;
}
//******************************************************************************
void nsGIFDecoder2::EndImageFrame()
{
  FrameBlender::FrameAlpha alpha = FrameBlender::kFrameHasAlpha;

  // First flush all pending image data 
  if (!mGIFStruct.images_decoded) {
    // Only need to flush first frame
    FlushImageData();

    // If the first frame is smaller in height than the entire image, send an
    // invalidation for the area it does not have data for.
    // This will clear the remaining bits of the placeholder. (Bug 37589)
    const uint32_t realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
    if (realFrameHeight < mGIFStruct.screen_height) {
      nsIntRect r(0, realFrameHeight,
                  mGIFStruct.screen_width,
                  mGIFStruct.screen_height - realFrameHeight);
      PostInvalidation(r);
    }
    // This transparency check is only valid for first frame
    if (mGIFStruct.is_transparent && !mSawTransparency) {
      alpha = FrameBlender::kFrameOpaque;
    }
  }
  mCurrentRow = mLastFlushedRow = -1;
  mCurrentPass = mLastFlushedPass = 0;

  // Only add frame if we have any rows at all
  if (mGIFStruct.rows_remaining != mGIFStruct.height) {
    if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
      // Clear the remaining rows (only needed for the animation frames)
      uint8_t *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
      memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
    }
  }

  // Unconditionally increment images_decoded, because we unconditionally
  // append frames in BeginImageFrame(). This ensures that images_decoded
  // always refers to the frame in mImage we're currently decoding,
  // even if some of them weren't decoded properly and thus are blank.
  mGIFStruct.images_decoded++;

  // Tell the superclass we finished a frame
  PostFrameStop(alpha,
                FrameBlender::FrameDisposalMethod(mGIFStruct.disposal_method),
                mGIFStruct.delay_time);

  // Reset the transparent pixel
  if (mOldColor) {
    mColormap[mGIFStruct.tpixel] = mOldColor;
    mOldColor = 0;
  }

  mCurrentFrameIndex = -1;
}
Exemple #6
0
void
Decoder::Finish()
{
  // Implementation-specific finalization
  if (!HasError())
    FinishInternal();

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasDecoderError())
    PostFrameStop();

  // If PostDecodeDone() has not been called, we need to sent teardown
  // notifications.
  if (!IsSizeDecode() && !mDecodeDone) {

    // Log data errors to the error console
    nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    nsCOMPtr<nsIScriptError2> errorObject =
      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);

    if (consoleService && errorObject && !HasDecoderError()) {
      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
                       NS_ConvertASCIItoUTF16(mImage->GetURIString()));

      errorObject->InitWithWindowID
        (msg.get(),
         NS_ConvertUTF8toUTF16(mImage->GetURIString()).get(),
         nsnull,
         0, 0, nsIScriptError::errorFlag,
         "Image", mImage->InnerWindowID()
         );
  
      nsCOMPtr<nsIScriptError> error = do_QueryInterface(errorObject);
      consoleService->LogMessage(error);
    }

    // If we only have a data error, see if things are worth salvaging
    bool salvage = !HasDecoderError() && mImage->GetNumFrames();

    // If we're salvaging, say we finished decoding
    if (salvage)
      mImage->DecodingComplete();

    // Fire teardown notifications
    if (mObserver) {
      mObserver->OnStopContainer(nsnull, mImage);
      mObserver->OnStopDecode(nsnull, salvage ? NS_OK : NS_ERROR_FAILURE, nsnull);
    }
  }
}
Exemple #7
0
void
nsWEBPDecoder::FinishInternal()
{
  // Flush the Decoder and let it free the output image buffer.
  WebPIDelete(mDecoder);
  WebPFreeDecBuffer(&mDecBuf);

  // We should never make multiple frames
  MOZ_ASSERT(GetFrameCount() <= 1, "Multiple WebP frames?");

  // Send notifications if appropriate
  if (!IsSizeDecode() && (GetFrameCount() == 1)) {
    PostFrameStop();
    PostDecodeDone();
  }
}
Exemple #8
0
void
nsIconDecoder::NotifyDone(PRBool aSuccess)
{
  // We should only call this once
  NS_ABORT_IF_FALSE(!mNotifiedDone, "Calling NotifyDone twice");

  // Notify
  PostFrameStop();
  if (aSuccess)
    mImage->DecodingComplete();
  if (mObserver) {
    mObserver->OnStopContainer(nsnull, mImage);
    mObserver->OnStopDecode(nsnull, aSuccess ? NS_OK : NS_ERROR_FAILURE,
                            nsnull);
  }

  // Flag that we've notified
  mNotifiedDone = PR_TRUE;
}
Exemple #9
0
// set timeout and frame disposal method for the current frame
void nsPNGDecoder::EndImageFrame()
{
  if (mFrameIsHidden)
    return;

  PRUint32 numFrames = 1;
#ifdef PNG_APNG_SUPPORTED
  numFrames = mImage->GetNumFrames();

  // We can't use mPNG->num_frames_read as it may be one ahead.
  if (numFrames > 1) {
    // Tell the image renderer that the frame is complete
    if (mFrameHasNoAlpha)
      mImage->SetFrameHasNoAlpha(numFrames - 1);

    PostInvalidation(mFrameRect);
  }
#endif

  PostFrameStop();
}
// set timeout and frame disposal method for the current frame
void nsPNGDecoder::EndImageFrame()
{
  if (mFrameIsHidden)
    return;

  mNumFrames++;

  FrameBlender::FrameAlpha alpha;
  if (mFrameHasNoAlpha)
    alpha = FrameBlender::kFrameOpaque;
  else
    alpha = FrameBlender::kFrameHasAlpha;

#ifdef PNG_APNG_SUPPORTED
  uint32_t numFrames = GetFrameCount();

  // We can't use mPNG->num_frames_read as it may be one ahead.
  if (numFrames > 1) {
    PostInvalidation(mFrameRect);
  }
#endif

  PostFrameStop(alpha, mAnimInfo.mDispose, mAnimInfo.mTimeout, mAnimInfo.mBlend);
}
Exemple #11
0
// set timeout and frame disposal method for the current frame
void nsPNGDecoder::EndImageFrame()
{
    if (mFrameIsHidden)
        return;

    uint32_t numFrames = 1;
#ifdef PNG_APNG_SUPPORTED
    numFrames = mImage.GetNumFrames();

    // We can't use mPNG->num_frames_read as it may be one ahead.
    if (numFrames > 1) {
        // Tell the image renderer that the frame is complete
        if (mFrameHasNoAlpha)
            mImage.SetFrameHasNoAlpha(numFrames - 1);

        // PNG is always non-premult
        mImage.SetFrameAsNonPremult(numFrames - 1, true);

        PostInvalidation(mFrameRect);
    }
#endif

    PostFrameStop();
}
Exemple #12
0
//******************************************************************************
void
nsGIFDecoder2::EndImageFrame()
{
  Opacity opacity = Opacity::SOME_TRANSPARENCY;

  // First flush all pending image data
  if (!mGIFStruct.images_decoded) {
    // Only need to flush first frame
    FlushImageData();

    // If the first frame is smaller in height than the entire image, send an
    // invalidation for the area it does not have data for.
    // This will clear the remaining bits of the placeholder. (Bug 37589)
    const uint32_t realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
    if (realFrameHeight < mGIFStruct.screen_height) {
      nsIntRect r(0, realFrameHeight,
                  mGIFStruct.screen_width,
                  mGIFStruct.screen_height - realFrameHeight);
      PostInvalidation(r);
    }

    // The first frame was preallocated with alpha; if it wasn't transparent, we
    // should fix that. We can also mark it opaque unconditionally if we didn't
    // actually see any transparent pixels - this test is only valid for the
    // first frame.
    if (!mGIFStruct.is_transparent || !mSawTransparency) {
      opacity = Opacity::OPAQUE;
    }
  }
  mCurrentRow = mLastFlushedRow = -1;
  mCurrentPass = mLastFlushedPass = 0;

  // Only add frame if we have any rows at all
  if (mGIFStruct.rows_remaining != mGIFStruct.height) {
    if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
      // Clear the remaining rows (only needed for the animation frames)
      uint8_t* rowp =
        mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) *
                      mGIFStruct.width);
      memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
    }
  }

  // Unconditionally increment images_decoded, because we unconditionally
  // append frames in BeginImageFrame(). This ensures that images_decoded
  // always refers to the frame in mImage we're currently decoding,
  // even if some of them weren't decoded properly and thus are blank.
  mGIFStruct.images_decoded++;

  // Tell the superclass we finished a frame
  PostFrameStop(opacity,
                DisposalMethod(mGIFStruct.disposal_method),
                mGIFStruct.delay_time);

  // Reset the transparent pixel
  if (mOldColor) {
    mColormap[mGIFStruct.tpixel] = mOldColor;
    mOldColor = 0;
  }

  mCurrentFrameIndex = -1;
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop(Opacity::OPAQUE);
  PostDecodeDone();
}
Exemple #14
0
void
Decoder::Finish(RasterImage::eShutdownIntent aShutdownIntent)
{
  // Implementation-specific finalization
  if (!HasError())
    FinishInternal();

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError())
    PostFrameStop();

  // If PostDecodeDone() has not been called, we need to sent teardown
  // notifications.
  if (!IsSizeDecode() && !mDecodeDone) {

    // Log data errors to the error console
    nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    nsCOMPtr<nsIScriptError> errorObject =
      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);

    if (consoleService && errorObject && !HasDecoderError()) {
      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
                       NS_ConvertUTF8toUTF16(mImage.GetURIString()));

      if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                         msg,
                         NS_ConvertUTF8toUTF16(mImage.GetURIString()),
                         EmptyString(), 0, 0, nsIScriptError::errorFlag,
                         "Image", mImage.InnerWindowID()
                       ))) {
        consoleService->LogMessage(errorObject);
      }
    }

    bool usable = true;
    if (aShutdownIntent != RasterImage::eShutdownIntent_NotNeeded && !HasDecoderError()) {
      // If we only have a data error, we're usable if we have at least one complete frame.
      if (GetCompleteFrameCount() == 0) {
        usable = false;
      }
    }

    // If we're usable, do exactly what we should have when the decoder
    // completed.
    if (usable) {
      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      if (mObserver) {
        mObserver->OnStopDecode(NS_ERROR_FAILURE);
      }
    }
  }

  // Set image metadata before calling DecodingComplete, because DecodingComplete calls Optimize().
  mImageMetadata.SetOnImage(&mImage);

  if (mDecodeDone) {
    mImage.DecodingComplete();
  }
}
void
nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
                             DecodeStrategy)
{
  NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");

  // We put this here to avoid errors about crossing initialization with case
  // jumps on linux.
  uint32_t bytesToRead = 0;

  // Loop until the input data is gone
  while (aCount > 0) {
    switch (mState) {
      case iconStateStart:

        // Grab the width
        mWidth = (uint8_t)*aBuffer;

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateHaveHeight;
        break;

      case iconStateHaveHeight:

        // Grab the Height
        mHeight = (uint8_t)*aBuffer;

        // Post our size to the superclass
        PostSize(mWidth, mHeight);

        PostHasTransparency();

        if (HasError()) {
          // Setting the size led to an error.
          mState = iconStateFinished;
          return;
        }

        // If We're doing a size decode, we're done
        if (IsSizeDecode()) {
          mState = iconStateFinished;
          break;
        }

        if (!mImageData) {
          PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
          return;
        }

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateReadPixels;
        break;

      case iconStateReadPixels: {

        // How many bytes are we reading?
        bytesToRead = std::min(aCount, mImageDataLength - mPixBytesRead);

        // Copy the bytes
        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);

        // Performance isn't critical here, so our update rectangle is
        // always the full icon
        nsIntRect r(0, 0, mWidth, mHeight);

        // Invalidate
        PostInvalidation(r);

        // Book Keeping
        aBuffer += bytesToRead;
        aCount -= bytesToRead;
        mPixBytesRead += bytesToRead;

        // If we've got all the pixel bytes, we're finished
        if (mPixBytesRead == mImageDataLength) {
          PostFrameStop();
          PostDecodeDone();
          mState = iconStateFinished;
        }
        break;
      }

      case iconStateFinished:

        // Consume all excess data silently
        aCount = 0;

        break;
    }
  }
}
Exemple #16
0
void
nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
{
  NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");

  // We put this here to avoid errors about crossing initialization with case
  // jumps on linux.
  PRUint32 bytesToRead = 0;
  nsresult rv;

  // Performance isn't critical here, so our update rectangle is 
  // always the full icon
  nsIntRect r(0, 0, mWidth, mHeight);

  // Loop until the input data is gone
  while (aCount > 0) {
    switch (mState) {
      case iconStateStart:

        // Grab the width
        mWidth = (PRUint8)*aBuffer;

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateHaveHeight;
        break;

      case iconStateHaveHeight:

        // Grab the Height
        mHeight = (PRUint8)*aBuffer;

        // Post our size to the superclass
        PostSize(mWidth, mHeight);
        if (HasError()) {
          // Setting the size led to an error.
          mState = iconStateFinished;
          return;
        }

        // If We're doing a size decode, we're done
        if (IsSizeDecode()) {
          mState = iconStateFinished;
          break;
        }

        // Add the frame and signal
        rv = mImage.EnsureFrame(0, 0, 0, mWidth, mHeight,
                                gfxASurface::ImageFormatARGB32,
                                &mImageData, &mPixBytesTotal);
        if (NS_FAILED(rv)) {
          PostDecoderError(rv);
          return;
        }

        // Tell the superclass we're starting a frame
        PostFrameStart();

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateReadPixels;
        break;

      case iconStateReadPixels:

        // How many bytes are we reading?
        bytesToRead = NS_MIN(aCount, mPixBytesTotal - mPixBytesRead);

        // Copy the bytes
        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);

        // Invalidate
        PostInvalidation(r);

        // Book Keeping
        aBuffer += bytesToRead;
        aCount -= bytesToRead;
        mPixBytesRead += bytesToRead;

        // If we've got all the pixel bytes, we're finished
        if (mPixBytesRead == mPixBytesTotal) {
          PostFrameStop();
          PostDecodeDone();
          mState = iconStateFinished;
        }
        break;

      case iconStateFinished:

        // Consume all excess data silently
        aCount = 0;

        break;
    }
  }
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop();
  PostDecodeDone();
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop(FrameBlender::kFrameOpaque);
  PostDecodeDone();
}
Exemple #19
0
void
Decoder::Finish(ShutdownReason aReason)
{
  MOZ_ASSERT(NS_IsMainThread());

  // Implementation-specific finalization
  if (!HasError())
    FinishInternal();

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError())
    PostFrameStop();

  // If PostDecodeDone() has not been called, we need to sent teardown
  // notifications.
  if (!IsSizeDecode() && !mDecodeDone) {

    // Log data errors to the error console
    nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    nsCOMPtr<nsIScriptError> errorObject =
      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);

    if (consoleService && errorObject && !HasDecoderError()) {
      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
                       NS_ConvertUTF8toUTF16(mImage.GetURIString()));

      if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                         msg,
                         NS_ConvertUTF8toUTF16(mImage.GetURIString()),
                         EmptyString(), 0, 0, nsIScriptError::errorFlag,
                         "Image", mImage.InnerWindowID()
                       ))) {
        consoleService->LogMessage(errorObject);
      }
    }

    bool usable = !HasDecoderError();
    if (aReason != ShutdownReason::NOT_NEEDED && !HasDecoderError()) {
      // If we only have a data error, we're usable if we have at least one complete frame.
      if (GetCompleteFrameCount() == 0) {
        usable = false;
      }
    }

    // If we're usable, do exactly what we should have when the decoder
    // completed.
    if (usable) {
      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      if (!IsSizeDecode()) {
        mProgress |= FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED;
      }
      mProgress |= FLAG_HAS_ERROR;
    }
  }

  // Set image metadata before calling DecodingComplete, because
  // DecodingComplete calls Optimize().
  mImageMetadata.SetOnImage(&mImage);

  if (mDecodeDone) {
    MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");
    mImage.DecodingComplete(mCurrentFrame.get());
  }
}