Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / ImageFrameGenerator.cpp
index 35c3cc3..2c2bd12 100644 (file)
@@ -29,9 +29,7 @@
 
 #include "platform/SharedBuffer.h"
 #include "platform/TraceEvent.h"
-#include "platform/graphics/DiscardablePixelRef.h"
 #include "platform/graphics/ImageDecodingStore.h"
-#include "platform/graphics/ScaledImageFragment.h"
 #include "platform/image-decoders/ImageDecoder.h"
 
 #include "skia/ext/image_operations.h"
@@ -71,12 +69,27 @@ private:
     size_t m_rowBytes;
 };
 
+static bool updateYUVComponentSizes(ImageDecoder* decoder, SkISize componentSizes[3], ImageDecoder::SizeType sizeType)
+{
+    // canDecodeToYUV() has to be called AFTER isSizeAvailable(),
+    // otherwise the output color space may not be set in the decoder.
+    if (!decoder->isSizeAvailable() || !decoder->canDecodeToYUV())
+        return false;
+
+    IntSize size = decoder->decodedYUVSize(0, sizeType);
+    componentSizes[0].set(size.width(), size.height());
+    size = decoder->decodedYUVSize(1, sizeType);
+    componentSizes[1].set(size.width(), size.height());
+    size = decoder->decodedYUVSize(2, sizeType);
+    componentSizes[2].set(size.width(), size.height());
+    return true;
+}
+
 ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
     : m_fullSize(fullSize)
     , m_isMultiFrame(isMultiFrame)
     , m_decodeFailedAndEmpty(false)
-    , m_decodeCount(ScaledImageFragment::FirstPartialImage)
-    , m_discardableAllocator(adoptPtr(new DiscardablePixelRefAllocator()))
+    , m_decodeCount(0)
 {
     setData(data.get(), allDataReceived);
 }
@@ -99,28 +112,6 @@ void ImageFrameGenerator::copyData(RefPtr<SharedBuffer>* data, bool* allDataRece
         *data = buffer->copy();
 }
 
-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("blink", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount));
-
-    cachedImage = tryToResumeDecode(scaledSize, index);
-    if (cachedImage)
-        return cachedImage;
-    return 0;
-}
-
 bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, void* pixels, size_t rowBytes)
 {
     // This method is called to populate a discardable memory owned by Skia.
@@ -133,51 +124,74 @@ bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index,
     ASSERT(m_fullSize == scaledSize);
 
     if (m_decodeFailedAndEmpty)
-        return 0;
-
-    TRACE_EVENT2("blink", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount));
-
-    // Don't use discardable memory for decoding if Skia is providing output
-    // memory. Instead use ExternalMemoryAllocator such that we can
-    // write directly to the memory given by Skia.
-    //
-    // TODO:
-    // This is not pretty because this class is used in two different code
-    // paths: discardable memory decoding on Android and discardable memory
-    // in Skia. Once the transition to caching in Skia is complete we can get
-    // rid of the logic that handles discardable memory.
-    m_discardableAllocator.clear();
+        return false;
+
+    TRACE_EVENT2("blink", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", m_decodeCount);
+
     m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes));
 
-    const ScaledImageFragment* cachedImage = tryToResumeDecode(scaledSize, index);
-    if (!cachedImage)
+    SkBitmap bitmap = tryToResumeDecode(scaledSize, index);
+    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();
 
-    ASSERT(cachedImage->bitmap().width() == scaledSize.width());
-    ASSERT(cachedImage->bitmap().height() == scaledSize.height());
+    ASSERT(bitmap.width() == scaledSize.width());
+    ASSERT(bitmap.height() == scaledSize.height());
 
     bool result = true;
     // Check to see if decoder has written directly to the memory provided
     // by Skia. If not make a copy.
-    if (cachedImage->bitmap().getPixels() != pixels)
-        result = cachedImage->bitmap().copyPixelsTo(pixels, rowBytes * info.fHeight, rowBytes);
-    ImageDecodingStore::instance()->unlockCache(this, cachedImage);
+    if (bitmap.getPixels() != pixels)
+        result = bitmap.copyPixelsTo(pixels, rowBytes * info.fHeight, rowBytes);
     return result;
 }
 
