const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& scaledSize) { // Prevents concurrent decode or scale operations on the same image data. // Multiple LazyDecodingPixelRefs can call this method at the same time. MutexLocker lock(m_decodeMutex); if (m_decodeFailedAndEmpty) return 0; const ScaledImageFragment* cachedImage = 0; cachedImage = tryToLockCompleteCache(scaledSize); if (cachedImage) return cachedImage; cachedImage = tryToScale(0, scaledSize); if (cachedImage) return cachedImage; cachedImage = tryToResumeDecodeAndScale(scaledSize); if (cachedImage) return cachedImage; cachedImage = tryToDecodeAndScale(scaledSize); if (cachedImage) return cachedImage; return 0; }
const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& scaledSize, size_t index) { // Prevents concurrent decode or scale operations on the same image data. // Multiple LazyDecodingPixelRefs can call this method at the same time. MutexLocker lock(m_decodeMutex); if (m_decodeFailedAndEmpty) return 0; const ScaledImageFragment* cachedImage = 0; cachedImage = tryToLockCompleteCache(scaledSize, index); if (cachedImage) return cachedImage; TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount)); cachedImage = tryToScale(0, scaledSize, index); if (cachedImage) return cachedImage; cachedImage = tryToResumeDecodeAndScale(scaledSize, index); if (cachedImage) return cachedImage; return 0; }
const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISize& scaledSize) { TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToDecodeAndScale"); ImageDecoder* decoder = 0; OwnPtr<ScaledImageFragment> fullSizeImage = decode(&decoder); if (!decoder) return 0; OwnPtr<ImageDecoder> decoderContainer = adoptPtr(decoder); if (!fullSizeImage) { // If decode has failed and resulted an empty image we need to make // sure we don't do wasted work in the future. m_decodeFailedAndEmpty = decoderContainer->failed(); return 0; } const ScaledImageFragment* cachedFullSizeImage = ImageDecodingStore::instance()->insertAndLockCache( this, fullSizeImage.release(), decoderContainer.release()); if (m_fullSize == scaledSize) return cachedFullSizeImage; return tryToScale(cachedFullSizeImage, scaledSize); }
const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISize& scaledSize) { RefPtr<SharedBuffer> data; bool allDataReceived = false; { MutexLocker lock(m_dataMutex); // FIXME: We should do a shallow copy instead. Now we're restricted by the API of SharedBuffer. data = m_data->copy(); allDataReceived = m_allDataReceived; } OwnPtr<ImageDecoder> decoder(adoptPtr(ImageDecoder::create(*data.get(), ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied))); if (!decoder && m_imageDecoderFactory) decoder = m_imageDecoderFactory->create(); if (!decoder) return 0; decoder->setData(data.get(), allDataReceived); ImageFrame* frame = decoder->frameBufferAtIndex(0); if (!frame || frame->status() == ImageFrame::FrameEmpty) return 0; bool isComplete = frame->status() == ImageFrame::FrameComplete; SkBitmap fullSizeBitmap = frame->getSkBitmap(); ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height()); const ScaledImageFragment* fullSizeImage = ImageDecodingStore::instance()->insertAndLockCache( this, ScaledImageFragment::create(m_fullSize, fullSizeBitmap, isComplete)); if (m_fullSize == scaledSize) return fullSizeImage; return tryToScale(fullSizeImage, scaledSize); }
const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize, size_t index) { TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale", "index", static_cast<int>(index)); ImageDecoder* decoder = 0; const bool resumeDecoding = ImageDecodingStore::instance()->lockDecoder(this, m_fullSize, &decoder); ASSERT(!resumeDecoding || decoder); OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &decoder); if (!decoder) return 0; // If we are not resuming decoding that means the decoder is freshly // created and we have ownership. If we are resuming decoding then // the decoder is owned by ImageDecodingStore. OwnPtr<ImageDecoder> decoderContainer; if (!resumeDecoding) decoderContainer = adoptPtr(decoder); if (!fullSizeImage) { // If decode has failed and resulted an empty image we can save work // in the future by returning early. m_decodeFailedAndEmpty = !m_isMultiFrame && decoder->failed(); if (resumeDecoding) ImageDecodingStore::instance()->unlockDecoder(this, decoder); return 0; } const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(this, fullSizeImage.release()); // If the image generated is complete then there is no need to keep // the decoder. The exception is multi-frame decoder which can generate // multiple complete frames. const bool removeDecoder = cachedImage->isComplete() && !m_isMultiFrame; if (resumeDecoding) { if (removeDecoder) ImageDecodingStore::instance()->removeDecoder(this, decoder); else ImageDecodingStore::instance()->unlockDecoder(this, decoder); } else if (!removeDecoder) { ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.release(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef())); } if (m_fullSize == scaledSize) return cachedImage; return tryToScale(cachedImage, scaledSize, index); }
const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize) { const ScaledImageFragment* cachedImage = 0; ImageDecoder* cachedDecoder = 0; if (!ImageDecodingStore::instance()->lockCache(this, m_fullSize, ImageDecodingStore::CacheCanBeIncomplete, &cachedImage, &cachedDecoder)) return 0; ASSERT(cachedDecoder); if (m_data.hasNewData()) { // Only do decoding if there is new data. OwnPtr<ScaledImageFragment> fullSizeImage = decode(&cachedDecoder); cachedImage = ImageDecodingStore::instance()->overwriteAndLockCache(this, cachedImage, fullSizeImage.release()); } if (m_fullSize == scaledSize) return cachedImage; return tryToScale(cachedImage, scaledSize); }