| /* |
| * Copyright (C) 2012 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "core/platform/graphics/chromium/DeferredImageDecoder.h" |
| |
| #include "core/platform/graphics/chromium/ImageDecodingStore.h" |
| #include "core/platform/graphics/chromium/ImageFrameGenerator.h" |
| #include "core/platform/graphics/chromium/LazyDecodingPixelRef.h" |
| #include <wtf/OwnPtr.h> |
| #include <wtf/PassOwnPtr.h> |
| |
| namespace WebCore { |
| |
| namespace { |
| |
| // URI label for a lazily decoded SkPixelRef. |
| const char labelLazyDecoded[] = "lazy"; |
| |
| } // namespace |
| |
| bool DeferredImageDecoder::s_enabled = false; |
| |
| DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder) |
| : m_allDataReceived(false) |
| , m_actualDecoder(actualDecoder) |
| , m_orientation(DefaultImageOrientation) |
| { |
| } |
| |
| DeferredImageDecoder::~DeferredImageDecoder() |
| { |
| } |
| |
| PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorOption) |
| { |
| OwnPtr<ImageDecoder> actualDecoder = ImageDecoder::create(data, alphaOption, gammaAndColorOption); |
| return actualDecoder ? adoptPtr(new DeferredImageDecoder(actualDecoder.release())) : nullptr; |
| } |
| |
| PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::createForTesting(PassOwnPtr<ImageDecoder> decoder) |
| { |
| return adoptPtr(new DeferredImageDecoder(decoder)); |
| } |
| |
| bool DeferredImageDecoder::isLazyDecoded(const SkBitmap& bitmap) |
| { |
| return bitmap.pixelRef() |
| && bitmap.pixelRef()->getURI() |
| && !memcmp(bitmap.pixelRef()->getURI(), labelLazyDecoded, sizeof(labelLazyDecoded)); |
| } |
| |
| SkBitmap DeferredImageDecoder::createResizedLazyDecodingBitmap(const SkBitmap& bitmap, const SkISize& scaledSize, const SkIRect& scaledSubset) |
| { |
| LazyDecodingPixelRef* pixelRef = static_cast<LazyDecodingPixelRef*>(bitmap.pixelRef()); |
| |
| int rowBytes = 0; |
| rowBytes = SkBitmap::ComputeRowBytes(SkBitmap::kARGB_8888_Config, scaledSize.width()); |
| |
| SkBitmap resizedBitmap; |
| resizedBitmap.setConfig(SkBitmap::kARGB_8888_Config, scaledSubset.width(), scaledSubset.height(), rowBytes); |
| |
| // FIXME: This code has the potential problem that multiple |
| // LazyDecodingPixelRefs are created even though they share the same |
| // scaled size and ImageFrameGenerator. |
| resizedBitmap.setPixelRef(new LazyDecodingPixelRef(pixelRef->frameGenerator(), scaledSize, scaledSubset))->unref(); |
| |
| // See comments in createLazyDecodingBitmap(). |
| resizedBitmap.setImmutable(); |
| return resizedBitmap; |
| } |
| |
| void DeferredImageDecoder::setEnabled(bool enabled) |
| { |
| s_enabled = enabled; |
| } |
| |
| String DeferredImageDecoder::filenameExtension() const |
| { |
| return m_actualDecoder ? m_actualDecoder->filenameExtension() : m_filenameExtension; |
| } |
| |
| ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index) |
| { |
| // Only defer image decoding if this is a single frame image. The reason is |
| // because a multiframe is usually animated GIF. Animation is handled by |
| // BitmapImage which uses some metadata functions that do synchronous image |
| // decoding. |
| if (s_enabled |
| && m_actualDecoder |
| && m_actualDecoder->repetitionCount() == cAnimationNone |
| && m_actualDecoder->isSizeAvailable() |
| && m_actualDecoder->frameCount() == 1) { |
| |
| m_size = m_actualDecoder->size(); |
| m_filenameExtension = m_actualDecoder->filenameExtension(); |
| m_orientation = m_actualDecoder->orientation(); |
| |
| SkBitmap lazyDecodedSkBitmap = createLazyDecodingBitmap(); |
| m_lazyDecodedFrame.setSkBitmap(lazyDecodedSkBitmap); |
| |
| // Don't mark the frame as completely decoded until the underlying |
| // decoder has really decoded it. Until then, our data and metadata may |
| // be incorrect, so callers can't rely on them. |
| m_lazyDecodedFrame.setStatus(ImageFrame::FramePartial); |
| } |
| |
| return m_actualDecoder ? m_actualDecoder->frameBufferAtIndex(index) : &m_lazyDecodedFrame; |
| } |
| |
| void DeferredImageDecoder::setData(SharedBuffer* data, bool allDataReceived) |
| { |
| if (m_actualDecoder) { |
| // Keep a reference to data until image decoding is deferred. |
| // When image decoding is deferred then ownership of m_data is |
| // transferred to ImageDecodingStore. |
| m_data = data; |
| m_allDataReceived = allDataReceived; |
| m_actualDecoder->setData(data, allDataReceived); |
| } else { |
| ASSERT(!m_data); |
| m_frameGenerator->setData(data, allDataReceived); |
| } |
| } |
| |
| bool DeferredImageDecoder::isSizeAvailable() |
| { |
| // m_actualDecoder is 0 only if image decoding is deferred and that |
| // means image header decoded successfully and size is available. |
| return m_actualDecoder ? m_actualDecoder->isSizeAvailable() : true; |
| } |
| |
| IntSize DeferredImageDecoder::size() const |
| { |
| return m_actualDecoder ? m_actualDecoder->size() : m_size; |
| } |
| |
| IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const |
| { |
| return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size; |
| } |
| |
| size_t DeferredImageDecoder::frameCount() |
| { |
| return m_actualDecoder ? m_actualDecoder->frameCount() : 1; |
| } |
| |
| int DeferredImageDecoder::repetitionCount() const |
| { |
| return m_actualDecoder ? m_actualDecoder->repetitionCount() : cAnimationNone; |
| } |
| |
| void DeferredImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame) |
| { |
| // If image decoding is deferred then frame buffer cache is managed by |
| // the compositor and this call is ignored. |
| if (m_actualDecoder) |
| m_actualDecoder->clearFrameBufferCache(clearBeforeFrame); |
| } |
| |
| bool DeferredImageDecoder::frameHasAlphaAtIndex(size_t index) const |
| { |
| return m_actualDecoder ? m_actualDecoder->frameHasAlphaAtIndex(index) : m_frameGenerator->hasAlpha(); |
| } |
| |
| bool DeferredImageDecoder::frameIsCompleteAtIndex(size_t index) const |
| { |
| // TODO: Implement this for deferred decoding. |
| return m_actualDecoder && m_actualDecoder->frameIsCompleteAtIndex(index); |
| } |
| |
| float DeferredImageDecoder::frameDurationAtIndex(size_t index) const |
| { |
| // TODO: Implement this for deferred decoding. |
| return m_actualDecoder ? m_actualDecoder->frameDurationAtIndex(index) : 0; |
| } |
| |
| unsigned DeferredImageDecoder::frameBytesAtIndex(size_t index) const |
| { |
| // If frame decoding is deferred then it is not managed by MemoryCache |
| // so return 0 here. |
| return m_actualDecoder ? m_actualDecoder->frameBytesAtIndex(index) : 0; |
| } |
| |
| ImageOrientation DeferredImageDecoder::orientation() const |
| { |
| return m_actualDecoder ? m_actualDecoder->orientation() : m_orientation; |
| } |
| |
| SkBitmap DeferredImageDecoder::createLazyDecodingBitmap() |
| { |
| SkISize fullSize = SkISize::Make(m_actualDecoder->size().width(), m_actualDecoder->size().height()); |
| ASSERT(!fullSize.isEmpty()); |
| |
| SkIRect fullRect = SkIRect::MakeSize(fullSize); |
| |
| // Creates a lazily decoded SkPixelRef that references the entire image without scaling. |
| SkBitmap bitmap; |
| bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullSize.width(), fullSize.height()); |
| |
| m_frameGenerator = ImageFrameGenerator::create(fullSize, m_data.release(), m_allDataReceived); |
| m_actualDecoder.clear(); |
| |
| bitmap.setPixelRef(new LazyDecodingPixelRef(m_frameGenerator, fullSize, fullRect))->unref(); |
| |
| // Use the URI to identify this as a lazily decoded SkPixelRef of type LazyDecodingPixelRef. |
| // FIXME: It would be more useful to give the actual image URI. |
| bitmap.pixelRef()->setURI(labelLazyDecoded); |
| |
| // Inform the bitmap that we will never change the pixels. This is a performance hint |
| // subsystems that may try to cache this bitmap (e.g. pictures, pipes, gpu, pdf, etc.) |
| bitmap.setImmutable(); |
| |
| // FIXME: Setting bitmap.setIsOpaque() is big performance gain if possible. We can |
| // do so safely if the image is fully loaded and it is a JPEG image, or if the image was |
| // decoded before. |
| |
| return bitmap; |
| } |
| |
| bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const |
| { |
| return m_actualDecoder ? m_actualDecoder->hotSpot(hotSpot) : false; |
| } |
| |
| } // namespace WebCore |