-const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkISize& scaledSize, size_t index)
+bool ImageFrameGenerator::decodeToYUV(SkISize componentSizes[3], void* planes[3], size_t rowBytes[3])
 {
-    const ScaledImageFragment* cachedImage = 0;
-    if (ImageDecodingStore::instance()->lockCache(this, scaledSize, index, &cachedImage))
-        return cachedImage;
-    return 0;
+    // This method is called to populate a discardable memory owned by Skia.
+
+    // Prevents concurrent decode or scale operations on the same image data.
+    MutexLocker lock(m_decodeMutex);
+
+    if (m_decodeFailedAndEmpty)
+        return false;
+
+    TRACE_EVENT2("blink", "ImageFrameGenerator::decodeToYUV", "generator", this, "decodeCount", static_cast<int>(m_decodeCount));
+
+    if (!planes || !planes[0] || !planes[1] || !planes[2]
+        || !rowBytes || !rowBytes[0] || !rowBytes[1] || !rowBytes[2]) {
+        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, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied);
+    if (!decoder)
+        return false;
+
+    decoder->setData(data, allDataReceived);
+
+    OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes));
+    decoder->setImagePlanes(imagePlanes.release());
+
+    bool sizeUpdated = updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::ActualSize);
+    RELEASE_ASSERT(sizeUpdated);
+
+    bool yuvDecoded = decoder->decodeToYUV();
+    if (yuvDecoded)
+        setHasAlpha(0, false); // YUV is always opaque
+    return yuvDecoded;
 }
 
-const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_t index)
+SkBitmap ImageFrameGenerator::tryToResumeDecode(const SkISize& scaledSize, size_t index)
 {
     TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecodeAndScale", "index", static_cast<int>(index));
 
@@ -185,10 +199,11 @@ const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecode(const SkISize&
     const bool resumeDecoding = ImageDecodingStore::instance()->lockDecoder(this, m_fullSize, &decoder);
     ASSERT(!resumeDecoding || decoder);
 
-    OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &decoder);
+    SkBitmap fullSizeImage;
+    bool complete = decode(index, &decoder, &fullSizeImage);
 
     if (!decoder)
-        return 0;
+        return SkBitmap();
 
     // If we are not resuming decoding that means the decoder is freshly
     // created and we have ownership. If we are resuming decoding then
@@ -197,22 +212,20 @@ const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecode(const SkISize&
     if (!resumeDecoding)
         decoderContainer = adoptPtr(decoder);
 
-    if (!fullSizeImage) {
+    if (fullSizeImage.isNull()) {
         // 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;
+        return SkBitmap();
     }
 
-    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;
+    const bool removeDecoder = complete && !m_isMultiFrame;
 
     if (resumeDecoding) {
         if (removeDecoder)
@@ -220,13 +233,24 @@ const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecode(const SkISize&
         else
             ImageDecodingStore::instance()->unlockDecoder(this, decoder);
     } else if (!removeDecoder) {
-        ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.release(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef()));
+        ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.release());
     }
+    return fullSizeImage;
+}
 
-    return cachedImage;
+void ImageFrameGenerator::setHasAlpha(size_t index, bool hasAlpha)
+{
+    MutexLocker lock(m_alphaMutex);
+    if (index >= m_hasAlpha.size()) {
+        const size_t oldSize = m_hasAlpha.size();
+        m_hasAlpha.resize(index + 1);
+        for (size_t i = oldSize; i < m_hasAlpha.size(); ++i)
+            m_hasAlpha[i] = true;
+    }
+    m_hasAlpha[index] = hasAlpha;
 }
 
-PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder)
+bool ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder, SkBitmap* bitmap)
 {
     TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_fullSize.width(), "height", m_fullSize.height());
 
@@ -246,74 +270,37 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageD
             *decoder = ImageDecoder::create(*data, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied).leakPtr();
 
         if (!*decoder)
-            return nullptr;
+            return false;
     }
 
-    // This variable is set to true if we can skip a memcpy of the decoded bitmap.
-    bool canSkipBitmapCopy = false;
-
     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.
