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(); } } }
// 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(); }
//****************************************************************************** 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; }
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); } } }
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(); } }
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; }
// 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); }
// 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(); }
//****************************************************************************** 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(); }
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; } } }
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(); }
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()); } }