mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
291 lines
10 KiB
C++
291 lines
10 KiB
C++
/*
|
|
* 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 "sky/engine/platform/graphics/DeferredImageDecoder.h"
|
|
|
|
#include "sky/engine/platform/graphics/DecodingImageGenerator.h"
|
|
#include "sky/engine/platform/graphics/ImageDecodingStore.h"
|
|
#include "sky/engine/wtf/PassOwnPtr.h"
|
|
#include "third_party/skia/include/core/SkImageInfo.h"
|
|
|
|
namespace blink {
|
|
|
|
namespace {
|
|
|
|
// URI label for SkDiscardablePixelRef.
|
|
const char labelDiscardable[] = "discardable";
|
|
|
|
} // namespace
|
|
|
|
bool DeferredImageDecoder::s_enabled = false;
|
|
|
|
DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder)
|
|
: m_allDataReceived(false)
|
|
, m_lastDataSize(0)
|
|
, m_dataChanged(false)
|
|
, m_actualDecoder(actualDecoder)
|
|
, m_orientation(DefaultImageOrientation)
|
|
, m_repetitionCount(cAnimationNone)
|
|
, m_hasColorProfile(false)
|
|
{
|
|
}
|
|
|
|
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(), labelDiscardable, sizeof(labelDiscardable));
|
|
}
|
|
|
|
void DeferredImageDecoder::setEnabled(bool enabled)
|
|
{
|
|
s_enabled = enabled;
|
|
}
|
|
|
|
bool DeferredImageDecoder::enabled()
|
|
{
|
|
return s_enabled;
|
|
}
|
|
|
|
String DeferredImageDecoder::filenameExtension() const
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->filenameExtension() : m_filenameExtension;
|
|
}
|
|
|
|
ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index)
|
|
{
|
|
prepareLazyDecodedFrames();
|
|
if (index < m_lazyDecodedFrames.size()) {
|
|
// ImageFrameGenerator has the latest known alpha state. There will
|
|
// be a performance boost if this frame is opaque.
|
|
m_lazyDecodedFrames[index]->setHasAlpha(m_frameGenerator->hasAlpha(index));
|
|
return m_lazyDecodedFrames[index].get();
|
|
}
|
|
if (m_actualDecoder)
|
|
return m_actualDecoder->frameBufferAtIndex(index);
|
|
return 0;
|
|
}
|
|
|
|
void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived)
|
|
{
|
|
if (m_actualDecoder) {
|
|
const bool firstData = !m_data;
|
|
const bool moreData = data.size() > m_lastDataSize;
|
|
m_dataChanged = firstData || moreData;
|
|
m_data = RefPtr<SharedBuffer>(data);
|
|
m_lastDataSize = data.size();
|
|
m_allDataReceived = allDataReceived;
|
|
m_actualDecoder->setData(&data, allDataReceived);
|
|
prepareLazyDecodedFrames();
|
|
}
|
|
|
|
if (m_frameGenerator)
|
|
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;
|
|
}
|
|
|
|
bool DeferredImageDecoder::hasColorProfile() const
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->hasColorProfile() : m_hasColorProfile;
|
|
}
|
|
|
|
IntSize DeferredImageDecoder::size() const
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->size() : m_size;
|
|
}
|
|
|
|
IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const
|
|
{
|
|
// FIXME: LocalFrame size is assumed to be uniform. This might not be true for
|
|
// future supported codecs.
|
|
return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size;
|
|
}
|
|
|
|
size_t DeferredImageDecoder::frameCount()
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->frameCount() : m_lazyDecodedFrames.size();
|
|
}
|
|
|
|
int DeferredImageDecoder::repetitionCount() const
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->repetitionCount() : m_repetitionCount;
|
|
}
|
|
|
|
size_t DeferredImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
|
|
{
|
|
// If image decoding is deferred then frame buffer cache is managed by
|
|
// the compositor and this call is ignored.
|
|
return m_actualDecoder ? m_actualDecoder->clearCacheExceptFrame(clearExceptFrame) : 0;
|
|
}
|
|
|
|
bool DeferredImageDecoder::frameHasAlphaAtIndex(size_t index) const
|
|
{
|
|
if (m_actualDecoder)
|
|
return m_actualDecoder->frameHasAlphaAtIndex(index);
|
|
if (!m_frameGenerator->isMultiFrame())
|
|
return m_frameGenerator->hasAlpha(index);
|
|
return true;
|
|
}
|
|
|
|
bool DeferredImageDecoder::frameIsCompleteAtIndex(size_t index) const
|
|
{
|
|
if (m_actualDecoder)
|
|
return m_actualDecoder->frameIsCompleteAtIndex(index);
|
|
if (index < m_lazyDecodedFrames.size())
|
|
return m_lazyDecodedFrames[index]->status() == ImageFrame::FrameComplete;
|
|
return false;
|
|
}
|
|
|
|
float DeferredImageDecoder::frameDurationAtIndex(size_t index) const
|
|
{
|
|
if (m_actualDecoder)
|
|
return m_actualDecoder->frameDurationAtIndex(index);
|
|
if (index < m_lazyDecodedFrames.size())
|
|
return m_lazyDecodedFrames[index]->duration();
|
|
return 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_frameGenerator ? 0 : m_actualDecoder->frameBytesAtIndex(index);
|
|
}
|
|
|
|
ImageOrientation DeferredImageDecoder::orientation() const
|
|
{
|
|
return m_actualDecoder ? m_actualDecoder->orientation() : m_orientation;
|
|
}
|
|
|
|
void DeferredImageDecoder::activateLazyDecoding()
|
|
{
|
|
if (m_frameGenerator)
|
|
return;
|
|
m_size = m_actualDecoder->size();
|
|
m_orientation = m_actualDecoder->orientation();
|
|
m_filenameExtension = m_actualDecoder->filenameExtension();
|
|
m_hasColorProfile = m_actualDecoder->hasColorProfile();
|
|
const bool isSingleFrame = m_actualDecoder->repetitionCount() == cAnimationNone || (m_allDataReceived && m_actualDecoder->frameCount() == 1u);
|
|
m_frameGenerator = ImageFrameGenerator::create(SkISize::Make(m_actualDecoder->decodedSize().width(), m_actualDecoder->decodedSize().height()), m_data, m_allDataReceived, !isSingleFrame);
|
|
}
|
|
|
|
void DeferredImageDecoder::prepareLazyDecodedFrames()
|
|
{
|
|
if (!s_enabled
|
|
|| !m_actualDecoder
|
|
|| !m_actualDecoder->isSizeAvailable()
|
|
|| m_actualDecoder->filenameExtension() == "ico")
|
|
return;
|
|
|
|
activateLazyDecoding();
|
|
|
|
const size_t previousSize = m_lazyDecodedFrames.size();
|
|
m_lazyDecodedFrames.resize(m_actualDecoder->frameCount());
|
|
|
|
// We have encountered a broken image file. Simply bail.
|
|
if (m_lazyDecodedFrames.size() < previousSize)
|
|
return;
|
|
|
|
for (size_t i = previousSize; i < m_lazyDecodedFrames.size(); ++i) {
|
|
OwnPtr<ImageFrame> frame(adoptPtr(new ImageFrame()));
|
|
frame->setSkBitmap(createBitmap(i));
|
|
frame->setDuration(m_actualDecoder->frameDurationAtIndex(i));
|
|
frame->setStatus(m_actualDecoder->frameIsCompleteAtIndex(i) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
|
|
m_lazyDecodedFrames[i] = frame.release();
|
|
}
|
|
|
|
// The last lazy decoded frame created from previous call might be
|
|
// incomplete so update its state.
|
|
if (previousSize) {
|
|
const size_t lastFrame = previousSize - 1;
|
|
m_lazyDecodedFrames[lastFrame]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(lastFrame) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
|
|
|
|
// If data has changed then create a new bitmap. This forces
|
|
// Skia to decode again.
|
|
if (m_dataChanged) {
|
|
m_dataChanged = false;
|
|
m_lazyDecodedFrames[lastFrame]->setSkBitmap(createBitmap(lastFrame));
|
|
}
|
|
}
|
|
|
|
if (m_allDataReceived) {
|
|
m_repetitionCount = m_actualDecoder->repetitionCount();
|
|
m_actualDecoder.clear();
|
|
m_data = nullptr;
|
|
}
|
|
}
|
|
|
|
// Creates a SkBitmap that is backed by SkDiscardablePixelRef.
|
|
SkBitmap DeferredImageDecoder::createBitmap(size_t index)
|
|
{
|
|
IntSize decodedSize = m_actualDecoder->decodedSize();
|
|
ASSERT(decodedSize.width() > 0);
|
|
ASSERT(decodedSize.height() > 0);
|
|
|
|
#if SK_B32_SHIFT // Little-endian RGBA pixels. (Android)
|
|
const SkColorType colorType = kRGBA_8888_SkColorType;
|
|
#else
|
|
const SkColorType colorType = kBGRA_8888_SkColorType;
|
|
#endif
|
|
const SkImageInfo info = SkImageInfo::Make(decodedSize.width(), decodedSize.height(), colorType, kPremul_SkAlphaType);
|
|
|
|
SkBitmap bitmap;
|
|
DecodingImageGenerator* generator = new DecodingImageGenerator(m_frameGenerator, info, index);
|
|
bool installed = SkInstallDiscardablePixelRef(generator, &bitmap);
|
|
ASSERT_UNUSED(installed, installed);
|
|
bitmap.pixelRef()->setURI(labelDiscardable);
|
|
generator->setGenerationId(bitmap.getGenerationID());
|
|
return bitmap;
|
|
}
|
|
|
|
bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const
|
|
{
|
|
// TODO: Implement.
|
|
return m_actualDecoder ? m_actualDecoder->hotSpot(hotSpot) : false;
|
|
}
|
|
|
|
} // namespace blink
|