-        canSkipBitmapCopy = true;
-        if (m_externalAllocator)
-            (*decoder)->setMemoryAllocator(m_externalAllocator.get());
-        else
-            (*decoder)->setMemoryAllocator(m_discardableAllocator.get());
+        ASSERT(m_externalAllocator.get());
+        (*decoder)->setMemoryAllocator(m_externalAllocator.get());
     }
     (*decoder)->setData(data, allDataReceived);
-    // If this call returns a newly allocated DiscardablePixelRef, then
-    // ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked.
-    // They will be unlocked when ImageDecoder is destroyed since ImageDecoder
-    // owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the
-    // ImageDecodingStore while locked.
+
     ImageFrame* frame = (*decoder)->frameBufferAtIndex(index);
     (*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
     (*decoder)->clearCacheExceptFrame(index);
     (*decoder)->setMemoryAllocator(0);
 
     if (!frame || frame->status() == ImageFrame::FrameEmpty)
-        return nullptr;
+        return false;
 
     // A cache object is considered complete if we can decode a complete frame.
     // Or we have received all data. The image might not be fully decoded in
     // the latter case.
-    const bool isCacheComplete = frame->status() == ImageFrame::FrameComplete || allDataReceived;
+    const bool isDecodeComplete = frame->status() == ImageFrame::FrameComplete || allDataReceived;
     SkBitmap fullSizeBitmap = frame->getSkBitmap();
-    if (fullSizeBitmap.isNull())
-        return nullptr;
-
+    if (!fullSizeBitmap.isNull())
     {
-        MutexLocker lock(m_alphaMutex);
-        if (index >= m_hasAlpha.size()) {
-            const size_t oldSize = m_hasAlpha.size();
-            m_hasAlpha.resize(index + 1);
-            for (size_t i = oldSize; i < m_hasAlpha.size(); ++i)
-                m_hasAlpha[i] = true;
-        }
-        m_hasAlpha[index] = !fullSizeBitmap.isOpaque();
+        ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height());
+        setHasAlpha(index, !fullSizeBitmap.isOpaque());
     }
-    ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height());
-
-    // We early out and do not copy the memory if decoder writes directly to
-    // the memory provided by Skia and the decode was complete.
-    if (canSkipBitmapCopy && isCacheComplete)
-        return ScaledImageFragment::createComplete(m_fullSize, index, fullSizeBitmap);
-
-    // If the image is progressively decoded we need to return a copy.
-    // This is to avoid future decode operations writing to the same bitmap.
-    // FIXME: Note that discardable allocator is used. This is because the code
-    // is still used in the Android discardable memory path. When this code is
-    // used in the Skia discardable memory path |m_discardableAllocator| is empty.
-    // This is confusing and should be cleaned up when we can deprecate the use
-    // case for Android discardable memory.
-    SkBitmap copyBitmap;
-    if (!fullSizeBitmap.copyTo(&copyBitmap, fullSizeBitmap.colorType(), m_discardableAllocator.get()))
-        return nullptr;
-
-    if (isCacheComplete)
-        return ScaledImageFragment::createComplete(m_fullSize, index, copyBitmap);
-    return ScaledImageFragment::createPartial(m_fullSize, index, nextGenerationId(), copyBitmap);
+    *bitmap = fullSizeBitmap;
+    return isDecodeComplete;
 }
 
 bool ImageFrameGenerator::hasAlpha(size_t index)
@@ -324,4 +311,30 @@ bool ImageFrameGenerator::hasAlpha(size_t index)
     return true;
 }
 
+bool ImageFrameGenerator::getYUVComponentSizes(SkISize componentSizes[3])
+{
+    ASSERT(componentSizes);
+
+    TRACE_EVENT2("webkit", "ImageFrameGenerator::getYUVComponentSizes", "width", m_fullSize.width(), "height", m_fullSize.height());
+
+    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, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileApplied);
+    if (!decoder)
+        return false;
+
+    // Setting a dummy ImagePlanes object signals to the decoder that we want to do YUV decoding.
+    decoder->setData(data, allDataReceived);
+    OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
+    decoder->setImagePlanes(dummyImagePlanes.release());
+
+    return updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::SizeForMemoryAllocation);
+}
+
 } // namespace blink