| Index: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
|
| diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
|
| index 1decd0f70f6f26e911b59732117b69f7bffea6ac..312dba24c3dd11a02830bf9cf60c3f94ab0f24c4 100644
|
| --- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
|
| +++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
|
| @@ -26,6 +26,7 @@
|
| #include "platform/graphics/ImageFrameGenerator.h"
|
|
|
| #include "SkData.h"
|
| +#include "platform/SharedBuffer.h"
|
| #include "platform/TraceEvent.h"
|
| #include "platform/graphics/ImageDecodingStore.h"
|
| #include "platform/image-decoders/ImageDecoder.h"
|
| @@ -51,7 +52,7 @@
|
|
|
| // Creates a SkPixelRef such that the memory for pixels is given by an external body.
|
| // This is used to write directly to the memory given by Skia during decoding.
|
| -class ExternalMemoryAllocator final : public SkBitmap::Allocator {
|
| +class ImageFrameGenerator::ExternalMemoryAllocator final : public SkBitmap::Allocator {
|
| USING_FAST_MALLOC(ExternalMemoryAllocator);
|
| WTF_MAKE_NONCOPYABLE(ExternalMemoryAllocator);
|
| public:
|
| @@ -100,38 +101,104 @@
|
| return true;
|
| }
|
|
|
| -ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, bool isMultiFrame)
|
| +ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
|
| : m_fullSize(fullSize)
|
| + , m_data(adoptRef(new ThreadSafeDataTransport()))
|
| , m_isMultiFrame(isMultiFrame)
|
| , m_decodeFailed(false)
|
| , m_yuvDecodingFailed(false)
|
| , m_frameCount(0)
|
| -{
|
| + , m_encodedData(nullptr)
|
| +{
|
| + setData(data.get(), allDataReceived);
|
| }
|
|
|
| ImageFrameGenerator::~ImageFrameGenerator()
|
| {
|
| + if (m_encodedData)
|
| + m_encodedData->unref();
|
| ImageDecodingStore::instance().removeCacheIndexedByGenerator(this);
|
| }
|
|
|
| -bool ImageFrameGenerator::decodeAndScale(SegmentReader* data, bool allDataReceived, size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes)
|
| -{
|
| +void ImageFrameGenerator::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
|
| +{
|
| + m_data->setData(data.get(), allDataReceived);
|
| +}
|
| +
|
| +static void sharedSkDataReleaseCallback(const void* address, void* context)
|
| +{
|
| + // This gets called when m_encodedData reference count becomes 0 - and it could happen in
|
| + // ImageFrameGenerator destructor or later when m_encodedData gets dereferenced.
|
| + // In this method, we deref ThreadSafeDataTransport, as ThreadSafeDataTransport is the owner
|
| + // of data returned via refEncodedData.
|
| +
|
| + ThreadSafeDataTransport* dataTransport = static_cast<ThreadSafeDataTransport*>(context);
|
| +#if ENABLE(ASSERT)
|
| + ASSERT(dataTransport);
|
| + SharedBuffer* buffer = 0;
|
| + bool allDataReceived = false;
|
| + dataTransport->data(&buffer, &allDataReceived);
|
| + ASSERT(allDataReceived && buffer && buffer->data() == address);
|
| +#endif
|
| + // Dereference m_data now.
|
| + dataTransport->deref();
|
| +}
|
| +
|
| +SkData* ImageFrameGenerator::refEncodedData()
|
| +{
|
| + // SkData is returned only when full image (encoded) data is received. This is important
|
| + // since DeferredImageDecoder::setData is called only once with allDataReceived set to true,
|
| + // and after that m_data->m_readBuffer.data() is not changed. See also RELEASE_ASSERT used in
|
| + // ThreadSafeDataTransport::data().
|
| + SharedBuffer* buffer = 0;
|
| + bool allDataReceived = false;
|
| + m_data->data(&buffer, &allDataReceived);
|
| + if (!allDataReceived)
|
| + return nullptr;
|
| +
|
| + {
|
| + // Prevents concurrent access to m_encodedData creation.
|
| + MutexLocker lock(m_decodeMutex);
|
| + if (m_encodedData) {
|
| + m_encodedData->ref();
|
| + return m_encodedData;
|
| + }
|
| + // m_encodedData is created with initial reference count == 1. ImageFrameGenerator always holds one
|
| + // reference to m_encodedData, as it prevents write access in SkData::writable_data.
|
| + m_encodedData = SkData::NewWithProc(buffer->data(), buffer->size(), sharedSkDataReleaseCallback, m_data.get());
|
| + // While m_encodedData is referenced, prevent disposing m_data and its content.
|
| + // it is dereferenced in sharedSkDataReleaseCallback, called when m_encodedData gets dereferenced.
|
| + m_data->ref();
|
| + }
|
| + // Increase the reference, caller must decrease it. One reference is always kept by ImageFrameGenerator and released
|
| + // in destructor.
|
| + m_encodedData->ref();
|
| + return m_encodedData;
|
| +}
|
| +
|
| +bool ImageFrameGenerator::decodeAndScale(size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes)
|
| +{
|
| + // Prevent concurrent decode or scale operations on the same image data.
|
| + MutexLocker lock(m_decodeMutex);
|
| +
|
| if (m_decodeFailed)
|
| return false;
|
|
|
| TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "frame index", static_cast<int>(index));
|
|
|
| - RefPtr<ExternalMemoryAllocator> externalAllocator = adoptRef(new ExternalMemoryAllocator(info, pixels, rowBytes));
|
| + m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes));
|
|
|
| // This implementation does not support scaling so check the requested size.
|
| SkISize scaledSize = SkISize::Make(info.width(), info.height());
|
| ASSERT(m_fullSize == scaledSize);
|
|
|
| - // TODO (scroggo): Convert tryToResumeDecode() and decode() to take a
|
| - // PassRefPtr<SkBitmap::Allocator> instead of a bare pointer.
|
| - SkBitmap bitmap = tryToResumeDecode(data, allDataReceived, index, scaledSize, externalAllocator.get());
|
| + SkBitmap bitmap = tryToResumeDecode(index, scaledSize);
|
| if (bitmap.isNull())
|
| return false;
|
| +
|
| + // Don't keep the allocator because it contains a pointer to memory
|
| + // that we do not own.
|
| + m_externalAllocator.clear();
|
|
|
| // Check to see if the decoder has written directly to the pixel memory
|
| // provided. If not, make a copy.
|
| @@ -143,10 +210,11 @@
|
| return true;
|
| }
|
|
|
| -bool ImageFrameGenerator::decodeToYUV(SegmentReader* data, size_t index, const SkISize componentSizes[3], void* planes[3], const size_t rowBytes[3])
|
| -{
|
| - // TODO (scroggo): The only interesting thing this uses from the ImageFrameGenerator is m_decodeFailed.
|
| - // Move this into DecodingImageGenerator, which is the only class that calls it.
|
| +bool ImageFrameGenerator::decodeToYUV(size_t index, const SkISize componentSizes[3], void* planes[3], const size_t rowBytes[3])
|
| +{
|
| + // Prevent concurrent decode or scale operations on the same image data.
|
| + MutexLocker lock(m_decodeMutex);
|
| +
|
| if (m_decodeFailed)
|
| return false;
|
|
|
| @@ -157,11 +225,18 @@
|
| return false;
|
| }
|
|
|
| + SharedBuffer* data = 0;
|
| + bool allDataReceived = false;
|
| + m_data->data(&data, &allDataReceived);
|
| +
|
| + // FIXME: YUV decoding does not currently support progressive decoding.
|
| + ASSERT(allDataReceived);
|
| +
|
| OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, ImageDecoder::AlphaPremultiplied, ImageDecoder::GammaAndColorProfileApplied);
|
| - // getYUVComponentSizes was already called and was successful, so ImageDecoder::create must succeed.
|
| - ASSERT(decoder);
|
| -
|
| - decoder->setData(data, true);
|
| + if (!decoder)
|
| + return false;
|
| +
|
| + decoder->setData(data, allDataReceived);
|
|
|
| OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes));
|
| decoder->setImagePlanes(imagePlanes.release());
|
| @@ -178,19 +253,16 @@
|
| return false;
|
| }
|
|
|
| -SkBitmap ImageFrameGenerator::tryToResumeDecode(SegmentReader* data, bool allDataReceived, size_t index, const SkISize& scaledSize, SkBitmap::Allocator* allocator)
|
| +SkBitmap ImageFrameGenerator::tryToResumeDecode(size_t index, const SkISize& scaledSize)
|
| {
|
| TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecode", "frame index", static_cast<int>(index));
|
|
|
| ImageDecoder* decoder = 0;
|
| -
|
| - // Lock the mutex, so only one thread can use the decoder at once.
|
| - MutexLocker lock(m_decodeMutex);
|
| const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder);
|
| ASSERT(!resumeDecoding || decoder);
|
|
|
| SkBitmap fullSizeImage;
|
| - bool complete = decode(data, allDataReceived, index, &decoder, &fullSizeImage, allocator);
|
| + bool complete = decode(index, &decoder, &fullSizeImage);
|
|
|
| if (!decoder)
|
| return SkBitmap();
|
| @@ -250,10 +322,13 @@
|
| m_hasAlpha[index] = hasAlpha;
|
| }
|
|
|
| -bool ImageFrameGenerator::decode(SegmentReader* data, bool allDataReceived, size_t index, ImageDecoder** decoder, SkBitmap* bitmap, SkBitmap::Allocator* allocator)
|
| -{
|
| - ASSERT(m_decodeMutex.locked());
|
| +bool ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder, SkBitmap* bitmap)
|
| +{
|
| TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_fullSize.width(), "height", m_fullSize.height());
|
| +
|
| + SharedBuffer* data = 0;
|
| + bool allDataReceived = false;
|
| + m_data->data(&data, &allDataReceived);
|
|
|
| // Try to create an ImageDecoder if we are not given one.
|
| ASSERT(decoder);
|
| @@ -273,8 +348,8 @@
|
| if (!m_isMultiFrame && newDecoder && allDataReceived) {
|
| // If we're using an external memory allocator that means we're decoding
|
| // directly into the output memory and we can save one memcpy.
|
| - ASSERT(allocator);
|
| - (*decoder)->setMemoryAllocator(allocator);
|
| + ASSERT(m_externalAllocator.get());
|
| + (*decoder)->setMemoryAllocator(m_externalAllocator.get());
|
| }
|
|
|
| (*decoder)->setData(data, allDataReceived);
|
| @@ -287,7 +362,7 @@
|
| if (allDataReceived)
|
| m_frameCount = (*decoder)->frameCount();
|
|
|
| - (*decoder)->setData(PassRefPtr<SegmentReader>(nullptr), false); // Unref SegmentReader from ImageDecoder.
|
| + (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
|
| (*decoder)->clearCacheExceptFrame(index);
|
| (*decoder)->setMemoryAllocator(0);
|
|
|
| @@ -317,11 +392,19 @@
|
| return true;
|
| }
|
|
|
| -bool ImageFrameGenerator::getYUVComponentSizes(SegmentReader* data, SkYUVSizeInfo* sizeInfo)
|
| +bool ImageFrameGenerator::getYUVComponentSizes(SkYUVSizeInfo* sizeInfo)
|
| {
|
| TRACE_EVENT2("blink", "ImageFrameGenerator::getYUVComponentSizes", "width", m_fullSize.width(), "height", m_fullSize.height());
|
|
|
| if (m_yuvDecodingFailed)
|
| + return false;
|
| +
|
| + SharedBuffer* data = 0;
|
| + bool allDataReceived = false;
|
| + m_data->data(&data, &allDataReceived);
|
| +
|
| + // FIXME: YUV decoding does not currently support progressive decoding.
|
| + if (!allDataReceived)
|
| return false;
|
|
|
| OwnPtr<ImageDecoder> decoder = ImageDecoder::create(*data, ImageDecoder::AlphaPremultiplied, ImageDecoder::GammaAndColorProfileApplied);
|
| @@ -329,7 +412,7 @@
|
| return false;
|
|
|
| // Setting a dummy ImagePlanes object signals to the decoder that we want to do YUV decoding.
|
| - decoder->setData(data, true);
|
| + decoder->setData(data, allDataReceived);
|
| OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
|
| decoder->setImagePlanes(dummyImagePlanes.release());
|
|
|
|
|