blob: 280b2e875ee70fc7899959d657d2ca0334069943 [file] [log] [blame]
/*
* 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 "platform/graphics/DeferredImageDecoder.h"
#include <memory>
#include "platform/SharedBuffer.h"
#include "platform/graphics/DecodingImageGenerator.h"
#include "platform/graphics/ImageDecodingStore.h"
#include "platform/graphics/ImageFrameGenerator.h"
#include "platform/graphics/skia/SkiaUtils.h"
#include "platform/image-decoders/SegmentReader.h"
#include "platform/runtime_enabled_features.h"
#include "platform/wtf/PtrUtil.h"
#include "third_party/skia/include/core/SkImage.h"
namespace blink {
struct DeferredFrameData {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
WTF_MAKE_NONCOPYABLE(DeferredFrameData);
public:
DeferredFrameData()
: orientation_(kDefaultImageOrientation),
is_received_(false) {}
ImageOrientation orientation_;
TimeDelta duration_;
bool is_received_;
};
std::unique_ptr<DeferredImageDecoder> DeferredImageDecoder::Create(
scoped_refptr<SharedBuffer> data,
bool data_complete,
ImageDecoder::AlphaOption alpha_option,
const ColorBehavior& color_behavior) {
std::unique_ptr<ImageDecoder> metadata_decoder =
ImageDecoder::Create(data, data_complete, alpha_option, color_behavior);
if (!metadata_decoder)
return nullptr;
std::unique_ptr<DeferredImageDecoder> decoder(
new DeferredImageDecoder(std::move(metadata_decoder)));
// Since we've just instantiated a fresh decoder, there's no need to reset its
// data.
decoder->SetDataInternal(std::move(data), data_complete, false);
return decoder;
}
std::unique_ptr<DeferredImageDecoder> DeferredImageDecoder::CreateForTesting(
std::unique_ptr<ImageDecoder> metadata_decoder) {
return WTF::WrapUnique(new DeferredImageDecoder(std::move(metadata_decoder)));
}
DeferredImageDecoder::DeferredImageDecoder(
std::unique_ptr<ImageDecoder> metadata_decoder)
: metadata_decoder_(std::move(metadata_decoder)),
repetition_count_(kAnimationNone),
all_data_received_(false),
can_yuv_decode_(false),
has_hot_spot_(false),
complete_frame_content_id_(PaintImage::GetNextContentId()) {}
DeferredImageDecoder::~DeferredImageDecoder() {}
String DeferredImageDecoder::FilenameExtension() const {
return metadata_decoder_ ? metadata_decoder_->FilenameExtension()
: filename_extension_;
}
sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator(size_t index) {
if (frame_generator_ && frame_generator_->DecodeFailed())
return nullptr;
PrepareLazyDecodedFrames();
// PrepareLazyDecodedFrames should populate the metadata for each frame in
// this image and create the |frame_generator_|, if enough data is available.
if (index >= frame_data_.size())
return nullptr;
DCHECK(frame_generator_);
const SkISize& decoded_size = frame_generator_->GetFullSize();
DCHECK_GT(decoded_size.width(), 0);
DCHECK_GT(decoded_size.height(), 0);
sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
scoped_refptr<SegmentReader> segment_reader =
SegmentReader::CreateFromSkROBuffer(std::move(ro_buffer));
// ImageFrameGenerator has the latest known alpha state. There will be a
// performance boost if this frame is opaque.
SkAlphaType alpha_type = frame_generator_->HasAlpha(index)
? kPremul_SkAlphaType
: kOpaque_SkAlphaType;
SkImageInfo info =
SkImageInfo::MakeN32(decoded_size.width(), decoded_size.height(),
alpha_type, color_space_for_sk_images_);
std::vector<FrameMetadata> frames(frame_data_.size());
for (size_t i = 0; i < frame_data_.size(); ++i) {
frames[i].complete = frame_data_[i].is_received_;
frames[i].duration = FrameDurationAtIndex(i);
}
auto generator = DecodingImageGenerator::Create(
frame_generator_, info, std::move(segment_reader), std::move(frames),
complete_frame_content_id_, all_data_received_);
generator->SetCanYUVDecode(can_yuv_decode_);
return generator;
}
scoped_refptr<SharedBuffer> DeferredImageDecoder::Data() {
if (!rw_buffer_)
return nullptr;
sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
scoped_refptr<SharedBuffer> shared_buffer = SharedBuffer::Create();
SkROBuffer::Iter it(ro_buffer.get());
do {
shared_buffer->Append(static_cast<const char*>(it.data()), it.size());
} while (it.next());
return shared_buffer;
}
void DeferredImageDecoder::SetData(scoped_refptr<SharedBuffer> data,
bool all_data_received) {
SetDataInternal(std::move(data), all_data_received, true);
}
void DeferredImageDecoder::SetDataInternal(scoped_refptr<SharedBuffer> data,
bool all_data_received,
bool push_data_to_decoder) {
if (metadata_decoder_) {
all_data_received_ = all_data_received;
if (push_data_to_decoder)
metadata_decoder_->SetData(data, all_data_received);
PrepareLazyDecodedFrames();
}
if (frame_generator_) {
if (!rw_buffer_)
rw_buffer_ = WTF::WrapUnique(new SkRWBuffer(data->size()));
const char* segment = nullptr;
for (size_t length = data->GetSomeData(segment, rw_buffer_->size()); length;
length = data->GetSomeData(segment, rw_buffer_->size())) {
DCHECK_GE(data->size(), rw_buffer_->size() + length);
const size_t remaining = data->size() - rw_buffer_->size() - length;
rw_buffer_->append(segment, length, remaining);
}
}
}
bool DeferredImageDecoder::IsSizeAvailable() {
// m_actualDecoder is 0 only if image decoding is deferred and that means
// the image header decoded successfully and the size is available.
return metadata_decoder_ ? metadata_decoder_->IsSizeAvailable() : true;
}
bool DeferredImageDecoder::HasEmbeddedColorSpace() const {
return metadata_decoder_ ? metadata_decoder_->HasEmbeddedColorSpace()
: has_embedded_color_space_;
}
IntSize DeferredImageDecoder::Size() const {
return metadata_decoder_ ? metadata_decoder_->Size() : 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 metadata_decoder_ ? metadata_decoder_->FrameSizeAtIndex(index) : size_;
}
size_t DeferredImageDecoder::FrameCount() {
return metadata_decoder_ ? metadata_decoder_->FrameCount()
: frame_data_.size();
}
int DeferredImageDecoder::RepetitionCount() const {
return metadata_decoder_ ? metadata_decoder_->RepetitionCount()
: repetition_count_;
}
void DeferredImageDecoder::ClearCacheExceptFrame(size_t clear_except_frame) {
if (metadata_decoder_)
metadata_decoder_->ClearCacheExceptFrame(clear_except_frame);
}
bool DeferredImageDecoder::FrameHasAlphaAtIndex(size_t index) const {
if (metadata_decoder_)
return metadata_decoder_->FrameHasAlphaAtIndex(index);
if (!frame_generator_->IsMultiFrame())
return frame_generator_->HasAlpha(index);
return true;
}
bool DeferredImageDecoder::FrameIsReceivedAtIndex(size_t index) const {
if (metadata_decoder_)
return metadata_decoder_->FrameIsReceivedAtIndex(index);
if (index < frame_data_.size())
return frame_data_[index].is_received_;
return false;
}
TimeDelta DeferredImageDecoder::FrameDurationAtIndex(size_t index) const {
TimeDelta duration;
if (metadata_decoder_)
duration = metadata_decoder_->FrameDurationAtIndex(index);
if (index < frame_data_.size())
duration = frame_data_[index].duration_;
// Many annoying ads specify a 0 duration to make an image flash as quickly as
// possible. We follow Firefox's behavior and use a duration of 100 ms for any
// frames that specify a duration of <= 10 ms. See <rdar://problem/7689300>
// and <http://webkit.org/b/36082> for more information.
if (duration <= TimeDelta::FromMilliseconds(10))
duration = TimeDelta::FromMilliseconds(100);
return duration;
}
ImageOrientation DeferredImageDecoder::OrientationAtIndex(size_t index) const {
if (metadata_decoder_)
return metadata_decoder_->Orientation();
if (index < frame_data_.size())
return frame_data_[index].orientation_;
return kDefaultImageOrientation;
}
void DeferredImageDecoder::ActivateLazyDecoding() {
if (frame_generator_)
return;
size_ = metadata_decoder_->Size();
has_hot_spot_ = metadata_decoder_->HotSpot(hot_spot_);
filename_extension_ = metadata_decoder_->FilenameExtension();
// JPEG images support YUV decoding; other decoders do not. (WebP could in the
// future.)
can_yuv_decode_ = RuntimeEnabledFeatures::DecodeToYUVEnabled() &&
(filename_extension_ == "jpg");
has_embedded_color_space_ = metadata_decoder_->HasEmbeddedColorSpace();
color_space_for_sk_images_ = metadata_decoder_->ColorSpaceForSkImages();
const bool is_single_frame =
metadata_decoder_->RepetitionCount() == kAnimationNone ||
(all_data_received_ && metadata_decoder_->FrameCount() == 1u);
const SkISize decoded_size =
SkISize::Make(metadata_decoder_->DecodedSize().Width(),
metadata_decoder_->DecodedSize().Height());
frame_generator_ = ImageFrameGenerator::Create(
decoded_size, !is_single_frame, metadata_decoder_->GetColorBehavior(),
metadata_decoder_->GetSupportedDecodeSizes());
}
void DeferredImageDecoder::PrepareLazyDecodedFrames() {
if (!metadata_decoder_ || !metadata_decoder_->IsSizeAvailable())
return;
ActivateLazyDecoding();
const size_t previous_size = frame_data_.size();
frame_data_.resize(metadata_decoder_->FrameCount());
// We have encountered a broken image file. Simply bail.
if (frame_data_.size() < previous_size)
return;
for (size_t i = previous_size; i < frame_data_.size(); ++i) {
frame_data_[i].duration_ = metadata_decoder_->FrameDurationAtIndex(i);
frame_data_[i].orientation_ = metadata_decoder_->Orientation();
frame_data_[i].is_received_ = metadata_decoder_->FrameIsReceivedAtIndex(i);
}
// The last lazy decoded frame created from previous call might be
// incomplete so update its state.
if (previous_size) {
const size_t last_frame = previous_size - 1;
frame_data_[last_frame].is_received_ =
metadata_decoder_->FrameIsReceivedAtIndex(last_frame);
}
// If we've received all of the data, then we can reset the metadata decoder,
// since everything we care about should now be stored in |frame_data_|.
if (all_data_received_) {
repetition_count_ = metadata_decoder_->RepetitionCount();
metadata_decoder_.reset();
// Hold on to m_rwBuffer, which is still needed by createFrameAtIndex.
}
}
bool DeferredImageDecoder::HotSpot(IntPoint& hot_spot) const {
if (metadata_decoder_)
return metadata_decoder_->HotSpot(hot_spot);
if (has_hot_spot_)
hot_spot = hot_spot_;
return has_hot_spot_;
}
} // namespace blink
namespace WTF {
template <>
struct VectorTraits<blink::DeferredFrameData>
: public SimpleClassVectorTraits<blink::DeferredFrameData> {
STATIC_ONLY(VectorTraits);
static const bool kCanInitializeWithMemset =
false; // Not all DeferredFrameData members initialize to 0.
};
}